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