MDL-11517 reserved word MOD used in table alias in questions backup code
[moodle-pu.git] / lib / yui / colorpicker / colorpicker-beta-debug.js
blob83d861b64f0e20c2f6ac2771801e4b087719cf36
1 /*
2 Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 2.3.0
6 */
7 /**
8  * Provides color conversion and validation utils
9  * @class YAHOO.util.Color
10  * @namespace YAHOO.util
11  */
12 YAHOO.util.Color = function() {
14     var HCHARS="0123456789ABCDEF", lang=YAHOO.lang;
16     return {
18         /**
19          * Converts 0-1 to 0-255
20          * @method real2dec
21          * @param n {float} the number to convert
22          * @return {int} a number 0-255
23          */
24         real2dec: function(n) {
25             return Math.min(255, Math.round(n*256));
26         },
28         /**
29          * Converts HSV (h[0-360], s[0-1]), v[0-1] to RGB [255,255,255]
30          * @method hsv2rgb
31          * @param h {int|[int, float, float]} the hue, or an
32          *        array containing all three parameters
33          * @param s {float} the saturation
34          * @param v {float} the value/brightness
35          * @return {[int, int, int]} the red, green, blue values in
36          *          decimal.
37          */
38         hsv2rgb: function(h, s, v) { 
40             if (lang.isArray(h)) {
41                 return this.hsv2rgb.call(this, h[0], h[1], h[2]);
42             }
44             var r, g, b, i, f, p, q, t;
45             i = Math.floor((h/60)%6);
46             f = (h/60)-i;
47             p = v*(1-s);
48             q = v*(1-f*s);
49             t = v*(1-(1-f)*s);
50             switch(i) {
51                 case 0: r=v; g=t; b=p; break;
52                 case 1: r=q; g=v; b=p; break;
53                 case 2: r=p; g=v; b=t; break;
54                 case 3: r=p; g=q; b=v; break;
55                 case 4: r=t; g=p; b=v; break;
56                 case 5: r=v; g=p; b=q; break;
57             }
59             var fn=this.real2dec;
61             return [fn(r), fn(g), fn(b)];
62         },
64         /**
65          * Converts to RGB [255,255,255] to HSV (h[0-360], s[0-1]), v[0-1]
66          * @method rgb2hsv
67          * @param r {int|[int, int, int]} the red value, or an
68          *        array containing all three parameters
69          * @param g {int} the green value
70          * @param b {int} the blue value
71          * @return {[int, float, float]} the value converted to hsv
72          */
73         rgb2hsv: function(r, g, b) {
75             if (lang.isArray(r)) {
76                 return this.rgb2hsv.call(this, r[0], r[1], r[2]);
77             }
79             r=r/255;
80             g=g/255;
81             b=b/255;
83             var min,max,delta,h,s,v;
84             min = Math.min(Math.min(r,g),b);
85             max = Math.max(Math.max(r,g),b);
86             delta = max-min;
88             switch (max) {
89                 case min: h=0; break;
90                 case r:   h=60*(g-b)/delta; 
91                           if (g<b) {
92                               h+=360;
93                           }
94                           break;
95                 case g:   h=(60*(b-r)/delta)+120; break;
96                 case b:   h=(60*(r-g)/delta)+240; break;
97             }
98             
99             s = (max === 0) ? 0 : 1-(min/max);
101             var hsv = [Math.round(h), s, max];
103             return hsv;
105         },
107         /**
108          * Converts decimal rgb values into a hex string
109          * 255,255,255 -> FFFFFF
110          * @method rgb2hex
111          * @param r {int|[int, int, int]} the red value, or an
112          *        array containing all three parameters
113          * @param g {int} the green value
114          * @param b {int} the blue value
115          * @return {string} the hex string
116          */
117         rgb2hex: function(r, g, b) {
118             if (lang.isArray(r)) {
119                 return this.rgb2hex.call(this, r[0], r[1], r[2]);
120             }
122             var f=this.dec2hex;
123             return f(r) + f(g) + f(b);
124         },
125      
126         /**
127          * Converts an int 0...255 to hex pair 00...FF
128          * @method dec2hex
129          * @param n {int} the number to convert
130          * @return {string} the hex equivalent
131          */
132         dec2hex: function(n) {
133             n = parseInt(n, 10);
134             n = (lang.isNumber(n)) ? n : 0;
135             n = (n > 255 || n < 0) ? 0 : n;
137             return HCHARS.charAt((n - n % 16) / 16) + HCHARS.charAt(n % 16);
138         },
140         /**
141          * Converts a hex pair 00...FF to an int 0...255 
142          * @method hex2dec
143          * @param str {string} the hex pair to convert
144          * @return {int} the decimal
145          */
146         hex2dec: function(str) {
147             var f = function(c) {
148                 return HCHARS.indexOf(c.toUpperCase());
149             };
151             var s=str.split('');
152             
153             return ((f(s[0]) * 16) + f(s[1]));
154         },
156         /**
157          * Converts a hex string to rgb
158          * @method hex2rgb
159          * @param str {string} the hex string
160          * @return {[int, int, int]} an array containing the rgb values
161          */
162         hex2rgb: function(s) { 
163             var f = this.hex2dec;
164             return [f(s.substr(0, 2)), f(s.substr(2, 2)), f(s.substr(4, 2))];
165         },
167         /**
168          * Returns the closest websafe color to the supplied rgb value.
169          * @method websafe
170          * @param r {int|[int, int, int]} the red value, or an
171          *        array containing all three parameters
172          * @param g {int} the green value
173          * @param b {int} the blue value
174          * @return {[int, int, int]} an array containing the closes
175          *                           websafe rgb colors.
176          */
177         websafe: function(r, g, b) {
179             if (lang.isArray(r)) {
180                 return this.websafe.call(this, r[0], r[1], r[2]);
181             }
183             // returns the closest match [0, 51, 102, 153, 204, 255]
184             var f = function(v) {
185                 if (lang.isNumber(v)) {
186                     v = Math.min(Math.max(0, v), 255);
187                     var i, next;
188                     for (i=0; i<256; i=i+51) {
189                         next = i+51;
190                         if (v >= i && v <= next) {
191                             return (v-i > 25) ? next : i;
192                         }
193                     }
194  YAHOO.log("Error calculating the websafe value for " + v, "warn");
195                 }
197                 return v;
198             };
200             return [f(r), f(g), f(b)];
201         }
202     };
203 }();
206 (function() {
208     var pickercount = 0;
210     /**
211      * The colorpicker module provides a widget for selecting colors
212      * @module colorpicker
213      * @requires yahoo, dom, event, element, slider
214      */
216     /**
217      * A widget to select colors
218      * @namespace YAHOO.widget
219      * @class YAHOO.widget.ColorPicker
220      * @extends YAHOO.util.Element
221      * @constructor
222      * @param {HTMLElement | String | Object} el(optional) The html 
223      * element that represents the colorpicker, or the attribute object to use. 
224      * An element will be created if none provided.
225      * @param {Object} attr (optional) A key map of the colorpicker's 
226      * initial attributes.  Ignored if first arg is attributes object.
227      */
228     YAHOO.widget.ColorPicker = function(el, attr) {
229         pickercount = pickercount + 1;
230         this.logger = new YAHOO.widget.LogWriter("ColorPicker");
231         attr = attr || {};
232         if (arguments.length === 1 && !YAHOO.lang.isString(el) && !el.nodeName) {
233             attr = el; // treat first arg as attr object
234             el = attr.element || null;
235         }
236         
237         if (!el && !attr.element) { // create if we dont have one
238             this.logger.log("creating host element");
239             el = _createHostElement.call(this, attr);
240         }
242         YAHOO.widget.ColorPicker.superclass.constructor.call(this, el, attr); 
243     };
245     YAHOO.extend(YAHOO.widget.ColorPicker, YAHOO.util.Element);
246     
247     var proto = YAHOO.widget.ColorPicker.prototype,
248         Slider=YAHOO.widget.Slider,
249         Color=YAHOO.util.Color,
250         Dom = YAHOO.util.Dom,
251         Event = YAHOO.util.Event,
252         lang = YAHOO.lang,
253         sub = lang.substitute;
254     
256     var b = "yui-picker";
258     /**
259      * The element ids used by this control
260      * @property ID
261      * @final
262      */
263     proto.ID = {
265         /**
266          * The id for the "red" form field
267          * @property ID.R
268          * @type String
269          * @final
270          * @default yui-picker-r
271          */
272         R: b + "-r",
274         /**
275          * The id for the "red" hex pair output
276          * @property ID.R_HEX
277          * @type String
278          * @final
279          * @default yui-picker-rhex
280          */
281         R_HEX: b + "-rhex",
283         /**
284          * The id for the "green" form field
285          * @property ID.G
286          * @type String
287          * @final
288          * @default yui-picker-g
289          */
290         G: b + "-g",
292         /**
293          * The id for the "green" hex pair output
294          * @property ID.G_HEX
295          * @type String
296          * @final
297          * @default yui-picker-ghex
298          */
299         G_HEX: b + "-ghex",
302         /**
303          * The id for the "blue" form field
304          * @property ID.B
305          * @type String
306          * @final
307          * @default yui-picker-b
308          */
309         B: b + "-b",
311         /**
312          * The id for the "blue" hex pair output
313          * @property ID.B_HEX
314          * @type String
315          * @final
316          * @default yui-picker-bhex
317          */
318         B_HEX: b + "-bhex",
320         /**
321          * The id for the "hue" form field
322          * @property ID.H
323          * @type String
324          * @final
325          * @default yui-picker-h
326          */
327         H: b + "-h",
329         /**
330          * The id for the "saturation" form field
331          * @property ID.S
332          * @type String
333          * @final
334          * @default yui-picker-s
335          */
336         S: b + "-s",
338         /**
339          * The id for the "value" form field
340          * @property ID.V
341          * @type String
342          * @final
343          * @default yui-picker-v
344          */
345         V: b + "-v",
347         /**
348          * The id for the picker region slider
349          * @property ID.PICKER_BG
350          * @type String
351          * @final
352          * @default yui-picker-bg
353          */
354         PICKER_BG:      b + "-bg",
356         /**
357          * The id for the picker region thumb
358          * @property ID.PICKER_THUMB
359          * @type String
360          * @final
361          * @default yui-picker-thumb
362          */
363         PICKER_THUMB:   b + "-thumb",
365         /**
366          * The id for the hue slider
367          * @property ID.HUE_BG
368          * @type String
369          * @final
370          * @default yui-picker-hue-bg
371          */
372         HUE_BG:         b + "-hue-bg",
374         /**
375          * The id for the hue thumb
376          * @property ID.HUE_THUMB
377          * @type String
378          * @final
379          * @default yui-picker-hue-thumb
380          */
381         HUE_THUMB:      b + "-hue-thumb",
383         /**
384          * The id for the hex value form field
385          * @property ID.HEX
386          * @type String
387          * @final
388          * @default yui-picker-hex
389          */
390         HEX:            b + "-hex",
392         /**
393          * The id for the color swatch
394          * @property ID.SWATCH
395          * @type String
396          * @final
397          * @default yui-picker-swatch
398          */
399         SWATCH:         b + "-swatch",
401         /**
402          * The id for the websafe color swatch
403          * @property ID.WEBSAFE_SWATCH
404          * @type String
405          * @final
406          * @default yui-picker-websafe-swatch
407          */
408         WEBSAFE_SWATCH: b + "-websafe-swatch",
410         /**
411          * The id for the control details
412          * @property ID.CONTROLS
413          * @final
414          * @default yui-picker-controls
415          */
416         CONTROLS: b + "-controls",
418         /**
419          * The id for the rgb controls
420          * @property ID.RGB_CONTROLS
421          * @final
422          * @default yui-picker-rgb-controls
423          */
424         RGB_CONTROLS: b + "-rgb-controls",
426         /**
427          * The id for the hsv controls
428          * @property ID.HSV_CONTROLS
429          * @final
430          * @default yui-picker-hsv-controls
431          */
432         HSV_CONTROLS: b + "-hsv-controls",
433         
434         /**
435          * The id for the hsv controls
436          * @property ID.HEX_CONTROLS
437          * @final
438          * @default yui-picker-hex-controls
439          */
440         HEX_CONTROLS: b + "-hex-controls",
442         /**
443          * The id for the hex summary
444          * @property ID.HEX_SUMMARY
445          * @final
446          * @default yui-picker-hex-summary
447          */
448         HEX_SUMMARY: b + "-hex-summary",
450         /**
451          * The id for the controls section header
452          * @property ID.CONTROLS_LABEL
453          * @final
454          * @default yui-picker-controls-label
455          */
456         CONTROLS_LABEL: b + "-controls-label"
457     };
459     /**
460      * Constants for any script-generated messages.  The values here
461      * are the default messages.  They can be updated by providing
462      * the complete list to the constructor for the "txt" attribute.
463      * @property TXT
464      * @final
465      */
466     proto.TXT = {
467         ILLEGAL_HEX: "Illegal hex value entered",
468         SHOW_CONTROLS: "Show color details",
469         HIDE_CONTROLS: "Hide color details",
470         CURRENT_COLOR: "Currently selected color: {rgb}",
471         CLOSEST_WEBSAFE: "Closest websafe color: {rgb}. Click to select.",
472         R: "R",
473         G: "G",
474         B: "B",
475         H: "H",
476         S: "S",
477         V: "V",
478         HEX: "#",
479         DEG: "\u00B0",
480         PERCENT: "%"
481     };
483     /**
484      * Constants for the default image locations for img tags that are
485      * generated by the control.  They can be modified by passing the
486      * complete list to the contructor for the "images" attribute
487      * @property IMAGE
488      * @final
489      */
490     proto.IMAGE = {
491         PICKER_THUMB: "../../build/colorpicker/assets/picker_thumb.png",
492         HUE_THUMB: "../../build/colorpicker/assets/hue_thumb.png"
493     };
495     /*
496      * Constants for the control's custom event names.  subscribe
497      * to the rgbChange event instead.
498      * @property EVENT
499      * @final
500      */
501     //proto.EVENT = {
502         //CHANGE: "change"
503     //};
505     //proto.CSS = { };
507     /**
508      * Constants for the control's default default values
509      * @property DEFAULT
510      * @final
511      */
512     proto.DEFAULT = {
513         PICKER_SIZE: 180
514     };
516     /**
517      * Constants for the control's configuration attributes
518      * @property OPT
519      * @final
520      */
521     proto.OPT = {
522         HUE: "hue",
523         SATURATION: "saturation",
524         VALUE: "value",
525         RED: "red",
526         GREEN: "green",
527         BLUE: "blue",
528         HSV: "hsv",
529         RGB: "rgb",
530         WEBSAFE: "websafe",
531         HEX: "hex",
532         PICKER_SIZE: "pickersize",
533         SHOW_CONTROLS: "showcontrols",
534         SHOW_RGB_CONTROLS: "showrgbcontrols",
535         SHOW_HSV_CONTROLS: "showhsvcontrols",
536         SHOW_HEX_CONTROLS: "showhexcontrols",
537         SHOW_HEX_SUMMARY: "showhexsummary",
538         SHOW_WEBSAFE: "showwebsafe",
539         //SHOW_SUBMIT: "showsubmit",
540         CONTAINER: "container",
541         IDS: "ids",
542         ELEMENTS: "elements",
543         TXT: "txt",
544         IMAGES: "images",
545         ANIMATE: "animate"
546     };
548     /**
549      * Sets the control to the specified rgb value and
550      * moves the sliders to the proper positions
551      * @method setValue
552      * @param rgb {[int, int, int]} the rgb value
553      * @param silent {boolean} whether or not to fire the change event
554      */
555     proto.setValue = function(rgb, silent) {
556         silent = (silent) || false;
557         this.set(this.OPT.RGB, rgb, silent);
558         _updateSliders.call(this);
559     };
561     /**
562      * The hue slider
563      * @property hueSlider
564      * @type YAHOO.widget.Slider
565      */
566     proto.hueSlider = null; 
567     
568     /**
569      * The picker region
570      * @property pickerSlider
571      * @type YAHOO.widget.Slider
572      */
573     proto.pickerSlider = null;
575     /**
576      * Translates the slider value into hue, int[0,359]
577      * @method _getH
578      * @private
579      * @return {int} the hue from 0 to 359
580      */
581     var _getH = function() {
582         var size = this.get(this.OPT.PICKER_SIZE),
583             h = (size - this.hueSlider.getValue()) / size;
584         h = Math.round(h*360);
585         return (h === 360) ? 0 : h;
586     };
588     /**
589      * Translates the slider value into saturation, int[0,1], left to right
590      * @method _getS
591      * @private
592      * @return {int} the saturation from 0 to 1
593      */
594     var _getS = function() {
595         return this.pickerSlider.getXValue() / this.get(this.OPT.PICKER_SIZE);
596     };
598     /**
599      * Translates the slider value into value/brightness, int[0,1], top
600      * to bottom
601      * @method _getV
602      * @private
603      * @return {int} the value from 0 to 1
604      */
605     var _getV = function() {
606         var size = this.get(this.OPT.PICKER_SIZE);
607         return (size - this.pickerSlider.getYValue()) / size;
608     };
610     /**
611      * Updates the background of the swatch with the current rbg value.
612      * Also updates the websafe swatch to the closest websafe color
613      * @method _updateSwatch
614      * @private
615      */
616     var _updateSwatch = function() {
617         var rgb = this.get(this.OPT.RGB),
618             websafe = this.get(this.OPT.WEBSAFE),
619             el = this.getElement(this.ID.SWATCH),
620             color = rgb.join(","),
621             txt = this.get(this.OPT.TXT);
623         Dom.setStyle(el, "background-color", "rgb(" + color  + ")");
624         el.title = lang.substitute(txt.CURRENT_COLOR, {
625                 "rgb": "#" + this.get(this.OPT.HEX)
626             });
629         el = this.getElement(this.ID.WEBSAFE_SWATCH);
630         color = websafe.join(",");
632         Dom.setStyle(el, "background-color", "rgb(" + color + ")");
633         el.title = lang.substitute(txt.CLOSEST_WEBSAFE, {
634                 "rgb": "#" + Color.rgb2hex(websafe)
635             });
637     };
639     /**
640      * Reads the sliders and converts the values to RGB, updating the
641      * internal state for all the individual form fields
642      * @method _getValuesFromSliders
643      * @private
644      */
645     var _getValuesFromSliders = function() {
646         var h=_getH.call(this), s=_getS.call(this), v=_getV.call(this);
647         YAHOO.log("hsv " + [h, s, v]);
649         rgb = Color.hsv2rgb(h, s, v);
650         var websafe = Color.websafe(rgb);
651         var hex = Color.rgb2hex(rgb[0], rgb[1], rgb[2]);
653         this.set(this.OPT.RGB, rgb);
654     };
656     /**
657      * Updates the form field controls with the state data contained
658      * in the control.
659      * @method _updateFormFields
660      * @private
661      */
662     var _updateFormFields = function() {
663         this.getElement(this.ID.H).value = this.get(this.OPT.HUE);
664         this.getElement(this.ID.S).value = this.get(this.OPT.SATURATION);
665         this.getElement(this.ID.V).value = this.get(this.OPT.VALUE);
666         this.getElement(this.ID.R).value = this.get(this.OPT.RED);
667         this.getElement(this.ID.R_HEX).innerHTML = Color.dec2hex(this.get(this.OPT.RED));
668         this.getElement(this.ID.G).value = this.get(this.OPT.GREEN);
669         this.getElement(this.ID.G_HEX).innerHTML = Color.dec2hex(this.get(this.OPT.GREEN));
670         this.getElement(this.ID.B).value = this.get(this.OPT.BLUE);
671         this.getElement(this.ID.B_HEX).innerHTML = Color.dec2hex(this.get(this.OPT.BLUE));
672         this.getElement(this.ID.HEX).value = this.get(this.OPT.HEX);
673     };
675     /**
676      * Event handler for the hue slider.
677      * @method _onHueSliderChange
678      * @param newOffset {int} pixels from the start position
679      * @private
680      */
681     var _onHueSliderChange = function(newOffset) {
682         this.logger.log("hue update: " + newOffset , "warn");
684         var h = _getH.call(this);
685         this.set(this.OPT.HUE, h, true);
687         // set picker background to the hue
688         var rgb = Color.hsv2rgb(h, 1, 1);
689         var styleDef = "rgb(" + rgb.join(",") + ")";
691         Dom.setStyle(this.getElement(this.ID.PICKER_BG), "background-color", styleDef);
693         if (this.hueSlider.valueChangeSource === this.hueSlider.SOURCE_UI_EVENT) {
694             _getValuesFromSliders.call(this);
695         }
697         _updateFormFields.call(this);
698         _updateSwatch.call(this);
699     };
701     /**
702      * Event handler for the picker slider, which controls the
703      * saturation and value/brightness.
704      * @method _onPickerSliderChange
705      * @param newOffset {{x: int, y: int}} x/y pixels from the start position
706      * @private
707      */
708     var _onPickerSliderChange = function(newOffset) {
709         this.logger.log(sub("picker update [{x}, {y}]", newOffset));
711         var s=_getS.call(this), v=_getV.call(this);
712         this.set(this.OPT.SATURATION, Math.round(s*100), true);
713         this.set(this.OPT.VALUE, Math.round(v*100), true);
715         if (this.pickerSlider.valueChangeSource === this.pickerSlider.SOURCE_UI_EVENT) {
716             _getValuesFromSliders.call(this);
717         }
719         _updateFormFields.call(this);
720         _updateSwatch.call(this);
721     };
724     /**
725      * Key map to well-known commands for txt field input
726      * @method _getCommand
727      * @param e {Event} the keypress or keydown event
728      * @return {int} a command code
729      * <ul>
730      * <li>0 = not a number, letter in range, or special key</li>
731      * <li>1 = number</li>
732      * <li>2 = a-fA-F</li>
733      * <li>3 = increment (up arrow)</li>
734      * <li>4 = decrement (down arrow)</li>
735      * <li>5 = special key (tab, delete, return, escape, left, right)</li> 
736      * <li>6 = return</li>
737      * </ul>
738      * @private
739      */
740     var _getCommand = function(e) {
741         var c = Event.getCharCode(e);
743         //alert(Event.getCharCode(e) + ", " + e.keyCode + ", " + e.charCode);
745         // special keys
746         if (c === 38) { // up arrow
747             return 3;
748         } else if (c === 13) { // return
749             return 6;
750         } else if (c === 40) { // down array
751             return 4;
752         } else if (c >= 48 && c<=57) { // 0-9
753             return 1;
754         } else if (c >= 97 && c<=102) { // a-f
755             return 2;
756         } else if (c >= 65 && c<=70) { // A-F
757             return 2;
758         //} else if ("8, 9, 13, 27, 37, 39".indexOf(c) > -1 || 
759         //              (c >= 112 && c <=123)) { // including F-keys
760         // tab, delete, return, escape, left, right
761         } else if ("8, 9, 13, 27, 37, 39".indexOf(c) > -1) { // special chars
762             return 5;
763         } else { // something we probably don't want
764             return 0;
765         }
766     };
768     /**
769      * Handle keypress on one of the rgb or hsv fields.
770      * @method _rgbFieldKeypress
771      * @param e {Event} the keypress event
772      * @param el {HTMLElement} the field
773      * @param prop {string} the key to the linked property
774      * @private
775      */
776     var _rgbFieldKeypress = function(e, el, prop) {
777         var command = _getCommand(e);
778         var inc = (e.shiftKey) ? 10 : 1;
779         switch (command) {
780             case 6: // return, update the value
781                 _useFieldValue.apply(this, arguments);
782                 break;
783                         
784             case 3: // up arrow, increment
785                 this.set(prop, Math.min(this.get(prop)+inc, 255));
786                 _updateFormFields.call(this);
787                 //Event.stopEvent(e);
788                 break;
789             case 4: // down arrow, decrement
790                 this.set(prop, Math.max(this.get(prop)-inc, 0));
791                 _updateFormFields.call(this);
792                 //Event.stopEvent(e);
793                 break;
795             default:
796         }
798     };
800     /**
801      * Handle keydown on the hex field
802      * @method _hexFieldKeypress
803      * @param e {Event} the keypress event
804      * @param el {HTMLElement} the field
805      * @param prop {string} the key to the linked property
806      * @private
807      */
808     var _hexFieldKeypress = function(e, el, prop) {
809         var command = _getCommand(e);
810         if (command === 6) { // return, update the value
811             _useFieldValue.apply(this, arguments);
812         }
813     };
815     /**
816      * Use the value of the text field to update the control
817      * @method _hexFieldKeypress
818      * @param e {Event} an event
819      * @param el {HTMLElement} the field
820      * @param prop {string} the key to the linked property
821      * @private
822      */
823     var _useFieldValue = function(e, el, prop) {
824         var val = el.value;
826         if (prop !== this.OPT.HEX) {
827             val = parseInt(val, 10);
828         }
830         if (val !== this.get(prop)) {
831             this.set(prop, val);
832         }
833     };
835     /** 
836      * Allows numbers and special chars only.  Used for the
837      * rgb and hsv fields keypress handler.
838      * @method _numbersOnly
839      * @param e {Event} the event
840      * @private
841      * @return {boolean} false if we are canceling the event
842      */
843     var _numbersOnly = function(e) {
844         return _hexOnly(e, true);
845     };
847     /** 
848      * Allows numbers and special chars, and by default allows a-f.  
849      * Used for the hex field keypress handler.
850      * @method _hexOnly
851      * @param e {Event} the event
852      * @param numbersOnly omits a-f if set to true
853      * @private
854      * @return {boolean} false if we are canceling the event
855      */
856     var _hexOnly = function(e, numbersOnly) {
857         var command = _getCommand(e);
858         switch (command) {
859             case 6: // return
860             case 5: // special char
861             case 1: // number
862                 break;
863             case 2: // hex char (a-f)
864                 if (numbersOnly !== true) {
865                     break;
866                 }
868                 // fallthrough is intentional
870             default: // prevent alpha and punctuation
871                 Event.stopEvent(e);
872                 return false;
873         }
874     };
876     /**
877      * Returns the element reference that is saved.  The id can be either
878      * the element id, or the key for this id in the "id" config attribute.
879      * For instance, the host element id can be obtained by passing its
880      * id (default: "yui_picker") or by its key "YUI_PICKER".
881      * @param id {string} the element id, or key 
882      * @return {HTMLElement} a reference to the element
883      */
884     proto.getElement = function(id) { 
885         return this.get(this.OPT.ELEMENTS)[this.get(this.OPT.IDS)[id]]; 
886     };
888     _createElements = function() {
889         this.logger.log("Building markup");
890         var el, child, img, fld, i, 
891             ids = this.get(this.OPT.IDS),
892             txt = this.get(this.OPT.TXT),
893             images = this.get(this.OPT.IMAGES),
894             Elem = function(type, o) {
895                 var n = document.createElement(type);
896                 if (o) {
897                     lang.augmentObject(n, o, true);
898                 }
899                 return n;
900             },
901             RGBElem = function(type, obj) {
902                 var o = lang.merge({
903                         //type: "txt",
904                         autocomplete: "off",
905                         value: "0",
906                         size: 3,
907                         maxlength: 3
908                     }, obj);
910                 o.name = o.id;
911                 return new Elem(type, o);
912             };
914         var p = this.get("element");
916         // Picker slider (S and V) ---------------------------------------------
918         el = new Elem("div", {
919             id: ids[this.ID.PICKER_BG],
920             className: "yui-picker-bg",
921             tabIndex: -1,
922             hideFocus: true
923         });
925         child = new Elem("div", {
926             id: ids[this.ID.PICKER_THUMB],
927             className: "yui-picker-thumb"
928         });
930         img = new Elem("img", {
931             src: images.PICKER_THUMB
932         });
934         child.appendChild(img);
935         el.appendChild(child);
936         p.appendChild(el);
937         
938         // Hue slider ---------------------------------------------
939         el = new Elem("div", {
940             id: ids[this.ID.HUE_BG],
941             className: "yui-picker-hue-bg",
942             tabIndex: -1,
943             hideFocus: true
944         });
946         child = new Elem("div", {
947             id: ids[this.ID.HUE_THUMB],
948             className: "yui-picker-hue-thumb"
949         });
951         img = new Elem("img", {
952             src: images.HUE_THUMB
953         });
955         child.appendChild(img);
956         el.appendChild(child);
957         p.appendChild(el);
960         // controls ---------------------------------------------
962         el = new Elem("div", {
963             id: ids[this.ID.CONTROLS],
964             className: "yui-picker-controls"
965         });
967         p.appendChild(el);
968         p = el;
970             // controls header
971             el = new Elem("div", {
972                 className: "hd"
973             });
975             child = new Elem("a", {
976                 id: ids[this.ID.CONTROLS_LABEL],
977                 //className: "yui-picker-controls-label",
978                 href: "#"
979             });
980             el.appendChild(child);
981             p.appendChild(el);
983             // bd
984             el = new Elem("div", {
985                 className: "bd"
986             });
988             p.appendChild(el);
989             p = el;
991                 // rgb
992                 el = new Elem("ul", {
993                     id: ids[this.ID.RGB_CONTROLS],
994                     className: "yui-picker-rgb-controls"
995                 });
997                 child = new Elem("li");
998                 child.appendChild(document.createTextNode(txt.R + " "));
1000                 fld = new RGBElem("input", {
1001                     id: ids[this.ID.R],
1002                     className: "yui-picker-r"
1003                 });
1005                 child.appendChild(fld);
1006                 el.appendChild(child);
1008                 child = new Elem("li");
1009                 child.appendChild(document.createTextNode(txt.G + " "));
1011                 fld = new RGBElem("input", {
1012                     id: ids[this.ID.G],
1013                     className: "yui-picker-g"
1014                 });
1016                 child.appendChild(fld);
1017                 el.appendChild(child);
1019                 child = new Elem("li");
1020                 child.appendChild(document.createTextNode(txt.B + " "));
1022                 fld = new RGBElem("input", {
1023                     id: ids[this.ID.B],
1024                     className: "yui-picker-b"
1025                 });
1027                 child.appendChild(fld);
1028                 el.appendChild(child);
1030                 p.appendChild(el);
1032                 // hsv
1033                 el = new Elem("ul", {
1034                     id: ids[this.ID.HSV_CONTROLS],
1035                     className: "yui-picker-hsv-controls"
1036                 });
1038                 child = new Elem("li");
1039                 child.appendChild(document.createTextNode(txt.H + " "));
1041                 fld = new RGBElem("input", {
1042                     id: ids[this.ID.H],
1043                     className: "yui-picker-h"
1044                 });
1046                 child.appendChild(fld);
1047                 child.appendChild(document.createTextNode(" " + txt.DEG));
1049                 el.appendChild(child);
1051                 child = new Elem("li");
1052                 child.appendChild(document.createTextNode(txt.S + " "));
1054                 fld = new RGBElem("input", {
1055                     id: ids[this.ID.S],
1056                     className: "yui-picker-s"
1057                 });
1059                 child.appendChild(fld);
1060                 child.appendChild(document.createTextNode(" " + txt.PERCENT));
1062                 el.appendChild(child);
1064                 child = new Elem("li");
1065                 child.appendChild(document.createTextNode(txt.V + " "));
1067                 fld = new RGBElem("input", {
1068                     id: ids[this.ID.V],
1069                     className: "yui-picker-v"
1070                 });
1072                 child.appendChild(fld);
1073                 child.appendChild(document.createTextNode(" " + txt.PERCENT));
1075                 el.appendChild(child);
1076                 p.appendChild(el);
1079                 // hex summary
1081                 el = new Elem("ul", {
1082                     id: ids[this.ID.HEX_SUMMARY],
1083                     className: "yui-picker-hex_summary"
1084                 });
1086                 child = new Elem("li", {
1087                     id: ids[this.ID.R_HEX]
1088                 });
1089                 el.appendChild(child);
1091                 child = new Elem("li", {
1092                     id: ids[this.ID.G_HEX]
1093                 });
1094                 el.appendChild(child);
1096                 child = new Elem("li", {
1097                     id: ids[this.ID.B_HEX]
1098                 });
1099                 el.appendChild(child);
1100                 p.appendChild(el);
1102                 // hex field
1103                 el = new Elem("div", {
1104                     id: ids[this.ID.HEX_CONTROLS],
1105                     className: "yui-picker-hex-controls"
1106                 });
1107                 el.appendChild(document.createTextNode(txt.HEX + " "));
1109                 child = new RGBElem("input", {
1110                     id: ids[this.ID.HEX],
1111                     className: "yui-picker-hex",
1112                     size: 6,
1113                     maxlength: 6
1114                 });
1116                 el.appendChild(child);
1117                 p.appendChild(el);
1119                 p = this.get("element");
1121                 // swatch
1122                 el = new Elem("div", {
1123                     id: ids[this.ID.SWATCH],
1124                     className: "yui-picker-swatch"
1125                 });
1127                 p.appendChild(el);
1129                 // websafe swatch
1130                 el = new Elem("div", {
1131                     id: ids[this.ID.WEBSAFE_SWATCH],
1132                     className: "yui-picker-websafe-swatch"
1133                 });
1135                 p.appendChild(el);
1137     };
1139     /**
1140      * Sets the initial state of the sliders
1141      * @method initPicker
1142      */
1143     proto.initPicker = function () {
1145         // bind all of our elements
1146         var o=this.OPT, 
1147             ids = this.get(o.IDS), 
1148             els = this.get(o.ELEMENTS), 
1149                   i, el, id;
1151         // Add the default value as a key for each element for easier lookup
1152         for (i in this.ID) {
1153             if (lang.hasOwnProperty(this.ID, i)) {
1154                 ids[this.ID[i]] = ids[i];
1155             }
1156         }
1158         // Check for picker element, if not there, create all of them
1159         el = Dom.get(ids[this.ID.PICKER_BG]);
1160         if (!el) {
1161             _createElements.call(this);
1162         } else {
1163             this.logger.log("Using pre-existing markup");
1164         }
1166         for (i in ids) {
1167             if (lang.hasOwnProperty(ids, i)) {
1168                 // look for element
1169                 el = Dom.get(ids[i]);
1171                 // generate an id if the implementer passed in an element reference,
1172                 // and the element did not have an id already
1173                 id = Dom.generateId(el);
1175                 // update the id in case we generated the id
1176                 ids[i] = id; // key is WEBSAFE_SWATCH
1177                 ids[ids[i]] = id; // key is websafe_swatch
1179                 // store the dom ref
1180                 els[id] = el;
1181             }
1182         }
1184         // set the initial visibility state of our controls
1185             els = [o.SHOW_CONTROLS, 
1186                    o.SHOW_RGB_CONTROLS,
1187                    o.SHOW_HSV_CONTROLS,
1188                    o.SHOW_HEX_CONTROLS,
1189                    o.SHOW_HEX_SUMMARY,
1190                    o.SHOW_WEBSAFE
1191                    ];
1193         for (i=0; i<els.length; i=i+1) {
1194             this.set(els[i], this.get(els[i]));
1195         }
1197         var s = this.get(o.PICKER_SIZE);
1198         this.logger.log("picker size" + s);
1200         this.hueSlider = Slider.getVertSlider(this.getElement(this.ID.HUE_BG), 
1201                                               this.getElement(this.ID.HUE_THUMB), 0, s);
1202         this.hueSlider.subscribe("change", _onHueSliderChange, this, true);
1204         this.pickerSlider = Slider.getSliderRegion(this.getElement(this.ID.PICKER_BG), 
1205                                                    this.getElement(this.ID.PICKER_THUMB), 0, s, 0, s);
1206         this.pickerSlider.subscribe("change", _onPickerSliderChange, this, true);
1208         //_onHueSliderChange.call(this, 0);
1210         Event.on(this.getElement(this.ID.WEBSAFE_SWATCH), "click", function(e) {
1211                this.setValue(this.get(o.WEBSAFE));
1212                //_updateSliders
1213            }, this, true);
1215         Event.on(this.getElement(this.ID.CONTROLS_LABEL), "click", function(e) {
1216                this.set(o.SHOW_CONTROLS, !this.get(o.SHOW_CONTROLS));
1217                Event.preventDefault(e);
1218            }, this, true);
1220         _attachRGBHSV.call(this, this.ID.R, this.OPT.RED); 
1221         _attachRGBHSV.call(this, this.ID.G, this.OPT.GREEN); 
1222         _attachRGBHSV.call(this, this.ID.B, this.OPT.BLUE); 
1223         _attachRGBHSV.call(this, this.ID.H, this.OPT.HUE); 
1224         _attachRGBHSV.call(this, this.ID.S, this.OPT.SATURATION); 
1225         _attachRGBHSV.call(this, this.ID.V, this.OPT.VALUE); 
1227         Event.on(this.getElement(this.ID.HEX), "keydown", function(e, me) {
1228                 _hexFieldKeypress.call(me, e, this, me.OPT.HEX);
1229             }, this);
1231         Event.on(this.getElement(this.ID.HEX), "keypress", _hexOnly, this);
1232         Event.on(this.getElement(this.ID.HEX), "blur", function(e, me) {
1233                 _useFieldValue.call(me, e, this, me.OPT.HEX);
1234             }, this);
1235     };
1237     _attachRGBHSV = function(id, config) {
1238         Event.on(this.getElement(id), "keydown", function(e, me) {
1239                 _rgbFieldKeypress.call(me, e, this, config);
1240             }, this);
1241         Event.on(this.getElement(id), "keypress", _numbersOnly, this);
1242         Event.on(this.getElement(id), "blur", function(e, me) {
1243                 _useFieldValue.call(me, e, this, config);
1244             }, this);
1245     };
1248     /**
1249      * Sets up the config attributes and the change listeners for this
1250      * properties
1251      * @method initAttributes
1252      * @param attr An object containing default attribute values
1253      */
1254     proto.initAttributes = function(attr) {
1256         attr = attr || {};
1257         YAHOO.widget.ColorPicker.superclass.initAttributes.call(this, attr);
1258         
1259         /**
1260          * The size of the picker. Trying to change this is not recommended.
1261          * @config pickersize
1262          * @default 180
1263          * @type int
1264          */
1265         this.setAttributeConfig(this.OPT.PICKER_SIZE, {
1266                 value: attr.size || this.DEFAULT.PICKER_SIZE
1267             });
1269         /**
1270          * The current hue value 0-360
1271          * @config hue
1272          * @type int
1273          */
1274         this.setAttributeConfig(this.OPT.HUE, {
1275                 value: attr.hue || 0,
1276                 validator: lang.isNumber
1277             });
1279         /**
1280          * The current saturation value 0-100
1281          * @config saturation
1282          * @type int
1283          */
1284         this.setAttributeConfig(this.OPT.SATURATION, {
1285                 value: attr.saturation || 0,
1286                 validator: lang.isNumber
1287             });
1289         /**
1290          * The current value/brightness value 0-100
1291          * @config value
1292          * @type int
1293          */
1294         this.setAttributeConfig(this.OPT.VALUE, {
1295                 value: attr.value || 100,
1296                 validator: lang.isNumber
1297             });
1299         /**
1300          * The current red value 0-255
1301          * @config red
1302          * @type int
1303          */
1304         this.setAttributeConfig(this.OPT.RED, {
1305                 value: attr.red || 255,
1306                 validator: lang.isNumber
1307             });
1309         /**
1310          * The current green value 0-255
1311          * @config green 
1312          * @type int
1313          */
1314         this.setAttributeConfig(this.OPT.GREEN, {
1315                 value: attr.red || 255,
1316                 validator: lang.isNumber
1317             });
1319         /**
1320          * The current blue value 0-255
1321          * @config blue
1322          * @type int
1323          */
1324         this.setAttributeConfig(this.OPT.BLUE, {
1325                 value: attr.blue || 255,
1326                 validator: lang.isNumber
1327             });
1329         /**
1330          * The current hex value #000000-#FFFFFF, without the #
1331          * @config hex
1332          * @type string
1333          */
1334         this.setAttributeConfig(this.OPT.HEX, {
1335                 value: attr.hex || "FFFFFF",
1336                 validator: lang.isString
1337             });
1339         /**
1340          * The current rgb value.  Updates the state of all of the
1341          * other value fields.  Read-only: use setValue to set the
1342          * controls rgb value.
1343          * @config hex
1344          * @type [int, int, int]
1345          * @readonly
1346          */
1347         this.setAttributeConfig(this.OPT.RGB, {
1348                 value: attr.rgb || [255,255,255],
1349                 method: function(rgb) {
1351                     this.set(this.OPT.RED, rgb[0], true);
1352                     this.set(this.OPT.GREEN, rgb[1], true);
1353                     this.set(this.OPT.BLUE, rgb[2], true);
1355                     var websafe = Color.websafe(rgb);
1356                     this.set(this.OPT.WEBSAFE, websafe, true);
1358                     var hex = Color.rgb2hex(rgb);
1359                     this.set(this.OPT.HEX, hex, true);
1361                     var hsv = Color.rgb2hsv(rgb);
1363                     this.logger.log(sub("RGB value set to {rgb} (hsv: {hsv})", {
1364                             "hsv": hsv, "rgb": rgb
1365                         }));
1367                     this.set(this.OPT.HUE, hsv[0], true);
1368                     this.set(this.OPT.SATURATION, Math.round(hsv[1]*100), true);
1369                     this.set(this.OPT.VALUE, Math.round(hsv[2]*100), true);
1370                 },
1371                 readonly: true
1372             });
1374         /**
1375          * If the color picker will live inside of a container object,
1376          * set, provide a reference to it so the control can use the
1377          * container's events.
1378          * @config container
1379          * @type YAHOO.widget.Panel
1380          */
1381         this.setAttributeConfig(this.OPT.CONTAINER, {
1382                     value: null,
1383                     method: function(container) {
1384                         if (container) {
1385                             // Position can get out of sync when the
1386                             // control is manipulated while display is
1387                             // none.  Resetting the slider constraints
1388                             // when it is visible gets the state back in
1389                             // order.
1390                             container.showEvent.subscribe(function() {
1391                                 // this.pickerSlider.thumb.resetConstraints();
1392                                 // this.hueSlider.thumb.resetConstraints();
1393                                 this.pickerSlider.focus();
1394                             }, this, true);
1395                         }
1396                     }
1397                 });
1398         /**
1399          * The closest current websafe value
1400          * @config websafe
1401          * @type int
1402          */
1403         this.setAttributeConfig(this.OPT.WEBSAFE, {
1404                 value: attr.websafe || [255,255,255]
1405             });
1408         ids = attr.ids || lang.merge({}, this.ID);
1410         if (!attr.ids && pickercount > 1) {
1411             for (var i in ids) {
1412                 if (lang.hasOwnProperty(ids, i)) {
1413                     ids[i] = ids[i] + pickercount;
1414                 }
1415             }
1416         }
1419         /**
1420          * A list of element ids and/or element references used by the 
1421          * control.  The default is the this.ID list, and can be customized
1422          * by passing a list in the contructor
1423          * @config ids
1424          * @type {referenceid: realid}
1425          * @writeonce
1426          */
1427         this.setAttributeConfig(this.OPT.IDS, {
1428                 value: ids,
1429                 writeonce: true
1430             });
1432         /**
1433          * A list of txt strings for internationalization.  Default
1434          * is this.TXT
1435          * @config txt
1436          * @type {key: txt}
1437          * @writeonce
1438          */
1439         this.setAttributeConfig(this.OPT.TXT, {
1440                 value: attr.txt || this.TXT,
1441                 writeonce: true
1442             });
1444         /**
1445          * The img src default list
1446          * is this.IMAGES
1447          * @config images
1448          * @type {key: image}
1449          * @writeonce
1450          */
1451         this.setAttributeConfig(this.OPT.IMAGES, {
1452                 value: attr.images || this.IMAGE,
1453                 writeonce: true
1454             });
1455         /**
1456          * The element refs used by this control.  Set at initialization
1457          * @config elements
1458          * @type {id: HTMLElement}
1459          * @readonly
1460          */
1461         this.setAttributeConfig(this.OPT.ELEMENTS, {
1462                 value: {},
1463                 readonly: true
1464             });
1466         /**
1467          * Returns the cached element reference.  If the id is not a string, it
1468          * is assumed that it is an element and this is returned.
1469          * @param id {string|HTMLElement} the element key, id, or ref
1470          * @param on {boolean} hide or show.  If true, show
1471          * @private */
1472         _hideShowEl = function(id, on) {
1473             var el = (lang.isString(id) ? this.getElement(id) : id);
1474             //Dom.setStyle(id, "visibility", (on) ? "" : "hidden");
1475             Dom.setStyle(el, "display", (on) ? "" : "none");
1476         };
1478         /**
1479          * Hide/show the entire set of controls
1480          * @config showcontrols
1481          * @type boolean
1482          * @default true
1483          */
1484         this.setAttributeConfig(this.OPT.SHOW_CONTROLS, {
1485                 value: (attr.showcontrols) || true,
1486                 method: function(on) {
1488                     var el = Dom.getElementsByClassName("bd", "div", 
1489                             this.getElement(this.ID.CONTROLS))[0];
1491                     _hideShowEl.call(this, el, on);
1493                     this.getElement(this.ID.CONTROLS_LABEL).innerHTML = 
1494                         (on) ? this.get(this.OPT.TXT).HIDE_CONTROLS :
1495                                this.get(this.OPT.TXT).SHOW_CONTROLS;
1497                 }
1498             });
1500         /**
1501          * Hide/show the rgb controls
1502          * @config showrgbcontrols
1503          * @type boolean
1504          * @default true
1505          */
1506         this.setAttributeConfig(this.OPT.SHOW_RGB_CONTROLS, {
1507                 value: (attr.showrgbcontrols) || true,
1508                 method: function(on) {
1509                     //Dom.setStyle(this.getElement(this.ID.RBG_CONTROLS), "visibility", (on) ? "" : "hidden");
1510                     _hideShowEl.call(this, this.ID.RGB_CONTROLS, on);
1511                 }
1512             });
1514         /**
1515          * Hide/show the hsv controls
1516          * @config showhsvcontrols
1517          * @type boolean
1518          * @default false
1519          */
1520         this.setAttributeConfig(this.OPT.SHOW_HSV_CONTROLS, {
1521                 value: (attr.showhsvcontrols) || false,
1522                 method: function(on) {
1523                     //Dom.setStyle(this.getElement(this.ID.HSV_CONTROLS), "visibility", (on) ? "" : "hidden");
1524                     _hideShowEl.call(this, this.ID.HSV_CONTROLS, on);
1526                     // can't show both the hsv controls and the rbg hex summary
1527                     if (on && this.get(this.OPT.SHOW_HEX_SUMMARY)) {
1528                         this.set(this.OPT.SHOW_HEX_SUMMARY, false);
1529                     }
1530                 }
1531             });
1533         /**
1534          * Hide/show the hex controls
1535          * @config showhexcontrols
1536          * @type boolean
1537          * @default true
1538          */
1539         this.setAttributeConfig(this.OPT.SHOW_HEX_CONTROLS, {
1540                 value: (attr.showhexcontrols) || false,
1541                 method: function(on) {
1542                     _hideShowEl.call(this, this.ID.HEX_CONTROLS, on);
1543                 }
1544             });
1546         /**
1547          * Hide/show the websafe swatch
1548          * @config showwebsafe
1549          * @type boolean
1550          * @default true
1551          */
1552         this.setAttributeConfig(this.OPT.SHOW_WEBSAFE, {
1553                 value: (attr.showwebsafe) || true,
1554                 method: function(on) {
1555                     _hideShowEl.call(this, this.ID.WEBSAFE_SWATCH, on);
1556                 }
1557             });
1559         /**
1560          * Hide/show the hex summary
1561          * @config showhexsummary
1562          * @type boolean
1563          * @default true
1564          */
1565         this.setAttributeConfig(this.OPT.SHOW_HEX_SUMMARY, {
1566                 value: (attr.showhexsummary) || true,
1567                 method: function(on) {
1568                     _hideShowEl.call(this, this.ID.HEX_SUMMARY, on);
1570                     // can't show both the hsv controls and the rbg hex summary
1571                     if (on && this.get(this.OPT.SHOW_HSV_CONTROLS)) {
1572                         this.set(this.OPT.SHOW_HSV_CONTROLS, false);
1573                     }
1574                 }
1575             });
1576         this.setAttributeConfig(this.OPT.ANIMATE, {
1577                 value: (attr.animate) || true,
1578                 method: function(on) {
1579                     this.pickerSlider.animate = on;
1580                     this.hueSlider.animate = on;
1581                 }
1582             });
1584         this.on(this.OPT.HUE + "Change", _updateRGBFromHSV, this, true);
1585         this.on(this.OPT.SATURATION + "Change", _updateRGBFromHSV, this, true);
1586         this.on(this.OPT.VALUE + "Change", _updatePickerSlider, this, true);
1588         this.on(this.OPT.RED + "Change", _updateRGB, this, true);
1589         this.on(this.OPT.GREEN + "Change", _updateRGB, this, true);
1590         this.on(this.OPT.BLUE + "Change", _updateRGB, this, true);
1592         this.on(this.OPT.HEX + "Change", _updateHex, this, true);
1594         this.initPicker();
1595     };
1597     /**
1598      * Updates the rgb attribute with the current state of the r,g,b
1599      * fields.  This is invoked from change listeners on these
1600      * attributes to facilitate updating these values from the
1601      * individual form fields
1602      * @method _updateRGB
1603      * @private
1604      */
1605     var _updateRGB = function() {
1606         var rgb = [this.get(this.OPT.RED), 
1607                    this.get(this.OPT.GREEN),
1608                    this.get(this.OPT.BLUE)];
1610         this.logger.log("RGB value set to " + rgb);
1611         this.set(this.OPT.RGB, rgb);
1613         _updateSliders.call(this);
1614     };
1616     /**
1617      * Updates the RGB values from the current state of the HSV
1618      * values.  Executed when the one of the HSV form fields are
1619      * updated
1620      * _updateRGBFromHSV
1621      * @private
1622      */
1623     var _updateRGBFromHSV = function() {
1624         var hsv = [this.get(this.OPT.HUE), 
1625                    this.get(this.OPT.SATURATION)/100,
1626                    this.get(this.OPT.VALUE)/100];
1628         var rgb = Color.hsv2rgb(hsv);
1630         this.logger.log("HSV converted to RGB " + hsv + " : " + rgb);
1631         this.set(this.OPT.RGB, rgb);
1633         _updateSliders.call(this);
1634     };
1636     /**
1637      * Parses the hex string to normalize shorthand values, converts
1638      * the hex value to rgb and updates the rgb attribute (which
1639      * updates the state for all of the other values)
1640      * method _updateHex
1641      * @private
1642      */
1643     var _updateHex = function() {
1644        
1645         var hex = this.get(this.OPT.HEX), l=hex.length;
1647         // support #369 -> #336699 shorthand
1648         if (l === 3) {
1649             var c = hex.split(""), i;
1650             for (i=0; i<l; i=i+1) {
1651                 c[i] = c[i] + c[i];
1652             }
1654             hex = c.join("");
1655         }
1657         if (hex.length !== 6) {
1658             this.logger.log(this.get(this.TXT.ILLEGAL_HEX), "error");
1659             return false;
1660         }
1662         var rgb = Color.hex2rgb(hex);
1664         this.logger.log(sub("Hex value set to {hex} ({rgb})", {
1665                 hex: hex, rgb: rgb
1666             }));
1668         this.setValue(rgb);
1670         //_updateSliders.call(this);
1672     };
1674     /**
1675      * Moves the sliders into the position dictated by the current state
1676      * of the control
1677      * @method _updateSliders
1678      * @private
1679      */
1680     var _updateSliders = function() {
1681         _updateHueSlider.call(this);
1682         _updatePickerSlider.call(this);
1683     };
1685     /**
1686      * Moves the hue slider into the position dictated by the current state
1687      * of the control
1688      * @method _updateHueSlider
1689      * @private
1690      */
1691     var _updateHueSlider = function() {
1692         var size = this.get(this.OPT.PICKER_SIZE),
1693             h = this.get(this.OPT.HUE);
1695         h = size - Math.round(h / 360 * size);
1696         
1697         // 0 is at the top and bottom of the hue slider.  Always go to
1698         // the top so we don't end up sending the thumb to the bottom
1699         // when the value didn't actually change (e.g., a conversion
1700         // produced 360 instead of 0 and the value was already 0).
1701         if (h === size) {
1702             h = 0;
1703         }
1704         this.logger.log("Hue slider is being set to " + h);
1706         this.hueSlider.setValue(h);
1707     };
1709     /**
1710      * Moves the picker slider into the position dictated by the current state
1711      * of the control
1712      * @method _updatePickerSlider
1713      * @private
1714      */
1715     var _updatePickerSlider = function() {
1716         var size = this.get(this.OPT.PICKER_SIZE),
1717             s = this.get(this.OPT.SATURATION),
1718             v = this.get(this.OPT.VALUE);
1720         s = Math.round(s * size / 100);
1721         v = Math.round(size - (v * size / 100));
1723         this.logger.log("Setting picker slider to " + [s, v]);
1725         this.pickerSlider.setRegionValue(s, v);
1726     };
1728     /**
1729      * Creates the host element if it doesn't exist
1730      * @method _createHostElement
1731      * @private
1732      */
1733     var _createHostElement = function() {
1734         var el = document.createElement('div');
1736         if (this.CSS.BASE) {
1737             el.className = this.CSS.BASE;
1738         }
1739         
1740         return el;
1741     };
1744 })();
1745 YAHOO.register("colorpicker", YAHOO.widget.ColorPicker, {version: "2.3.0", build: "442"});