]>
Commit | Line | Data |
---|---|---|
31f18b77 FG |
1 | /*! |
2 | * Bootstrap Colorpicker | |
3 | * http://mjolnic.github.io/bootstrap-colorpicker/ | |
4 | * | |
5 | * Originally written by (c) 2012 Stefan Petre | |
6 | * Licensed under the Apache License v2.0 | |
7 | * http://www.apache.org/licenses/LICENSE-2.0.txt | |
8 | * | |
9 | * @todo Update DOCS | |
10 | */ | |
11 | ||
12 | (function(factory) { | |
13 | "use strict"; | |
14 | if (typeof exports === 'object') { | |
15 | module.exports = factory(window.jQuery); | |
16 | } else if (typeof define === 'function' && define.amd) { | |
17 | define(['jquery'], factory); | |
18 | } else if (window.jQuery && !window.jQuery.fn.colorpicker) { | |
19 | factory(window.jQuery); | |
20 | } | |
21 | } | |
22 | (function($) { | |
23 | 'use strict'; | |
24 | ||
25 | // Color object | |
26 | var Color = function(val, customColors) { | |
27 | this.value = { | |
28 | h: 0, | |
29 | s: 0, | |
30 | b: 0, | |
31 | a: 1 | |
32 | }; | |
33 | this.origFormat = null; // original string format | |
34 | if (customColors) { | |
35 | $.extend(this.colors, customColors); | |
36 | } | |
37 | if (val) { | |
38 | if (val.toLowerCase !== undefined) { | |
39 | // cast to string | |
40 | val = val + ''; | |
41 | this.setColor(val); | |
42 | } else if (val.h !== undefined) { | |
43 | this.value = val; | |
44 | } | |
45 | } | |
46 | }; | |
47 | ||
48 | Color.prototype = { | |
49 | constructor: Color, | |
50 | // 140 predefined colors from the HTML Colors spec | |
51 | colors: { | |
52 | "aliceblue": "#f0f8ff", | |
53 | "antiquewhite": "#faebd7", | |
54 | "aqua": "#00ffff", | |
55 | "aquamarine": "#7fffd4", | |
56 | "azure": "#f0ffff", | |
57 | "beige": "#f5f5dc", | |
58 | "bisque": "#ffe4c4", | |
59 | "black": "#000000", | |
60 | "blanchedalmond": "#ffebcd", | |
61 | "blue": "#0000ff", | |
62 | "blueviolet": "#8a2be2", | |
63 | "brown": "#a52a2a", | |
64 | "burlywood": "#deb887", | |
65 | "cadetblue": "#5f9ea0", | |
66 | "chartreuse": "#7fff00", | |
67 | "chocolate": "#d2691e", | |
68 | "coral": "#ff7f50", | |
69 | "cornflowerblue": "#6495ed", | |
70 | "cornsilk": "#fff8dc", | |
71 | "crimson": "#dc143c", | |
72 | "cyan": "#00ffff", | |
73 | "darkblue": "#00008b", | |
74 | "darkcyan": "#008b8b", | |
75 | "darkgoldenrod": "#b8860b", | |
76 | "darkgray": "#a9a9a9", | |
77 | "darkgreen": "#006400", | |
78 | "darkkhaki": "#bdb76b", | |
79 | "darkmagenta": "#8b008b", | |
80 | "darkolivegreen": "#556b2f", | |
81 | "darkorange": "#ff8c00", | |
82 | "darkorchid": "#9932cc", | |
83 | "darkred": "#8b0000", | |
84 | "darksalmon": "#e9967a", | |
85 | "darkseagreen": "#8fbc8f", | |
86 | "darkslateblue": "#483d8b", | |
87 | "darkslategray": "#2f4f4f", | |
88 | "darkturquoise": "#00ced1", | |
89 | "darkviolet": "#9400d3", | |
90 | "deeppink": "#ff1493", | |
91 | "deepskyblue": "#00bfff", | |
92 | "dimgray": "#696969", | |
93 | "dodgerblue": "#1e90ff", | |
94 | "firebrick": "#b22222", | |
95 | "floralwhite": "#fffaf0", | |
96 | "forestgreen": "#228b22", | |
97 | "fuchsia": "#ff00ff", | |
98 | "gainsboro": "#dcdcdc", | |
99 | "ghostwhite": "#f8f8ff", | |
100 | "gold": "#ffd700", | |
101 | "goldenrod": "#daa520", | |
102 | "gray": "#808080", | |
103 | "green": "#008000", | |
104 | "greenyellow": "#adff2f", | |
105 | "honeydew": "#f0fff0", | |
106 | "hotpink": "#ff69b4", | |
107 | "indianred": "#cd5c5c", | |
108 | "indigo": "#4b0082", | |
109 | "ivory": "#fffff0", | |
110 | "khaki": "#f0e68c", | |
111 | "lavender": "#e6e6fa", | |
112 | "lavenderblush": "#fff0f5", | |
113 | "lawngreen": "#7cfc00", | |
114 | "lemonchiffon": "#fffacd", | |
115 | "lightblue": "#add8e6", | |
116 | "lightcoral": "#f08080", | |
117 | "lightcyan": "#e0ffff", | |
118 | "lightgoldenrodyellow": "#fafad2", | |
119 | "lightgrey": "#d3d3d3", | |
120 | "lightgreen": "#90ee90", | |
121 | "lightpink": "#ffb6c1", | |
122 | "lightsalmon": "#ffa07a", | |
123 | "lightseagreen": "#20b2aa", | |
124 | "lightskyblue": "#87cefa", | |
125 | "lightslategray": "#778899", | |
126 | "lightsteelblue": "#b0c4de", | |
127 | "lightyellow": "#ffffe0", | |
128 | "lime": "#00ff00", | |
129 | "limegreen": "#32cd32", | |
130 | "linen": "#faf0e6", | |
131 | "magenta": "#ff00ff", | |
132 | "maroon": "#800000", | |
133 | "mediumaquamarine": "#66cdaa", | |
134 | "mediumblue": "#0000cd", | |
135 | "mediumorchid": "#ba55d3", | |
136 | "mediumpurple": "#9370d8", | |
137 | "mediumseagreen": "#3cb371", | |
138 | "mediumslateblue": "#7b68ee", | |
139 | "mediumspringgreen": "#00fa9a", | |
140 | "mediumturquoise": "#48d1cc", | |
141 | "mediumvioletred": "#c71585", | |
142 | "midnightblue": "#191970", | |
143 | "mintcream": "#f5fffa", | |
144 | "mistyrose": "#ffe4e1", | |
145 | "moccasin": "#ffe4b5", | |
146 | "navajowhite": "#ffdead", | |
147 | "navy": "#000080", | |
148 | "oldlace": "#fdf5e6", | |
149 | "olive": "#808000", | |
150 | "olivedrab": "#6b8e23", | |
151 | "orange": "#ffa500", | |
152 | "orangered": "#ff4500", | |
153 | "orchid": "#da70d6", | |
154 | "palegoldenrod": "#eee8aa", | |
155 | "palegreen": "#98fb98", | |
156 | "paleturquoise": "#afeeee", | |
157 | "palevioletred": "#d87093", | |
158 | "papayawhip": "#ffefd5", | |
159 | "peachpuff": "#ffdab9", | |
160 | "peru": "#cd853f", | |
161 | "pink": "#ffc0cb", | |
162 | "plum": "#dda0dd", | |
163 | "powderblue": "#b0e0e6", | |
164 | "purple": "#800080", | |
165 | "red": "#ff0000", | |
166 | "rosybrown": "#bc8f8f", | |
167 | "royalblue": "#4169e1", | |
168 | "saddlebrown": "#8b4513", | |
169 | "salmon": "#fa8072", | |
170 | "sandybrown": "#f4a460", | |
171 | "seagreen": "#2e8b57", | |
172 | "seashell": "#fff5ee", | |
173 | "sienna": "#a0522d", | |
174 | "silver": "#c0c0c0", | |
175 | "skyblue": "#87ceeb", | |
176 | "slateblue": "#6a5acd", | |
177 | "slategray": "#708090", | |
178 | "snow": "#fffafa", | |
179 | "springgreen": "#00ff7f", | |
180 | "steelblue": "#4682b4", | |
181 | "tan": "#d2b48c", | |
182 | "teal": "#008080", | |
183 | "thistle": "#d8bfd8", | |
184 | "tomato": "#ff6347", | |
185 | "turquoise": "#40e0d0", | |
186 | "violet": "#ee82ee", | |
187 | "wheat": "#f5deb3", | |
188 | "white": "#ffffff", | |
189 | "whitesmoke": "#f5f5f5", | |
190 | "yellow": "#ffff00", | |
191 | "yellowgreen": "#9acd32", | |
192 | "transparent": "transparent" | |
193 | }, | |
194 | _sanitizeNumber: function(val) { | |
195 | if (typeof val === 'number') { | |
196 | return val; | |
197 | } | |
198 | if (isNaN(val) || (val === null) || (val === '') || (val === undefined)) { | |
199 | return 1; | |
200 | } | |
201 | if (val.toLowerCase !== undefined) { | |
202 | return parseFloat(val); | |
203 | } | |
204 | return 1; | |
205 | }, | |
206 | isTransparent: function(strVal) { | |
207 | if (!strVal) { | |
208 | return false; | |
209 | } | |
210 | strVal = strVal.toLowerCase().trim(); | |
211 | return (strVal === 'transparent') || (strVal.match(/#?00000000/)) || (strVal.match(/(rgba|hsla)\(0,0,0,0?\.?0\)/)); | |
212 | }, | |
213 | rgbaIsTransparent: function(rgba) { | |
214 | return ((rgba.r === 0) && (rgba.g === 0) && (rgba.b === 0) && (rgba.a === 0)); | |
215 | }, | |
216 | //parse a string to HSB | |
217 | setColor: function(strVal) { | |
218 | strVal = strVal.toLowerCase().trim(); | |
219 | if (strVal) { | |
220 | if (this.isTransparent(strVal)) { | |
221 | this.value = { | |
222 | h: 0, | |
223 | s: 0, | |
224 | b: 0, | |
225 | a: 0 | |
226 | }; | |
227 | } else { | |
228 | this.value = this.stringToHSB(strVal) || { | |
229 | h: 0, | |
230 | s: 0, | |
231 | b: 0, | |
232 | a: 1 | |
233 | }; // if parser fails, defaults to black | |
234 | } | |
235 | } | |
236 | }, | |
237 | stringToHSB: function(strVal) { | |
238 | strVal = strVal.toLowerCase(); | |
239 | var alias; | |
240 | if (typeof this.colors[strVal] !== 'undefined') { | |
241 | strVal = this.colors[strVal]; | |
242 | alias = 'alias'; | |
243 | } | |
244 | var that = this, | |
245 | result = false; | |
246 | $.each(this.stringParsers, function(i, parser) { | |
247 | var match = parser.re.exec(strVal), | |
248 | values = match && parser.parse.apply(that, [match]), | |
249 | format = alias || parser.format || 'rgba'; | |
250 | if (values) { | |
251 | if (format.match(/hsla?/)) { | |
252 | result = that.RGBtoHSB.apply(that, that.HSLtoRGB.apply(that, values)); | |
253 | } else { | |
254 | result = that.RGBtoHSB.apply(that, values); | |
255 | } | |
256 | that.origFormat = format; | |
257 | return false; | |
258 | } | |
259 | return true; | |
260 | }); | |
261 | return result; | |
262 | }, | |
263 | setHue: function(h) { | |
264 | this.value.h = 1 - h; | |
265 | }, | |
266 | setSaturation: function(s) { | |
267 | this.value.s = s; | |
268 | }, | |
269 | setBrightness: function(b) { | |
270 | this.value.b = 1 - b; | |
271 | }, | |
272 | setAlpha: function(a) { | |
273 | this.value.a = parseInt((1 - a) * 100, 10) / 100; | |
274 | }, | |
275 | toRGB: function(h, s, b, a) { | |
276 | if (!h) { | |
277 | h = this.value.h; | |
278 | s = this.value.s; | |
279 | b = this.value.b; | |
280 | } | |
281 | h *= 360; | |
282 | var R, G, B, X, C; | |
283 | h = (h % 360) / 60; | |
284 | C = b * s; | |
285 | X = C * (1 - Math.abs(h % 2 - 1)); | |
286 | R = G = B = b - C; | |
287 | ||
288 | h = ~~h; | |
289 | R += [C, X, 0, 0, X, C][h]; | |
290 | G += [X, C, C, X, 0, 0][h]; | |
291 | B += [0, 0, X, C, C, X][h]; | |
292 | return { | |
293 | r: Math.round(R * 255), | |
294 | g: Math.round(G * 255), | |
295 | b: Math.round(B * 255), | |
296 | a: a || this.value.a | |
297 | }; | |
298 | }, | |
299 | toHex: function(h, s, b, a) { | |
300 | var rgb = this.toRGB(h, s, b, a); | |
301 | if (this.rgbaIsTransparent(rgb)) { | |
302 | return 'transparent'; | |
303 | } | |
304 | return '#' + ((1 << 24) | (parseInt(rgb.r) << 16) | (parseInt(rgb.g) << 8) | parseInt(rgb.b)).toString(16).substr(1); | |
305 | }, | |
306 | toHSL: function(h, s, b, a) { | |
307 | h = h || this.value.h; | |
308 | s = s || this.value.s; | |
309 | b = b || this.value.b; | |
310 | a = a || this.value.a; | |
311 | ||
312 | var H = h, | |
313 | L = (2 - s) * b, | |
314 | S = s * b; | |
315 | if (L > 0 && L <= 1) { | |
316 | S /= L; | |
317 | } else { | |
318 | S /= 2 - L; | |
319 | } | |
320 | L /= 2; | |
321 | if (S > 1) { | |
322 | S = 1; | |
323 | } | |
324 | return { | |
325 | h: isNaN(H) ? 0 : H, | |
326 | s: isNaN(S) ? 0 : S, | |
327 | l: isNaN(L) ? 0 : L, | |
328 | a: isNaN(a) ? 0 : a | |
329 | }; | |
330 | }, | |
331 | toAlias: function(r, g, b, a) { | |
332 | var rgb = this.toHex(r, g, b, a); | |
333 | for (var alias in this.colors) { | |
334 | if (this.colors[alias] === rgb) { | |
335 | return alias; | |
336 | } | |
337 | } | |
338 | return false; | |
339 | }, | |
340 | RGBtoHSB: function(r, g, b, a) { | |
341 | r /= 255; | |
342 | g /= 255; | |
343 | b /= 255; | |
344 | ||
345 | var H, S, V, C; | |
346 | V = Math.max(r, g, b); | |
347 | C = V - Math.min(r, g, b); | |
348 | H = (C === 0 ? null : | |
349 | V === r ? (g - b) / C : | |
350 | V === g ? (b - r) / C + 2 : | |
351 | (r - g) / C + 4 | |
352 | ); | |
353 | H = ((H + 360) % 6) * 60 / 360; | |
354 | S = C === 0 ? 0 : C / V; | |
355 | return { | |
356 | h: this._sanitizeNumber(H), | |
357 | s: S, | |
358 | b: V, | |
359 | a: this._sanitizeNumber(a) | |
360 | }; | |
361 | }, | |
362 | HueToRGB: function(p, q, h) { | |
363 | if (h < 0) { | |
364 | h += 1; | |
365 | } else if (h > 1) { | |
366 | h -= 1; | |
367 | } | |
368 | if ((h * 6) < 1) { | |
369 | return p + (q - p) * h * 6; | |
370 | } else if ((h * 2) < 1) { | |
371 | return q; | |
372 | } else if ((h * 3) < 2) { | |
373 | return p + (q - p) * ((2 / 3) - h) * 6; | |
374 | } else { | |
375 | return p; | |
376 | } | |
377 | }, | |
378 | HSLtoRGB: function(h, s, l, a) { | |
379 | if (s < 0) { | |
380 | s = 0; | |
381 | } | |
382 | var q; | |
383 | if (l <= 0.5) { | |
384 | q = l * (1 + s); | |
385 | } else { | |
386 | q = l + s - (l * s); | |
387 | } | |
388 | ||
389 | var p = 2 * l - q; | |
390 | ||
391 | var tr = h + (1 / 3); | |
392 | var tg = h; | |
393 | var tb = h - (1 / 3); | |
394 | ||
395 | var r = Math.round(this.HueToRGB(p, q, tr) * 255); | |
396 | var g = Math.round(this.HueToRGB(p, q, tg) * 255); | |
397 | var b = Math.round(this.HueToRGB(p, q, tb) * 255); | |
398 | return [r, g, b, this._sanitizeNumber(a)]; | |
399 | }, | |
400 | toString: function(format) { | |
401 | format = format || 'rgba'; | |
402 | var c = false; | |
403 | switch (format) { | |
404 | case 'rgb': | |
405 | { | |
406 | c = this.toRGB(); | |
407 | if (this.rgbaIsTransparent(c)) { | |
408 | return 'transparent'; | |
409 | } | |
410 | return 'rgb(' + c.r + ',' + c.g + ',' + c.b + ')'; | |
411 | } | |
412 | break; | |
413 | case 'rgba': | |
414 | { | |
415 | c = this.toRGB(); | |
416 | return 'rgba(' + c.r + ',' + c.g + ',' + c.b + ',' + c.a + ')'; | |
417 | } | |
418 | break; | |
419 | case 'hsl': | |
420 | { | |
421 | c = this.toHSL(); | |
422 | return 'hsl(' + Math.round(c.h * 360) + ',' + Math.round(c.s * 100) + '%,' + Math.round(c.l * 100) + '%)'; | |
423 | } | |
424 | break; | |
425 | case 'hsla': | |
426 | { | |
427 | c = this.toHSL(); | |
428 | return 'hsla(' + Math.round(c.h * 360) + ',' + Math.round(c.s * 100) + '%,' + Math.round(c.l * 100) + '%,' + c.a + ')'; | |
429 | } | |
430 | break; | |
431 | case 'hex': | |
432 | { | |
433 | return this.toHex(); | |
434 | } | |
435 | break; | |
436 | case 'alias': | |
437 | return this.toAlias() || this.toHex(); | |
438 | default: | |
439 | { | |
440 | return c; | |
441 | } | |
442 | break; | |
443 | } | |
444 | }, | |
445 | // a set of RE's that can match strings and generate color tuples. | |
446 | // from John Resig color plugin | |
447 | // https://github.com/jquery/jquery-color/ | |
448 | stringParsers: [{ | |
449 | re: /rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*?\)/, | |
450 | format: 'rgb', | |
451 | parse: function(execResult) { | |
452 | return [ | |
453 | execResult[1], | |
454 | execResult[2], | |
455 | execResult[3], | |
456 | 1 | |
457 | ]; | |
458 | } | |
459 | }, { | |
460 | re: /rgb\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*?\)/, | |
461 | format: 'rgb', | |
462 | parse: function(execResult) { | |
463 | return [ | |
464 | 2.55 * execResult[1], | |
465 | 2.55 * execResult[2], | |
466 | 2.55 * execResult[3], | |
467 | 1 | |
468 | ]; | |
469 | } | |
470 | }, { | |
471 | re: /rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, | |
472 | format: 'rgba', | |
473 | parse: function(execResult) { | |
474 | return [ | |
475 | execResult[1], | |
476 | execResult[2], | |
477 | execResult[3], | |
478 | execResult[4] | |
479 | ]; | |
480 | } | |
481 | }, { | |
482 | re: /rgba\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, | |
483 | format: 'rgba', | |
484 | parse: function(execResult) { | |
485 | return [ | |
486 | 2.55 * execResult[1], | |
487 | 2.55 * execResult[2], | |
488 | 2.55 * execResult[3], | |
489 | execResult[4] | |
490 | ]; | |
491 | } | |
492 | }, { | |
493 | re: /hsl\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*?\)/, | |
494 | format: 'hsl', | |
495 | parse: function(execResult) { | |
496 | return [ | |
497 | execResult[1] / 360, | |
498 | execResult[2] / 100, | |
499 | execResult[3] / 100, | |
500 | execResult[4] | |
501 | ]; | |
502 | } | |
503 | }, { | |
504 | re: /hsla\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, | |
505 | format: 'hsla', | |
506 | parse: function(execResult) { | |
507 | return [ | |
508 | execResult[1] / 360, | |
509 | execResult[2] / 100, | |
510 | execResult[3] / 100, | |
511 | execResult[4] | |
512 | ]; | |
513 | } | |
514 | }, { | |
515 | re: /#?([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/, | |
516 | format: 'hex', | |
517 | parse: function(execResult) { | |
518 | return [ | |
519 | parseInt(execResult[1], 16), | |
520 | parseInt(execResult[2], 16), | |
521 | parseInt(execResult[3], 16), | |
522 | 1 | |
523 | ]; | |
524 | } | |
525 | }, { | |
526 | re: /#?([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/, | |
527 | format: 'hex', | |
528 | parse: function(execResult) { | |
529 | return [ | |
530 | parseInt(execResult[1] + execResult[1], 16), | |
531 | parseInt(execResult[2] + execResult[2], 16), | |
532 | parseInt(execResult[3] + execResult[3], 16), | |
533 | 1 | |
534 | ]; | |
535 | } | |
536 | }], | |
537 | colorNameToHex: function(name) { | |
538 | if (typeof this.colors[name.toLowerCase()] !== 'undefined') { | |
539 | return this.colors[name.toLowerCase()]; | |
540 | } | |
541 | return false; | |
542 | } | |
543 | }; | |
544 | ||
545 | ||
546 | var defaults = { | |
547 | horizontal: false, // horizontal mode layout ? | |
548 | inline: false, //forces to show the colorpicker as an inline element | |
549 | color: false, //forces a color | |
550 | format: false, //forces a format | |
551 | input: 'input', // children input selector | |
552 | container: false, // container selector | |
553 | component: '.add-on, .input-group-addon', // children component selector | |
554 | sliders: { | |
555 | saturation: { | |
556 | maxLeft: 100, | |
557 | maxTop: 100, | |
558 | callLeft: 'setSaturation', | |
559 | callTop: 'setBrightness' | |
560 | }, | |
561 | hue: { | |
562 | maxLeft: 0, | |
563 | maxTop: 100, | |
564 | callLeft: false, | |
565 | callTop: 'setHue' | |
566 | }, | |
567 | alpha: { | |
568 | maxLeft: 0, | |
569 | maxTop: 100, | |
570 | callLeft: false, | |
571 | callTop: 'setAlpha' | |
572 | } | |
573 | }, | |
574 | slidersHorz: { | |
575 | saturation: { | |
576 | maxLeft: 100, | |
577 | maxTop: 100, | |
578 | callLeft: 'setSaturation', | |
579 | callTop: 'setBrightness' | |
580 | }, | |
581 | hue: { | |
582 | maxLeft: 100, | |
583 | maxTop: 0, | |
584 | callLeft: 'setHue', | |
585 | callTop: false | |
586 | }, | |
587 | alpha: { | |
588 | maxLeft: 100, | |
589 | maxTop: 0, | |
590 | callLeft: 'setAlpha', | |
591 | callTop: false | |
592 | } | |
593 | }, | |
594 | template: '<div class="colorpicker dropdown-menu">' + | |
595 | '<div class="colorpicker-saturation"><i><b></b></i></div>' + | |
596 | '<div class="colorpicker-hue"><i></i></div>' + | |
597 | '<div class="colorpicker-alpha"><i></i></div>' + | |
598 | '<div class="colorpicker-color"><div /></div>' + | |
599 | '<div class="colorpicker-selectors"></div>' + | |
600 | '</div>', | |
601 | align: 'right', | |
602 | customClass: null, | |
603 | colorSelectors: null | |
604 | }; | |
605 | ||
606 | var Colorpicker = function(element, options) { | |
607 | this.element = $(element).addClass('colorpicker-element'); | |
608 | this.options = $.extend(true, {}, defaults, this.element.data(), options); | |
609 | this.component = this.options.component; | |
610 | this.component = (this.component !== false) ? this.element.find(this.component) : false; | |
611 | if (this.component && (this.component.length === 0)) { | |
612 | this.component = false; | |
613 | } | |
614 | this.container = (this.options.container === true) ? this.element : this.options.container; | |
615 | this.container = (this.container !== false) ? $(this.container) : false; | |
616 | ||
617 | // Is the element an input? Should we search inside for any input? | |
618 | this.input = this.element.is('input') ? this.element : (this.options.input ? | |
619 | this.element.find(this.options.input) : false); | |
620 | if (this.input && (this.input.length === 0)) { | |
621 | this.input = false; | |
622 | } | |
623 | // Set HSB color | |
624 | this.color = new Color(this.options.color !== false ? this.options.color : this.getValue(), this.options.colorSelectors); | |
625 | this.format = this.options.format !== false ? this.options.format : this.color.origFormat; | |
626 | ||
627 | // Setup picker | |
628 | this.picker = $(this.options.template); | |
629 | if (this.options.customClass) { | |
630 | this.picker.addClass(this.options.customClass); | |
631 | } | |
632 | if (this.options.inline) { | |
633 | this.picker.addClass('colorpicker-inline colorpicker-visible'); | |
634 | } else { | |
635 | this.picker.addClass('colorpicker-hidden'); | |
636 | } | |
637 | if (this.options.horizontal) { | |
638 | this.picker.addClass('colorpicker-horizontal'); | |
639 | } | |
640 | if (this.format === 'rgba' || this.format === 'hsla' || this.options.format === false) { | |
641 | this.picker.addClass('colorpicker-with-alpha'); | |
642 | } | |
643 | if (this.options.align === 'right') { | |
644 | this.picker.addClass('colorpicker-right'); | |
645 | } | |
646 | if (this.options.colorSelectors) { | |
647 | var colorpicker = this; | |
648 | $.each(this.options.colorSelectors, function(name, color) { | |
649 | var $btn = $('<i />').css('background-color', color).data('class', name); | |
650 | $btn.click(function() { | |
651 | colorpicker.setValue($(this).css('background-color')); | |
652 | }); | |
653 | colorpicker.picker.find('.colorpicker-selectors').append($btn); | |
654 | }); | |
655 | this.picker.find('.colorpicker-selectors').show(); | |
656 | } | |
657 | this.picker.on('mousedown.colorpicker touchstart.colorpicker', $.proxy(this.mousedown, this)); | |
658 | this.picker.appendTo(this.container ? this.container : $('body')); | |
659 | ||
660 | // Bind events | |
661 | if (this.input !== false) { | |
662 | this.input.on({ | |
663 | 'keyup.colorpicker': $.proxy(this.keyup, this) | |
664 | }); | |
665 | this.input.on({ | |
666 | 'change.colorpicker': $.proxy(this.change, this) | |
667 | }); | |
668 | if (this.component === false) { | |
669 | this.element.on({ | |
670 | 'focus.colorpicker': $.proxy(this.show, this) | |
671 | }); | |
672 | } | |
673 | if (this.options.inline === false) { | |
674 | this.element.on({ | |
675 | 'focusout.colorpicker': $.proxy(this.hide, this) | |
676 | }); | |
677 | } | |
678 | } | |
679 | ||
680 | if (this.component !== false) { | |
681 | this.component.on({ | |
682 | 'click.colorpicker': $.proxy(this.show, this) | |
683 | }); | |
684 | } | |
685 | ||
686 | if ((this.input === false) && (this.component === false)) { | |
687 | this.element.on({ | |
688 | 'click.colorpicker': $.proxy(this.show, this) | |
689 | }); | |
690 | } | |
691 | ||
692 | // for HTML5 input[type='color'] | |
693 | if ((this.input !== false) && (this.component !== false) && (this.input.attr('type') === 'color')) { | |
694 | ||
695 | this.input.on({ | |
696 | 'click.colorpicker': $.proxy(this.show, this), | |
697 | 'focus.colorpicker': $.proxy(this.show, this) | |
698 | }); | |
699 | } | |
700 | this.update(); | |
701 | ||
702 | $($.proxy(function() { | |
703 | this.element.trigger('create'); | |
704 | }, this)); | |
705 | }; | |
706 | ||
707 | Colorpicker.Color = Color; | |
708 | ||
709 | Colorpicker.prototype = { | |
710 | constructor: Colorpicker, | |
711 | destroy: function() { | |
712 | this.picker.remove(); | |
713 | this.element.removeData('colorpicker').off('.colorpicker'); | |
714 | if (this.input !== false) { | |
715 | this.input.off('.colorpicker'); | |
716 | } | |
717 | if (this.component !== false) { | |
718 | this.component.off('.colorpicker'); | |
719 | } | |
720 | this.element.removeClass('colorpicker-element'); | |
721 | this.element.trigger({ | |
722 | type: 'destroy' | |
723 | }); | |
724 | }, | |
725 | reposition: function() { | |
726 | if (this.options.inline !== false || this.options.container) { | |
727 | return false; | |
728 | } | |
729 | var type = this.container && this.container[0] !== document.body ? 'position' : 'offset'; | |
730 | var element = this.component || this.element; | |
731 | var offset = element[type](); | |
732 | if (this.options.align === 'right') { | |
733 | offset.left -= this.picker.outerWidth() - element.outerWidth(); | |
734 | } | |
735 | this.picker.css({ | |
736 | top: offset.top + element.outerHeight(), | |
737 | left: offset.left | |
738 | }); | |
739 | }, | |
740 | show: function(e) { | |
741 | if (this.isDisabled()) { | |
742 | return false; | |
743 | } | |
744 | this.picker.addClass('colorpicker-visible').removeClass('colorpicker-hidden'); | |
745 | this.reposition(); | |
746 | $(window).on('resize.colorpicker', $.proxy(this.reposition, this)); | |
747 | if (e && (!this.hasInput() || this.input.attr('type') === 'color')) { | |
748 | if (e.stopPropagation && e.preventDefault) { | |
749 | e.stopPropagation(); | |
750 | e.preventDefault(); | |
751 | } | |
752 | } | |
753 | if (this.options.inline === false) { | |
754 | $(window.document).on({ | |
755 | 'mousedown.colorpicker': $.proxy(this.hide, this) | |
756 | }); | |
757 | } | |
758 | this.element.trigger({ | |
759 | type: 'showPicker', | |
760 | color: this.color | |
761 | }); | |
762 | }, | |
763 | hide: function() { | |
764 | this.picker.addClass('colorpicker-hidden').removeClass('colorpicker-visible'); | |
765 | $(window).off('resize.colorpicker', this.reposition); | |
766 | $(document).off({ | |
767 | 'mousedown.colorpicker': this.hide | |
768 | }); | |
769 | this.update(); | |
770 | this.element.trigger({ | |
771 | type: 'hidePicker', | |
772 | color: this.color | |
773 | }); | |
774 | }, | |
775 | updateData: function(val) { | |
776 | val = val || this.color.toString(this.format); | |
777 | this.element.data('color', val); | |
778 | return val; | |
779 | }, | |
780 | updateInput: function(val) { | |
781 | val = val || this.color.toString(this.format); | |
782 | if (this.input !== false) { | |
783 | if (this.options.colorSelectors) { | |
784 | var color = new Color(val, this.options.colorSelectors); | |
785 | var alias = color.toAlias(); | |
786 | if (typeof this.options.colorSelectors[alias] !== 'undefined') { | |
787 | val = alias; | |
788 | } | |
789 | } | |
790 | this.input.prop('value', val); | |
791 | } | |
792 | return val; | |
793 | }, | |
794 | updatePicker: function(val) { | |
795 | if (val !== undefined) { | |
796 | this.color = new Color(val, this.options.colorSelectors); | |
797 | } | |
798 | var sl = (this.options.horizontal === false) ? this.options.sliders : this.options.slidersHorz; | |
799 | var icns = this.picker.find('i'); | |
800 | if (icns.length === 0) { | |
801 | return; | |
802 | } | |
803 | if (this.options.horizontal === false) { | |
804 | sl = this.options.sliders; | |
805 | icns.eq(1).css('top', sl.hue.maxTop * (1 - this.color.value.h)).end() | |
806 | .eq(2).css('top', sl.alpha.maxTop * (1 - this.color.value.a)); | |
807 | } else { | |
808 | sl = this.options.slidersHorz; | |
809 | icns.eq(1).css('left', sl.hue.maxLeft * (1 - this.color.value.h)).end() | |
810 | .eq(2).css('left', sl.alpha.maxLeft * (1 - this.color.value.a)); | |
811 | } | |
812 | icns.eq(0).css({ | |
813 | 'top': sl.saturation.maxTop - this.color.value.b * sl.saturation.maxTop, | |
814 | 'left': this.color.value.s * sl.saturation.maxLeft | |
815 | }); | |
816 | this.picker.find('.colorpicker-saturation').css('backgroundColor', this.color.toHex(this.color.value.h, 1, 1, 1)); | |
817 | this.picker.find('.colorpicker-alpha').css('backgroundColor', this.color.toHex()); | |
818 | this.picker.find('.colorpicker-color, .colorpicker-color div').css('backgroundColor', this.color.toString(this.format)); | |
819 | return val; | |
820 | }, | |
821 | updateComponent: function(val) { | |
822 | val = val || this.color.toString(this.format); | |
823 | if (this.component !== false) { | |
824 | var icn = this.component.find('i').eq(0); | |
825 | if (icn.length > 0) { | |
826 | icn.css({ | |
827 | 'backgroundColor': val | |
828 | }); | |
829 | } else { | |
830 | this.component.css({ | |
831 | 'backgroundColor': val | |
832 | }); | |
833 | } | |
834 | } | |
835 | return val; | |
836 | }, | |
837 | update: function(force) { | |
838 | var val; | |
839 | if ((this.getValue(false) !== false) || (force === true)) { | |
840 | // Update input/data only if the current value is not empty | |
841 | val = this.updateComponent(); | |
842 | this.updateInput(val); | |
843 | this.updateData(val); | |
844 | this.updatePicker(); // only update picker if value is not empty | |
845 | } | |
846 | return val; | |
847 | ||
848 | }, | |
849 | setValue: function(val) { // set color manually | |
850 | this.color = new Color(val, this.options.colorSelectors); | |
851 | this.update(true); | |
852 | this.element.trigger({ | |
853 | type: 'changeColor', | |
854 | color: this.color, | |
855 | value: val | |
856 | }); | |
857 | }, | |
858 | getValue: function(defaultValue) { | |
859 | defaultValue = (defaultValue === undefined) ? '#000000' : defaultValue; | |
860 | var val; | |
861 | if (this.hasInput()) { | |
862 | val = this.input.val(); | |
863 | } else { | |
864 | val = this.element.data('color'); | |
865 | } | |
866 | if ((val === undefined) || (val === '') || (val === null)) { | |
867 | // if not defined or empty, return default | |
868 | val = defaultValue; | |
869 | } | |
870 | return val; | |
871 | }, | |
872 | hasInput: function() { | |
873 | return (this.input !== false); | |
874 | }, | |
875 | isDisabled: function() { | |
876 | if (this.hasInput()) { | |
877 | return (this.input.prop('disabled') === true); | |
878 | } | |
879 | return false; | |
880 | }, | |
881 | disable: function() { | |
882 | if (this.hasInput()) { | |
883 | this.input.prop('disabled', true); | |
884 | this.element.trigger({ | |
885 | type: 'disable', | |
886 | color: this.color, | |
887 | value: this.getValue() | |
888 | }); | |
889 | return true; | |
890 | } | |
891 | return false; | |
892 | }, | |
893 | enable: function() { | |
894 | if (this.hasInput()) { | |
895 | this.input.prop('disabled', false); | |
896 | this.element.trigger({ | |
897 | type: 'enable', | |
898 | color: this.color, | |
899 | value: this.getValue() | |
900 | }); | |
901 | return true; | |
902 | } | |
903 | return false; | |
904 | }, | |
905 | currentSlider: null, | |
906 | mousePointer: { | |
907 | left: 0, | |
908 | top: 0 | |
909 | }, | |
910 | mousedown: function(e) { | |
911 | if (!e.pageX && !e.pageY && e.originalEvent) { | |
912 | e.pageX = e.originalEvent.touches[0].pageX; | |
913 | e.pageY = e.originalEvent.touches[0].pageY; | |
914 | } | |
915 | e.stopPropagation(); | |
916 | e.preventDefault(); | |
917 | ||
918 | var target = $(e.target); | |
919 | ||
920 | //detect the slider and set the limits and callbacks | |
921 | var zone = target.closest('div'); | |
922 | var sl = this.options.horizontal ? this.options.slidersHorz : this.options.sliders; | |
923 | if (!zone.is('.colorpicker')) { | |
924 | if (zone.is('.colorpicker-saturation')) { | |
925 | this.currentSlider = $.extend({}, sl.saturation); | |
926 | } else if (zone.is('.colorpicker-hue')) { | |
927 | this.currentSlider = $.extend({}, sl.hue); | |
928 | } else if (zone.is('.colorpicker-alpha')) { | |
929 | this.currentSlider = $.extend({}, sl.alpha); | |
930 | } else { | |
931 | return false; | |
932 | } | |
933 | var offset = zone.offset(); | |
934 | //reference to guide's style | |
935 | this.currentSlider.guide = zone.find('i')[0].style; | |
936 | this.currentSlider.left = e.pageX - offset.left; | |
937 | this.currentSlider.top = e.pageY - offset.top; | |
938 | this.mousePointer = { | |
939 | left: e.pageX, | |
940 | top: e.pageY | |
941 | }; | |
942 | //trigger mousemove to move the guide to the current position | |
943 | $(document).on({ | |
944 | 'mousemove.colorpicker': $.proxy(this.mousemove, this), | |
945 | 'touchmove.colorpicker': $.proxy(this.mousemove, this), | |
946 | 'mouseup.colorpicker': $.proxy(this.mouseup, this), | |
947 | 'touchend.colorpicker': $.proxy(this.mouseup, this) | |
948 | }).trigger('mousemove'); | |
949 | } | |
950 | return false; | |
951 | }, | |
952 | mousemove: function(e) { | |
953 | if (!e.pageX && !e.pageY && e.originalEvent) { | |
954 | e.pageX = e.originalEvent.touches[0].pageX; | |
955 | e.pageY = e.originalEvent.touches[0].pageY; | |
956 | } | |
957 | e.stopPropagation(); | |
958 | e.preventDefault(); | |
959 | var left = Math.max( | |
960 | 0, | |
961 | Math.min( | |
962 | this.currentSlider.maxLeft, | |
963 | this.currentSlider.left + ((e.pageX || this.mousePointer.left) - this.mousePointer.left) | |
964 | ) | |
965 | ); | |
966 | var top = Math.max( | |
967 | 0, | |
968 | Math.min( | |
969 | this.currentSlider.maxTop, | |
970 | this.currentSlider.top + ((e.pageY || this.mousePointer.top) - this.mousePointer.top) | |
971 | ) | |
972 | ); | |
973 | this.currentSlider.guide.left = left + 'px'; | |
974 | this.currentSlider.guide.top = top + 'px'; | |
975 | if (this.currentSlider.callLeft) { | |
976 | this.color[this.currentSlider.callLeft].call(this.color, left / this.currentSlider.maxLeft); | |
977 | } | |
978 | if (this.currentSlider.callTop) { | |
979 | this.color[this.currentSlider.callTop].call(this.color, top / this.currentSlider.maxTop); | |
980 | } | |
981 | // Change format dynamically | |
982 | // Only occurs if user choose the dynamic format by | |
983 | // setting option format to false | |
984 | if (this.currentSlider.callTop === 'setAlpha' && this.options.format === false) { | |
985 | ||
986 | // Converting from hex / rgb to rgba | |
987 | if (this.color.value.a !== 1) { | |
988 | this.format = 'rgba'; | |
989 | this.color.origFormat = 'rgba'; | |
990 | } | |
991 | ||
992 | // Converting from rgba to hex | |
993 | else { | |
994 | this.format = 'hex'; | |
995 | this.color.origFormat = 'hex'; | |
996 | } | |
997 | } | |
998 | this.update(true); | |
999 | ||
1000 | this.element.trigger({ | |
1001 | type: 'changeColor', | |
1002 | color: this.color | |
1003 | }); | |
1004 | return false; | |
1005 | }, | |
1006 | mouseup: function(e) { | |
1007 | e.stopPropagation(); | |
1008 | e.preventDefault(); | |
1009 | $(document).off({ | |
1010 | 'mousemove.colorpicker': this.mousemove, | |
1011 | 'touchmove.colorpicker': this.mousemove, | |
1012 | 'mouseup.colorpicker': this.mouseup, | |
1013 | 'touchend.colorpicker': this.mouseup | |
1014 | }); | |
1015 | return false; | |
1016 | }, | |
1017 | change: function(e) { | |
1018 | this.keyup(e); | |
1019 | }, | |
1020 | keyup: function(e) { | |
1021 | if ((e.keyCode === 38)) { | |
1022 | if (this.color.value.a < 1) { | |
1023 | this.color.value.a = Math.round((this.color.value.a + 0.01) * 100) / 100; | |
1024 | } | |
1025 | this.update(true); | |
1026 | } else if ((e.keyCode === 40)) { | |
1027 | if (this.color.value.a > 0) { | |
1028 | this.color.value.a = Math.round((this.color.value.a - 0.01) * 100) / 100; | |
1029 | } | |
1030 | this.update(true); | |
1031 | } else { | |
1032 | this.color = new Color(this.input.val(), this.options.colorSelectors); | |
1033 | // Change format dynamically | |
1034 | // Only occurs if user choose the dynamic format by | |
1035 | // setting option format to false | |
1036 | if (this.color.origFormat && this.options.format === false) { | |
1037 | this.format = this.color.origFormat; | |
1038 | } | |
1039 | if (this.getValue(false) !== false) { | |
1040 | this.updateData(); | |
1041 | this.updateComponent(); | |
1042 | this.updatePicker(); | |
1043 | } | |
1044 | } | |
1045 | this.element.trigger({ | |
1046 | type: 'changeColor', | |
1047 | color: this.color, | |
1048 | value: this.input.val() | |
1049 | }); | |
1050 | } | |
1051 | }; | |
1052 | ||
1053 | $.colorpicker = Colorpicker; | |
1054 | ||
1055 | $.fn.colorpicker = function(option) { | |
1056 | var pickerArgs = arguments, | |
1057 | rv; | |
1058 | ||
1059 | var $returnValue = this.each(function() { | |
1060 | var $this = $(this), | |
1061 | inst = $this.data('colorpicker'), | |
1062 | options = ((typeof option === 'object') ? option : {}); | |
1063 | if ((!inst) && (typeof option !== 'string')) { | |
1064 | $this.data('colorpicker', new Colorpicker(this, options)); | |
1065 | } else { | |
1066 | if (typeof option === 'string') { | |
1067 | rv = inst[option].apply(inst, Array.prototype.slice.call(pickerArgs, 1)); | |
1068 | } | |
1069 | } | |
1070 | }); | |
1071 | if (option === 'getValue') { | |
1072 | return rv; | |
1073 | } | |
1074 | return $returnValue; | |
1075 | }; | |
1076 | ||
1077 | $.fn.colorpicker.constructor = Colorpicker; | |
1078 | ||
1079 | })); |