Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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