Include simple color picker
[infodrom.org/service.infodrom.org] / src / jquery.simplecolorpicker.js
1 /*!
2  * Very simple jQuery Color Picker
3  * https://github.com/tkrotoff/jquery-simplecolorpicker
4  *
5  * Copyright (C) 2012-2013 Tanguy Krotoff <tkrotoff@gmail.com>
6  *
7  * Licensed under the MIT license
8  */
9
10 (function($) {
11   'use strict';
12
13   /**
14    * Constructor.
15    */
16   var SimpleColorPicker = function(select, options) {
17     this.init('simplecolorpicker', select, options);
18   };
19
20   /**
21    * SimpleColorPicker class.
22    */
23   SimpleColorPicker.prototype = {
24     constructor: SimpleColorPicker,
25
26     init: function(type, select, options) {
27       var self = this;
28
29       self.type = type;
30
31       self.$select = $(select);
32       self.$select.hide();
33
34       self.options = $.extend({}, $.fn.simplecolorpicker.defaults, options);
35
36       self.$colorList = null;
37
38       if (self.options.picker === true) {
39         var selectText = self.$select.find('> option:selected').text();
40         self.$icon = $('<span class="simplecolorpicker icon"'
41                      + ' title="' + selectText + '"'
42                      + ' style="background-color: ' + self.$select.val() + ';"'
43                      + ' role="button" tabindex="0">'
44                      + '</span>').insertAfter(self.$select);
45         self.$icon.on('click.' + self.type, $.proxy(self.showPicker, self));
46
47         self.$picker = $('<span class="simplecolorpicker picker ' + self.options.theme + '"></span>').appendTo(document.body);
48         self.$colorList = self.$picker;
49
50         // Hide picker when clicking outside
51         $(document).on('mousedown.' + self.type, $.proxy(self.hidePicker, self));
52         self.$picker.on('mousedown.' + self.type, $.proxy(self.mousedown, self));
53       } else {
54         self.$inline = $('<span class="simplecolorpicker inline ' + self.options.theme + '"></span>').insertAfter(self.$select);
55         self.$colorList = self.$inline;
56       }
57
58       // Build the list of colors
59       // <span class="color selected" title="Green" style="background-color: #7bd148;" role="button"></span>
60       self.$select.find('> option').each(function() {
61         var $option = $(this);
62         var color = $option.val();
63
64         var isSelected = $option.is(':selected');
65         var isDisabled = $option.is(':disabled');
66
67         var selected = '';
68         if (isSelected === true) {
69           selected = ' data-selected';
70         }
71
72         var disabled = '';
73         if (isDisabled === true) {
74           disabled = ' data-disabled';
75         }
76
77         var title = '';
78         if (isDisabled === false) {
79           title = ' title="' + $option.text() + '"';
80         }
81
82         var role = '';
83         if (isDisabled === false) {
84           role = ' role="button" tabindex="0"';
85         }
86
87         var $colorSpan = $('<span class="color"'
88                          + title
89                          + ' style="background-color: ' + color + ';"'
90                          + ' data-color="' + color + '"'
91                          + selected
92                          + disabled
93                          + role + '>'
94                          + '</span>');
95
96         self.$colorList.append($colorSpan);
97         $colorSpan.on('click.' + self.type, $.proxy(self.colorSpanClicked, self));
98
99         var $next = $option.next();
100         if ($next.is('optgroup') === true) {
101           // Vertical break, like hr
102           self.$colorList.append('<span class="vr"></span>');
103         }
104       });
105     },
106
107     /**
108      * Changes the selected color.
109      *
110      * @param color the hexadecimal color to select, ex: '#fbd75b'
111      */
112     selectColor: function(color) {
113       var self = this;
114
115       var $colorSpan = self.$colorList.find('> span.color').filter(function() {
116         return $(this).data('color').toLowerCase() === color.toLowerCase();
117       });
118
119       if ($colorSpan.length > 0) {
120         self.selectColorSpan($colorSpan);
121       } else {
122         console.error("The given color '" + color + "' could not be found");
123       }
124     },
125
126     showPicker: function() {
127       var pos = this.$icon.offset();
128       this.$picker.css({
129         // Remove some pixels to align the picker icon with the icons inside the dropdown
130         left: pos.left - 6,
131         top: pos.top + this.$icon.outerHeight()
132       });
133
134       this.$picker.show(this.options.pickerDelay);
135     },
136
137     hidePicker: function() {
138       this.$picker.hide(this.options.pickerDelay);
139     },
140
141     /**
142      * Selects the given span inside $colorList.
143      *
144      * The given span becomes the selected one.
145      * It also changes the HTML select value, this will emit the 'change' event.
146      */
147     selectColorSpan: function($colorSpan) {
148       var color = $colorSpan.data('color');
149       var title = $colorSpan.prop('title');
150
151       // Mark this span as the selected one
152       $colorSpan.siblings().removeAttr('data-selected');
153       $colorSpan.attr('data-selected', '');
154
155       if (this.options.picker === true) {
156         this.$icon.css('background-color', color);
157         this.$icon.prop('title', title);
158         this.hidePicker();
159       }
160
161       // Change HTML select value
162       this.$select.val(color);
163     },
164
165     /**
166      * The user clicked on a color inside $colorList.
167      */
168     colorSpanClicked: function(e) {
169       // When a color is clicked, make it the new selected one (unless disabled)
170       if ($(e.target).is('[data-disabled]') === false) {
171         this.selectColorSpan($(e.target));
172         this.$select.trigger('change');
173       }
174     },
175
176     /**
177      * Prevents the mousedown event from "eating" the click event.
178      */
179     mousedown: function(e) {
180       e.stopPropagation();
181       e.preventDefault();
182     },
183
184     destroy: function() {
185       if (this.options.picker === true) {
186         this.$icon.off('.' + this.type);
187         this.$icon.remove();
188         $(document).off('.' + this.type);
189       }
190
191       this.$colorList.off('.' + this.type);
192       this.$colorList.remove();
193
194       this.$select.removeData(this.type);
195       this.$select.show();
196     }
197   };
198
199   /**
200    * Plugin definition.
201    * How to use: $('#id').simplecolorpicker()
202    */
203   $.fn.simplecolorpicker = function(option) {
204     var args = $.makeArray(arguments);
205     args.shift();
206
207     // For HTML element passed to the plugin
208     return this.each(function() {
209       var $this = $(this),
210         data = $this.data('simplecolorpicker'),
211         options = typeof option === 'object' && option;
212       if (data === undefined) {
213         $this.data('simplecolorpicker', (data = new SimpleColorPicker(this, options)));
214       }
215       if (typeof option === 'string') {
216         data[option].apply(data, args);
217       }
218     });
219   };
220
221   /**
222    * Default options.
223    */
224   $.fn.simplecolorpicker.defaults = {
225     // No theme by default
226     theme: '',
227
228     // Show the picker or make it inline
229     picker: false,
230
231     // Animation delay in milliseconds
232     pickerDelay: 0
233   };
234
235 })(jQuery);