spectrum-rails 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Kevin Trotter
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Spectrum::Rails
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'spectrum-rails'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install spectrum-rails
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,8 @@
1
+ require "spectrum-rails/version"
2
+
3
+ module Spectrum
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Spectrum
2
+ module Rails
3
+ VERSION = "1.0.9"
4
+ end
5
+ end
@@ -0,0 +1,1748 @@
1
+ // Spectrum Colorpicker v1.0.9
2
+ // https://github.com/bgrins/spectrum
3
+ // Author: Brian Grinstead
4
+ // License: MIT
5
+
6
+ (function (window, $, undefined) {
7
+ var defaultOpts = {
8
+
9
+ // Events
10
+ beforeShow: noop,
11
+ move: noop,
12
+ change: noop,
13
+ show: noop,
14
+ hide: noop,
15
+
16
+ // Options
17
+ color: false,
18
+ flat: false,
19
+ showInput: false,
20
+ showButtons: true,
21
+ clickoutFiresChange: false,
22
+ showInitial: false,
23
+ showPalette: false,
24
+ showPaletteOnly: false,
25
+ showSelectionPalette: true,
26
+ localStorageKey: false,
27
+ maxSelectionSize: 7,
28
+ cancelText: "cancel",
29
+ chooseText: "choose",
30
+ preferredFormat: false,
31
+ className: "",
32
+ showAlpha: false,
33
+ theme: "sp-light",
34
+ palette: ['fff', '000'],
35
+ selectionPalette: [],
36
+ disabled: false
37
+ },
38
+ spectrums = [],
39
+ IE = !!/msie/i.exec( window.navigator.userAgent ),
40
+ rgbaSupport = (function() {
41
+ function contains( str, substr ) {
42
+ return !!~('' + str).indexOf(substr);
43
+ }
44
+
45
+ var elem = document.createElement('div');
46
+ var style = elem.style;
47
+ style.cssText = 'background-color:rgba(0,0,0,.5)';
48
+ return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
49
+ })(),
50
+ replaceInput = [
51
+ "<div class='sp-replacer'>",
52
+ "<div class='sp-preview'><div class='sp-preview-inner'></div></div>",
53
+ "<div class='sp-dd'>&#9660;</div>",
54
+ "</div>"
55
+ ].join(''),
56
+ markup = (function () {
57
+
58
+ // IE does not support gradients with multiple stops, so we need to simulate
59
+ // that for the rainbow slider with 8 divs that each have a single gradient
60
+ var gradientFix = "";
61
+ if (IE) {
62
+ for (var i = 1; i <= 6; i++) {
63
+ gradientFix += "<div class='sp-" + i + "'></div>";
64
+ }
65
+ }
66
+
67
+ return [
68
+ "<div class='sp-container'>",
69
+ "<div class='sp-palette-container'>",
70
+ "<div class='sp-palette sp-thumb sp-cf'></div>",
71
+ "</div>",
72
+ "<div class='sp-picker-container'>",
73
+ "<div class='sp-top sp-cf'>",
74
+ "<div class='sp-fill'></div>",
75
+ "<div class='sp-top-inner'>",
76
+ "<div class='sp-color'>",
77
+ "<div class='sp-sat'>",
78
+ "<div class='sp-val'>",
79
+ "<div class='sp-dragger'></div>",
80
+ "</div>",
81
+ "</div>",
82
+ "</div>",
83
+ "<div class='sp-hue'>",
84
+ "<div class='sp-slider'></div>",
85
+ gradientFix,
86
+ "</div>",
87
+ "</div>",
88
+ "<div class='sp-alpha'><div class='sp-alpha-inner'><div class='sp-alpha-handle'></div></div></div>",
89
+ "</div>",
90
+ "<div class='sp-input-container sp-cf'>",
91
+ "<input class='sp-input' type='text' spellcheck='false' />",
92
+ "</div>",
93
+ "<div class='sp-initial sp-thumb sp-cf'></div>",
94
+ "<div class='sp-button-container sp-cf'>",
95
+ "<a class='sp-cancel' href='#'></a>",
96
+ "<button class='sp-choose'></button>",
97
+ "</div>",
98
+ "</div>",
99
+ "</div>"
100
+ ].join("");
101
+ })();
102
+
103
+ function paletteTemplate (p, color, className) {
104
+ var html = [];
105
+ for (var i = 0; i < p.length; i++) {
106
+ var tiny = tinycolor(p[i]);
107
+ var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light";
108
+ c += (tinycolor.equals(color, p[i])) ? " sp-thumb-active" : "";
109
+
110
+ var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter();
111
+ html.push('<span title="' + tiny.toRgbString() + '" data-color="' + tiny.toRgbString() + '" class="' + c + '"><span class="sp-thumb-inner" style="' + swatchStyle + ';" /></span>');
112
+ }
113
+ return "<div class='sp-cf " + className + "'>" + html.join('') + "</div>";
114
+ }
115
+
116
+ function hideAll() {
117
+ for (var i = 0; i < spectrums.length; i++) {
118
+ if (spectrums[i]) {
119
+ spectrums[i].hide();
120
+ }
121
+ }
122
+ }
123
+
124
+ function instanceOptions(o, callbackContext) {
125
+ var opts = $.extend({}, defaultOpts, o);
126
+ opts.callbacks = {
127
+ 'move': bind(opts.move, callbackContext),
128
+ 'change': bind(opts.change, callbackContext),
129
+ 'show': bind(opts.show, callbackContext),
130
+ 'hide': bind(opts.hide, callbackContext),
131
+ 'beforeShow': bind(opts.beforeShow, callbackContext)
132
+ };
133
+
134
+ return opts;
135
+ }
136
+
137
+ function spectrum(element, o) {
138
+
139
+ var opts = instanceOptions(o, element),
140
+ flat = opts.flat,
141
+ showSelectionPalette = opts.showSelectionPalette,
142
+ localStorageKey = opts.localStorageKey,
143
+ theme = opts.theme,
144
+ callbacks = opts.callbacks,
145
+ resize = throttle(reflow, 10),
146
+ visible = false,
147
+ dragWidth = 0,
148
+ dragHeight = 0,
149
+ dragHelperHeight = 0,
150
+ slideHeight = 0,
151
+ slideWidth = 0,
152
+ alphaWidth = 0,
153
+ alphaSlideHelperWidth = 0,
154
+ slideHelperHeight = 0,
155
+ currentHue = 0,
156
+ currentSaturation = 0,
157
+ currentValue = 0,
158
+ currentAlpha = 1,
159
+ palette = opts.palette.slice(0),
160
+ paletteArray = $.isArray(palette[0]) ? palette : [palette],
161
+ selectionPalette = opts.selectionPalette.slice(0),
162
+ draggingClass = "sp-dragging";
163
+
164
+ var doc = element.ownerDocument,
165
+ body = doc.body,
166
+ boundElement = $(element),
167
+ disabled = false,
168
+ container = $(markup, doc).addClass(theme),
169
+ dragger = container.find(".sp-color"),
170
+ dragHelper = container.find(".sp-dragger"),
171
+ slider = container.find(".sp-hue"),
172
+ slideHelper = container.find(".sp-slider"),
173
+ alphaSliderInner = container.find(".sp-alpha-inner"),
174
+ alphaSlider = container.find(".sp-alpha"),
175
+ alphaSlideHelper = container.find(".sp-alpha-handle"),
176
+ textInput = container.find(".sp-input"),
177
+ paletteContainer = container.find(".sp-palette"),
178
+ initialColorContainer = container.find(".sp-initial"),
179
+ cancelButton = container.find(".sp-cancel"),
180
+ chooseButton = container.find(".sp-choose"),
181
+ isInput = boundElement.is("input"),
182
+ shouldReplace = isInput && !flat,
183
+ replacer = (shouldReplace) ? $(replaceInput).addClass(theme) : $([]),
184
+ offsetElement = (shouldReplace) ? replacer : boundElement,
185
+ previewElement = replacer.find(".sp-preview-inner"),
186
+ initialColor = opts.color || (isInput && boundElement.val()),
187
+ colorOnShow = false,
188
+ preferredFormat = opts.preferredFormat,
189
+ currentPreferredFormat = preferredFormat,
190
+ clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange;
191
+
192
+
193
+ function applyOptions() {
194
+
195
+ container.toggleClass("sp-flat", flat);
196
+ container.toggleClass("sp-input-disabled", !opts.showInput);
197
+ container.toggleClass("sp-alpha-enabled", opts.showAlpha);
198
+ container.toggleClass("sp-buttons-disabled", !opts.showButtons || flat);
199
+ container.toggleClass("sp-palette-disabled", !opts.showPalette);
200
+ container.toggleClass("sp-palette-only", opts.showPaletteOnly);
201
+ container.toggleClass("sp-initial-disabled", !opts.showInitial);
202
+ container.addClass(opts.className);
203
+
204
+ reflow();
205
+ }
206
+
207
+ function initialize() {
208
+
209
+ if (IE) {
210
+ container.find("*:not(input)").attr("unselectable", "on");
211
+ }
212
+
213
+ applyOptions();
214
+
215
+ if (shouldReplace) {
216
+ boundElement.hide().after(replacer);
217
+ }
218
+
219
+ if (flat) {
220
+ boundElement.after(container).hide();
221
+ }
222
+ else {
223
+ $(body).append(container.hide());
224
+ }
225
+
226
+ if (localStorageKey && window.localStorage) {
227
+
228
+ // Migrate old palettes over to new format. May want to remove this eventually.
229
+ try {
230
+ var oldPalette = window.localStorage[localStorageKey].split(",#");
231
+ if (oldPalette.length > 1) {
232
+ delete window.localStorage[localStorageKey];
233
+ $.each(oldPalette, function(i, c) {
234
+ addColorToSelectionPalette(c);
235
+ });
236
+ }
237
+ }
238
+ catch(e) { }
239
+
240
+ try {
241
+ selectionPalette = window.localStorage[localStorageKey].split(";");
242
+ }
243
+ catch (e) { }
244
+ }
245
+
246
+ offsetElement.bind("click.spectrum touchstart.spectrum", function (e) {
247
+ if (!disabled) {
248
+ toggle();
249
+ }
250
+
251
+ e.stopPropagation();
252
+
253
+ if (!$(e.target).is("input")) {
254
+ e.preventDefault();
255
+ }
256
+ });
257
+
258
+ if(boundElement.is(":disabled") || (opts.disabled === true)) {
259
+ disable();
260
+ }
261
+
262
+ // Prevent clicks from bubbling up to document. This would cause it to be hidden.
263
+ container.click(stopPropagation);
264
+
265
+ // Handle user typed input
266
+ textInput.change(setFromTextInput);
267
+ textInput.bind("paste", function () {
268
+ setTimeout(setFromTextInput, 1);
269
+ });
270
+ textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } });
271
+
272
+ cancelButton.text(opts.cancelText);
273
+ cancelButton.bind("click.spectrum", function (e) {
274
+ e.stopPropagation();
275
+ e.preventDefault();
276
+ hide("cancel");
277
+ });
278
+
279
+ chooseButton.text(opts.chooseText);
280
+ chooseButton.bind("click.spectrum", function (e) {
281
+ e.stopPropagation();
282
+ e.preventDefault();
283
+
284
+ if (isValid()) {
285
+ updateOriginalInput(true);
286
+ hide();
287
+ }
288
+ });
289
+
290
+ draggable(alphaSlider, function (dragX, dragY, e) {
291
+ currentAlpha = (dragX / alphaWidth);
292
+ if (e.shiftKey) {
293
+ currentAlpha = Math.round(currentAlpha * 10) / 10;
294
+ }
295
+
296
+ move();
297
+ });
298
+
299
+ draggable(slider, function (dragX, dragY) {
300
+ currentHue = parseFloat(dragY / slideHeight);
301
+ move();
302
+ }, dragStart, dragStop);
303
+
304
+ draggable(dragger, function (dragX, dragY) {
305
+ currentSaturation = parseFloat(dragX / dragWidth);
306
+ currentValue = parseFloat((dragHeight - dragY) / dragHeight);
307
+ move();
308
+ }, dragStart, dragStop);
309
+
310
+ if (!!initialColor) {
311
+ set(initialColor);
312
+
313
+ // In case color was black - update the preview UI and set the format
314
+ // since the set function will not run (default color is black).
315
+ updateUI();
316
+ currentPreferredFormat = preferredFormat || tinycolor(initialColor).format;
317
+
318
+ addColorToSelectionPalette(initialColor);
319
+ }
320
+ else {
321
+ updateUI();
322
+ }
323
+
324
+ if (flat) {
325
+ show();
326
+ }
327
+
328
+ function palletElementClick(e) {
329
+ if (e.data && e.data.ignore) {
330
+ set($(this).data("color"));
331
+ move();
332
+ }
333
+ else {
334
+ set($(this).data("color"));
335
+ updateOriginalInput(true);
336
+ move();
337
+ hide();
338
+ }
339
+
340
+ return false;
341
+ }
342
+
343
+ var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum";
344
+ paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick);
345
+ initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick);
346
+ }
347
+
348
+ function addColorToSelectionPalette(color) {
349
+ if (showSelectionPalette) {
350
+ var colorRgb = tinycolor(color).toRgbString();
351
+ if ($.inArray(colorRgb, selectionPalette) === -1) {
352
+ selectionPalette.push(colorRgb);
353
+ }
354
+
355
+ if (localStorageKey && window.localStorage) {
356
+ try {
357
+ window.localStorage[localStorageKey] = selectionPalette.join(";");
358
+ }
359
+ catch(e) { }
360
+ }
361
+ }
362
+ }
363
+
364
+ function getUniqueSelectionPalette() {
365
+ var unique = [];
366
+ var p = selectionPalette;
367
+ var paletteLookup = {};
368
+ var rgb;
369
+
370
+ if (opts.showPalette) {
371
+
372
+ for (var i = 0; i < paletteArray.length; i++) {
373
+ for (var j = 0; j < paletteArray[i].length; j++) {
374
+ rgb = tinycolor(paletteArray[i][j]).toRgbString();
375
+ paletteLookup[rgb] = true;
376
+ }
377
+ }
378
+
379
+ for (i = 0; i < p.length; i++) {
380
+ rgb = tinycolor(p[i]).toRgbString();
381
+
382
+ if (!paletteLookup.hasOwnProperty(rgb)) {
383
+ unique.push(p[i]);
384
+ paletteLookup[rgb] = true;
385
+ }
386
+ }
387
+ }
388
+
389
+ return unique.reverse().slice(0, opts.maxSelectionSize);
390
+ }
391
+
392
+ function drawPalette() {
393
+
394
+ var currentColor = get();
395
+
396
+ var html = $.map(paletteArray, function (palette, i) {
397
+ return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i);
398
+ });
399
+
400
+ if (selectionPalette) {
401
+ html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection"));
402
+ }
403
+
404
+ paletteContainer.html(html.join(""));
405
+ }
406
+
407
+ function drawInitial() {
408
+ if (opts.showInitial) {
409
+ var initial = colorOnShow;
410
+ var current = get();
411
+ initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial"));
412
+ }
413
+ }
414
+
415
+ function dragStart() {
416
+ if (dragHeight === 0 || dragWidth === 0 || slideHeight === 0) {
417
+ reflow();
418
+ }
419
+ container.addClass(draggingClass);
420
+ }
421
+
422
+ function dragStop() {
423
+ container.removeClass(draggingClass);
424
+ }
425
+
426
+ function setFromTextInput() {
427
+ var tiny = tinycolor(textInput.val());
428
+ if (tiny.ok) {
429
+ set(tiny);
430
+ }
431
+ else {
432
+ textInput.addClass("sp-validation-error");
433
+ }
434
+ }
435
+
436
+ function toggle() {
437
+ if (visible) {
438
+ hide();
439
+ }
440
+ else {
441
+ show();
442
+ }
443
+ }
444
+
445
+ function show() {
446
+ if (visible) {
447
+ reflow();
448
+ return;
449
+ }
450
+ if (callbacks.beforeShow(get()) === false) return;
451
+
452
+ hideAll();
453
+ visible = true;
454
+
455
+ $(doc).bind("click.spectrum", hide);
456
+ $(window).bind("resize.spectrum", resize);
457
+ replacer.addClass("sp-active");
458
+ container.show();
459
+
460
+ if (opts.showPalette) {
461
+ drawPalette();
462
+ }
463
+ reflow();
464
+ updateUI();
465
+
466
+ colorOnShow = get();
467
+
468
+ drawInitial();
469
+ callbacks.show(colorOnShow);
470
+ }
471
+
472
+ function hide(e) {
473
+
474
+ // Return on right click
475
+ if (e && e.type == "click" && e.button == 2) { return; }
476
+
477
+ // Return if hiding is unnecessary
478
+ if (!visible || flat) { return; }
479
+ visible = false;
480
+
481
+ $(doc).unbind("click.spectrum", hide);
482
+ $(window).unbind("resize.spectrum", resize);
483
+
484
+ replacer.removeClass("sp-active");
485
+ container.hide();
486
+
487
+ var colorHasChanged = !tinycolor.equals(get(), colorOnShow);
488
+
489
+ if (colorHasChanged) {
490
+ if (clickoutFiresChange && e !== "cancel") {
491
+ updateOriginalInput(true);
492
+ }
493
+ else {
494
+ revert();
495
+ }
496
+ }
497
+
498
+ callbacks.hide(get());
499
+ }
500
+
501
+ function revert() {
502
+ set(colorOnShow, true);
503
+ }
504
+
505
+ function set(color, ignoreFormatChange) {
506
+ if (tinycolor.equals(color, get())) {
507
+ return;
508
+ }
509
+
510
+ var newColor = tinycolor(color);
511
+ var newHsv = newColor.toHsv();
512
+
513
+ currentHue = newHsv.h;
514
+ currentSaturation = newHsv.s;
515
+ currentValue = newHsv.v;
516
+ currentAlpha = newHsv.a;
517
+
518
+ updateUI();
519
+
520
+ if (!ignoreFormatChange) {
521
+ currentPreferredFormat = preferredFormat || newColor.format;
522
+ }
523
+ }
524
+
525
+ function get() {
526
+ return tinycolor.fromRatio({ h: currentHue, s: currentSaturation, v: currentValue, a: Math.round(currentAlpha * 100) / 100 });
527
+ }
528
+
529
+ function isValid() {
530
+ return !textInput.hasClass("sp-validation-error");
531
+ }
532
+
533
+ function move() {
534
+ updateUI();
535
+
536
+ callbacks.move(get());
537
+ }
538
+
539
+ function updateUI() {
540
+
541
+ textInput.removeClass("sp-validation-error");
542
+
543
+ updateHelperLocations();
544
+
545
+ // Update dragger background color (gradients take care of saturation and value).
546
+ var flatColor = tinycolor({ h: currentHue, s: "1.0", v: "1.0" });
547
+ dragger.css("background-color", flatColor.toHexString());
548
+
549
+ // Get a format that alpha will be included in (hex and names ignore alpha)
550
+ var format = currentPreferredFormat;
551
+ if (currentAlpha < 1) {
552
+ if (format === "hex" || format === "name") {
553
+ format = "rgb";
554
+ }
555
+ }
556
+
557
+ var realColor = get(),
558
+ realHex = realColor.toHexString(),
559
+ realRgb = realColor.toRgbString();
560
+
561
+
562
+ // Update the replaced elements background color (with actual selected color)
563
+ if (rgbaSupport || realColor.alpha === 1) {
564
+ previewElement.css("background-color", realRgb);
565
+ }
566
+ else {
567
+ previewElement.css("background-color", "transparent");
568
+ previewElement.css("filter", realColor.toFilter());
569
+ }
570
+
571
+ if (opts.showAlpha) {
572
+ var rgb = realColor.toRgb();
573
+ rgb.a = 0;
574
+ var realAlpha = tinycolor(rgb).toRgbString();
575
+ var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")";
576
+
577
+ if (IE) {
578
+ alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex));
579
+ }
580
+ else {
581
+ alphaSliderInner.css("background", "-webkit-" + gradient);
582
+ alphaSliderInner.css("background", "-moz-" + gradient);
583
+ alphaSliderInner.css("background", "-ms-" + gradient);
584
+ alphaSliderInner.css("background", gradient);
585
+ }
586
+ }
587
+
588
+
589
+ // Update the text entry input as it changes happen
590
+ if (opts.showInput) {
591
+ if (currentAlpha < 1) {
592
+ if (format === "hex" || format === "name") {
593
+ format = "rgb";
594
+ }
595
+ }
596
+ textInput.val(realColor.toString(format));
597
+ }
598
+
599
+ if (opts.showPalette) {
600
+ drawPalette();
601
+ }
602
+
603
+ drawInitial();
604
+ }
605
+
606
+ function updateHelperLocations() {
607
+ var s = currentSaturation;
608
+ var v = currentValue;
609
+
610
+ // Where to show the little circle in that displays your current selected color
611
+ var dragX = s * dragWidth;
612
+ var dragY = dragHeight - (v * dragHeight);
613
+ dragX = Math.max(
614
+ -dragHelperHeight,
615
+ Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight)
616
+ );
617
+ dragY = Math.max(
618
+ -dragHelperHeight,
619
+ Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight)
620
+ );
621
+ dragHelper.css({
622
+ "top": dragY,
623
+ "left": dragX
624
+ });
625
+
626
+ var alphaX = currentAlpha * alphaWidth;
627
+ alphaSlideHelper.css({
628
+ "left": alphaX - (alphaSlideHelperWidth / 2)
629
+ });
630
+
631
+ // Where to show the bar that displays your current selected hue
632
+ var slideY = (currentHue) * slideHeight;
633
+ slideHelper.css({
634
+ "top": slideY - slideHelperHeight
635
+ });
636
+ }
637
+
638
+ function updateOriginalInput(fireCallback) {
639
+ var color = get();
640
+
641
+ if (isInput) {
642
+ boundElement.val(color.toString(currentPreferredFormat)).change();
643
+ }
644
+
645
+ var hasChanged = !tinycolor.equals(color, colorOnShow);
646
+ colorOnShow = color;
647
+
648
+ // Update the selection palette with the current color
649
+ addColorToSelectionPalette(color);
650
+ if (fireCallback && hasChanged) {
651
+ callbacks.change(color);
652
+ }
653
+ }
654
+
655
+ function reflow() {
656
+ dragWidth = dragger.width();
657
+ dragHeight = dragger.height();
658
+ dragHelperHeight = dragHelper.height();
659
+ slideWidth = slider.width();
660
+ slideHeight = slider.height();
661
+ slideHelperHeight = slideHelper.height();
662
+ alphaWidth = alphaSlider.width();
663
+ alphaSlideHelperWidth = alphaSlideHelper.width();
664
+
665
+ if (!flat) {
666
+ container.offset(getOffset(container, offsetElement));
667
+ }
668
+
669
+ updateHelperLocations();
670
+ }
671
+
672
+ function destroy() {
673
+ boundElement.show();
674
+ offsetElement.unbind("click.spectrum touchstart.spectrum");
675
+ container.remove();
676
+ replacer.remove();
677
+ spectrums[spect.id] = null;
678
+ }
679
+
680
+ function option(optionName, optionValue) {
681
+ if (optionName === undefined) {
682
+ return $.extend({}, opts);
683
+ }
684
+ if (optionValue === undefined) {
685
+ return opts[optionName];
686
+ }
687
+
688
+ opts[optionName] = optionValue;
689
+ applyOptions();
690
+ }
691
+
692
+ function enable() {
693
+ disabled = false;
694
+ boundElement.attr("disabled", false);
695
+ offsetElement.removeClass("sp-disabled");
696
+ }
697
+
698
+ function disable() {
699
+ hide();
700
+ disabled = true;
701
+ boundElement.attr("disabled", true);
702
+ offsetElement.addClass("sp-disabled");
703
+ }
704
+
705
+ initialize();
706
+
707
+ var spect = {
708
+ show: show,
709
+ hide: hide,
710
+ toggle: toggle,
711
+ reflow: reflow,
712
+ option: option,
713
+ enable: enable,
714
+ disable: disable,
715
+ set: function (c) {
716
+ set(c);
717
+ updateOriginalInput();
718
+ },
719
+ get: get,
720
+ destroy: destroy,
721
+ container: container
722
+ };
723
+
724
+ spect.id = spectrums.push(spect) - 1;
725
+
726
+ return spect;
727
+ }
728
+
729
+ /**
730
+ * checkOffset - get the offset below/above and left/right element depending on screen position
731
+ * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js
732
+ */
733
+ function getOffset(picker, input) {
734
+ var extraY = 0;
735
+ var dpWidth = picker.outerWidth();
736
+ var dpHeight = picker.outerHeight();
737
+ var inputHeight = input.outerHeight();
738
+ var doc = picker[0].ownerDocument;
739
+ var docElem = doc.documentElement;
740
+ var viewWidth = docElem.clientWidth + $(doc).scrollLeft();
741
+ var viewHeight = docElem.clientHeight + $(doc).scrollTop();
742
+ var offset = input.offset();
743
+ offset.top += inputHeight;
744
+
745
+ offset.left -=
746
+ Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
747
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
748
+
749
+ offset.top -=
750
+ Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
751
+ Math.abs(dpHeight + inputHeight - extraY) : extraY));
752
+
753
+ return offset;
754
+ }
755
+
756
+ /**
757
+ * noop - do nothing
758
+ */
759
+ function noop() {
760
+
761
+ }
762
+
763
+ /**
764
+ * stopPropagation - makes the code only doing this a little easier to read in line
765
+ */
766
+ function stopPropagation(e) {
767
+ e.stopPropagation();
768
+ }
769
+
770
+ /**
771
+ * Create a function bound to a given object
772
+ * Thanks to underscore.js
773
+ */
774
+ function bind(func, obj) {
775
+ var slice = Array.prototype.slice;
776
+ var args = slice.call(arguments, 2);
777
+ return function () {
778
+ return func.apply(obj, args.concat(slice.call(arguments)));
779
+ };
780
+ }
781
+
782
+ /**
783
+ * Lightweight drag helper. Handles containment within the element, so that
784
+ * when dragging, the x is within [0,element.width] and y is within [0,element.height]
785
+ */
786
+ function draggable(element, onmove, onstart, onstop) {
787
+ onmove = onmove || function () { };
788
+ onstart = onstart || function () { };
789
+ onstop = onstop || function () { };
790
+ var doc = element.ownerDocument || document;
791
+ var dragging = false;
792
+ var offset = {};
793
+ var maxHeight = 0;
794
+ var maxWidth = 0;
795
+ var hasTouch = ('ontouchstart' in window);
796
+
797
+ var duringDragEvents = {};
798
+ duringDragEvents["selectstart"] = prevent;
799
+ duringDragEvents["dragstart"] = prevent;
800
+ duringDragEvents[(hasTouch ? "touchmove" : "mousemove")] = move;
801
+ duringDragEvents[(hasTouch ? "touchend" : "mouseup")] = stop;
802
+
803
+ function prevent(e) {
804
+ if (e.stopPropagation) {
805
+ e.stopPropagation();
806
+ }
807
+ if (e.preventDefault) {
808
+ e.preventDefault();
809
+ }
810
+ e.returnValue = false;
811
+ }
812
+
813
+ function move(e) {
814
+ if (dragging) {
815
+ // Mouseup happened outside of window
816
+ if (IE && document.documentMode < 9 && !e.button) {
817
+ return stop();
818
+ }
819
+
820
+ var touches = e.originalEvent.touches;
821
+ var pageX = touches ? touches[0].pageX : e.pageX;
822
+ var pageY = touches ? touches[0].pageY : e.pageY;
823
+
824
+ var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth));
825
+ var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight));
826
+
827
+ if (hasTouch) {
828
+ // Stop scrolling in iOS
829
+ prevent(e);
830
+ }
831
+
832
+ onmove.apply(element, [dragX, dragY, e]);
833
+ }
834
+ }
835
+ function start(e) {
836
+ var rightclick = (e.which) ? (e.which == 3) : (e.button == 2);
837
+ var touches = e.originalEvent.touches;
838
+
839
+ if (!rightclick && !dragging) {
840
+ if (onstart.apply(element, arguments) !== false) {
841
+ dragging = true;
842
+ maxHeight = $(element).height();
843
+ maxWidth = $(element).width();
844
+ offset = $(element).offset();
845
+
846
+ $(doc).bind(duringDragEvents);
847
+ $(doc.body).addClass("sp-dragging");
848
+
849
+ if (!hasTouch) {
850
+ move(e);
851
+ }
852
+
853
+ prevent(e);
854
+ }
855
+ }
856
+ }
857
+ function stop() {
858
+ if (dragging) {
859
+ $(doc).unbind(duringDragEvents);
860
+ $(doc.body).removeClass("sp-dragging");
861
+ onstop.apply(element, arguments);
862
+ }
863
+ dragging = false;
864
+ }
865
+
866
+ $(element).bind(hasTouch ? "touchstart" : "mousedown", start);
867
+ }
868
+
869
+ function throttle(func, wait, debounce) {
870
+ var timeout;
871
+ return function () {
872
+ var context = this, args = arguments;
873
+ var throttler = function () {
874
+ timeout = null;
875
+ func.apply(context, args);
876
+ };
877
+ if (debounce) clearTimeout(timeout);
878
+ if (debounce || !timeout) timeout = setTimeout(throttler, wait);
879
+ };
880
+ }
881
+
882
+
883
+ /**
884
+ * Define a jQuery plugin
885
+ */
886
+ var dataID = "spectrum.id";
887
+ $.fn.spectrum = function (opts, extra) {
888
+
889
+ if (typeof opts == "string") {
890
+
891
+ var returnValue = this;
892
+ var args = Array.prototype.slice.call( arguments, 1 );
893
+
894
+ this.each(function () {
895
+ var spect = spectrums[$(this).data(dataID)];
896
+ if (spect) {
897
+
898
+ var method = spect[opts];
899
+ if (!method) {
900
+ throw new Error( "Spectrum: no such method: '" + opts + "'" );
901
+ }
902
+
903
+ if (opts == "get") {
904
+ returnValue = spect.get();
905
+ }
906
+ else if (opts == "container") {
907
+ returnValue = spect.container;
908
+ }
909
+ else if (opts == "option") {
910
+ returnValue = spect.option.apply(spect, args);
911
+ }
912
+ else if (opts == "destroy") {
913
+ spect.destroy();
914
+ $(this).removeData(dataID);
915
+ }
916
+ else {
917
+ method.apply(spect, args);
918
+ }
919
+ }
920
+ });
921
+
922
+ return returnValue;
923
+ }
924
+
925
+ // Initializing a new instance of spectrum
926
+ return this.spectrum("destroy").each(function () {
927
+ var spect = spectrum(this, opts);
928
+ $(this).data(dataID, spect.id);
929
+ });
930
+ };
931
+
932
+ $.fn.spectrum.load = true;
933
+ $.fn.spectrum.loadOpts = {};
934
+ $.fn.spectrum.draggable = draggable;
935
+ $.fn.spectrum.defaults = defaultOpts;
936
+
937
+ $.spectrum = { };
938
+ $.spectrum.localization = { };
939
+ $.spectrum.palettes = { };
940
+
941
+ $.fn.spectrum.processNativeColorInputs = function () {
942
+ var colorInput = $("<input type='color' value='!' />")[0];
943
+ var supportsColor = colorInput.type === "color" && colorInput.value != "!";
944
+
945
+ if (!supportsColor) {
946
+ $("input[type=color]").spectrum({
947
+ preferredFormat: "hex6"
948
+ });
949
+ }
950
+ };
951
+
952
+ // TinyColor.js - <https://github.com/bgrins/TinyColor> - 2011 Brian Grinstead - v0.5
953
+
954
+ (function (window) {
955
+
956
+ var trimLeft = /^[\s,#]+/,
957
+ trimRight = /\s+$/,
958
+ tinyCounter = 0,
959
+ math = Math,
960
+ mathRound = math.round,
961
+ mathMin = math.min,
962
+ mathMax = math.max,
963
+ mathRandom = math.random,
964
+ parseFloat = window.parseFloat;
965
+
966
+ function tinycolor(color, opts) {
967
+
968
+ // If input is already a tinycolor, return itself
969
+ if (typeof color == "object" && color.hasOwnProperty("_tc_id")) {
970
+ return color;
971
+ }
972
+
973
+ var rgb = inputToRGB(color);
974
+ var r = rgb.r, g = rgb.g, b = rgb.b, a = parseFloat(rgb.a), format = rgb.format;
975
+
976
+ return {
977
+ ok: rgb.ok,
978
+ format: format,
979
+ _tc_id: tinyCounter++,
980
+ alpha: a,
981
+ toHsv: function () {
982
+ var hsv = rgbToHsv(r, g, b);
983
+ return { h: hsv.h, s: hsv.s, v: hsv.v, a: a };
984
+ },
985
+ toHsvString: function () {
986
+ var hsv = rgbToHsv(r, g, b);
987
+ var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
988
+ return (a == 1) ?
989
+ "hsv(" + h + ", " + s + "%, " + v + "%)" :
990
+ "hsva(" + h + ", " + s + "%, " + v + "%, " + a + ")";
991
+ },
992
+ toHsl: function () {
993
+ var hsl = rgbToHsl(r, g, b);
994
+ return { h: hsl.h, s: hsl.s, l: hsl.l, a: a };
995
+ },
996
+ toHslString: function () {
997
+ var hsl = rgbToHsl(r, g, b);
998
+ var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
999
+ return (a == 1) ?
1000
+ "hsl(" + h + ", " + s + "%, " + l + "%)" :
1001
+ "hsla(" + h + ", " + s + "%, " + l + "%, " + a + ")";
1002
+ },
1003
+ toHex: function () {
1004
+ return rgbToHex(r, g, b);
1005
+ },
1006
+ toHexString: function (force6Char) {
1007
+ return '#' + rgbToHex(r, g, b, force6Char);
1008
+ },
1009
+ toRgb: function () {
1010
+ return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a };
1011
+ },
1012
+ toRgbString: function () {
1013
+ return (a == 1) ?
1014
+ "rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" :
1015
+ "rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + a + ")";
1016
+ },
1017
+ toName: function () {
1018
+ return hexNames[rgbToHex(r, g, b)] || false;
1019
+ },
1020
+ toFilter: function (opts, secondColor) {
1021
+
1022
+ var hex = rgbToHex(r, g, b, true);
1023
+ var secondHex = hex;
1024
+ var alphaHex = Math.round(parseFloat(a) * 255).toString(16);
1025
+ var secondAlphaHex = alphaHex;
1026
+ var gradientType = opts && opts.gradientType ? "GradientType = 1, " : "";
1027
+
1028
+ if (secondColor) {
1029
+ var s = tinycolor(secondColor);
1030
+ secondHex = s.toHex();
1031
+ secondAlphaHex = Math.round(parseFloat(s.alpha) * 255).toString(16);
1032
+ }
1033
+
1034
+ return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr=#" + pad2(alphaHex) + hex + ",endColorstr=#" + pad2(secondAlphaHex) + secondHex + ")";
1035
+ },
1036
+ toString: function (format) {
1037
+ format = format || this.format;
1038
+ var formattedString = false;
1039
+ if (format === "rgb") {
1040
+ formattedString = this.toRgbString();
1041
+ }
1042
+ if (format === "hex") {
1043
+ formattedString = this.toHexString();
1044
+ }
1045
+ if (format === "hex6") {
1046
+ formattedString = this.toHexString(true);
1047
+ }
1048
+ if (format === "name") {
1049
+ formattedString = this.toName();
1050
+ }
1051
+ if (format === "hsl") {
1052
+ formattedString = this.toHslString();
1053
+ }
1054
+ if (format === "hsv") {
1055
+ formattedString = this.toHsvString();
1056
+ }
1057
+
1058
+ return formattedString || this.toHexString(true);
1059
+ }
1060
+ };
1061
+ }
1062
+
1063
+ // If input is an object, force 1 into "1.0" to handle ratios properly
1064
+ // String input requires "1.0" as input, so 1 will be treated as 1
1065
+ tinycolor.fromRatio = function (color) {
1066
+
1067
+ if (typeof color == "object") {
1068
+ for (var i in color) {
1069
+ if (color[i] === 1) {
1070
+ color[i] = "1.0";
1071
+ }
1072
+ }
1073
+ }
1074
+
1075
+ return tinycolor(color);
1076
+
1077
+ };
1078
+
1079
+ // Given a string or object, convert that input to RGB
1080
+ // Possible string inputs:
1081
+ //
1082
+ // "red"
1083
+ // "#f00" or "f00"
1084
+ // "#ff0000" or "ff0000"
1085
+ // "rgb 255 0 0" or "rgb (255, 0, 0)"
1086
+ // "rgb 1.0 0 0" or "rgb (1, 0, 0)"
1087
+ // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
1088
+ // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
1089
+ // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
1090
+ // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
1091
+ // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
1092
+ //
1093
+ function inputToRGB(color) {
1094
+
1095
+ var rgb = { r: 0, g: 0, b: 0 };
1096
+ var a = 1;
1097
+ var ok = false;
1098
+ var format = false;
1099
+
1100
+ if (typeof color == "string") {
1101
+ color = stringInputToObject(color);
1102
+ }
1103
+
1104
+ if (typeof color == "object") {
1105
+ if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) {
1106
+ rgb = rgbToRgb(color.r, color.g, color.b);
1107
+ ok = true;
1108
+ format = "rgb";
1109
+ }
1110
+ else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
1111
+ rgb = hsvToRgb(color.h, color.s, color.v);
1112
+ ok = true;
1113
+ format = "hsv";
1114
+ }
1115
+ else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
1116
+ rgb = hslToRgb(color.h, color.s, color.l);
1117
+ ok = true;
1118
+ format = "hsl";
1119
+ }
1120
+
1121
+ if (color.hasOwnProperty("a")) {
1122
+ a = color.a;
1123
+ }
1124
+ }
1125
+
1126
+ rgb.r = mathMin(255, mathMax(rgb.r, 0));
1127
+ rgb.g = mathMin(255, mathMax(rgb.g, 0));
1128
+ rgb.b = mathMin(255, mathMax(rgb.b, 0));
1129
+
1130
+
1131
+ // Don't let the range of [0,255] come back in [0,1].
1132
+ // Potentially lose a little bit of precision here, but will fix issues where
1133
+ // .5 gets interpreted as half of the total, instead of half of 1.
1134
+ // If it was supposed to be 128, this was already taken care of in the conversion function
1135
+ if (rgb.r < 1) { rgb.r = mathRound(rgb.r); }
1136
+ if (rgb.g < 1) { rgb.g = mathRound(rgb.g); }
1137
+ if (rgb.b < 1) { rgb.b = mathRound(rgb.b); }
1138
+
1139
+ return {
1140
+ ok: ok,
1141
+ format: (color && color.format) || format,
1142
+ r: rgb.r,
1143
+ g: rgb.g,
1144
+ b: rgb.b,
1145
+ a: a
1146
+ };
1147
+ }
1148
+
1149
+
1150
+
1151
+ // Conversion Functions
1152
+ // --------------------
1153
+
1154
+ // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
1155
+ // <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
1156
+
1157
+ // `rgbToRgb`
1158
+ // Handle bounds / percentage checking to conform to CSS color spec
1159
+ // <http://www.w3.org/TR/css3-color/>
1160
+ // *Assumes:* r, g, b in [0, 255] or [0, 1]
1161
+ // *Returns:* { r, g, b } in [0, 255]
1162
+ function rgbToRgb(r, g, b) {
1163
+ return {
1164
+ r: bound01(r, 255) * 255,
1165
+ g: bound01(g, 255) * 255,
1166
+ b: bound01(b, 255) * 255
1167
+ };
1168
+ }
1169
+
1170
+ // `rgbToHsl`
1171
+ // Converts an RGB color value to HSL.
1172
+ // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
1173
+ // *Returns:* { h, s, l } in [0,1]
1174
+ function rgbToHsl(r, g, b) {
1175
+
1176
+ r = bound01(r, 255);
1177
+ g = bound01(g, 255);
1178
+ b = bound01(b, 255);
1179
+
1180
+ var max = mathMax(r, g, b), min = mathMin(r, g, b);
1181
+ var h, s, l = (max + min) / 2;
1182
+
1183
+ if (max == min) {
1184
+ h = s = 0; // achromatic
1185
+ }
1186
+ else {
1187
+ var d = max - min;
1188
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1189
+ switch (max) {
1190
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1191
+ case g: h = (b - r) / d + 2; break;
1192
+ case b: h = (r - g) / d + 4; break;
1193
+ }
1194
+
1195
+ h /= 6;
1196
+ }
1197
+
1198
+ return { h: h, s: s, l: l };
1199
+ }
1200
+
1201
+ // `hslToRgb`
1202
+ // Converts an HSL color value to RGB.
1203
+ // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
1204
+ // *Returns:* { r, g, b } in the set [0, 255]
1205
+ function hslToRgb(h, s, l) {
1206
+ var r, g, b;
1207
+
1208
+ h = bound01(h, 360);
1209
+ s = bound01(s, 100);
1210
+ l = bound01(l, 100);
1211
+
1212
+ function hue2rgb(p, q, t) {
1213
+ if (t < 0) t += 1;
1214
+ if (t > 1) t -= 1;
1215
+ if (t < 1 / 6) return p + (q - p) * 6 * t;
1216
+ if (t < 1 / 2) return q;
1217
+ if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
1218
+ return p;
1219
+ }
1220
+
1221
+ if (s === 0) {
1222
+ r = g = b = l; // achromatic
1223
+ }
1224
+ else {
1225
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1226
+ var p = 2 * l - q;
1227
+ r = hue2rgb(p, q, h + 1 / 3);
1228
+ g = hue2rgb(p, q, h);
1229
+ b = hue2rgb(p, q, h - 1 / 3);
1230
+ }
1231
+
1232
+ return { r: r * 255, g: g * 255, b: b * 255 };
1233
+ }
1234
+
1235
+ // `rgbToHsv`
1236
+ // Converts an RGB color value to HSV
1237
+ // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
1238
+ // *Returns:* { h, s, v } in [0,1]
1239
+ function rgbToHsv(r, g, b) {
1240
+
1241
+ r = bound01(r, 255);
1242
+ g = bound01(g, 255);
1243
+ b = bound01(b, 255);
1244
+
1245
+ var max = mathMax(r, g, b), min = mathMin(r, g, b);
1246
+ var h, s, v = max;
1247
+
1248
+ var d = max - min;
1249
+ s = max === 0 ? 0 : d / max;
1250
+
1251
+ if (max == min) {
1252
+ h = 0; // achromatic
1253
+ }
1254
+ else {
1255
+ switch (max) {
1256
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1257
+ case g: h = (b - r) / d + 2; break;
1258
+ case b: h = (r - g) / d + 4; break;
1259
+ }
1260
+ h /= 6;
1261
+ }
1262
+ return { h: h, s: s, v: v };
1263
+ }
1264
+
1265
+ // `hsvToRgb`
1266
+ // Converts an HSV color value to RGB.
1267
+ // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
1268
+ // *Returns:* { r, g, b } in the set [0, 255]
1269
+ function hsvToRgb(h, s, v) {
1270
+ h = bound01(h, 360) * 6;
1271
+ s = bound01(s, 100);
1272
+ v = bound01(v, 100);
1273
+
1274
+ var i = math.floor(h),
1275
+ f = h - i,
1276
+ p = v * (1 - s),
1277
+ q = v * (1 - f * s),
1278
+ t = v * (1 - (1 - f) * s),
1279
+ mod = i % 6,
1280
+ r = [v, q, p, p, t, v][mod],
1281
+ g = [t, v, v, q, p, p][mod],
1282
+ b = [p, p, t, v, v, q][mod];
1283
+
1284
+ return { r: r * 255, g: g * 255, b: b * 255 };
1285
+ }
1286
+
1287
+ // `rgbToHex`
1288
+ // Converts an RGB color to hex
1289
+ // Assumes r, g, and b are contained in the set [0, 255]
1290
+ // Returns a 3 or 6 character hex
1291
+ function rgbToHex(r, g, b, force6Char) {
1292
+
1293
+ var hex = [
1294
+ pad2(mathRound(r).toString(16)),
1295
+ pad2(mathRound(g).toString(16)),
1296
+ pad2(mathRound(b).toString(16))
1297
+ ];
1298
+
1299
+ // Return a 3 character hex if possible
1300
+ if (!force6Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
1301
+ return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
1302
+ }
1303
+
1304
+ return hex.join("");
1305
+ }
1306
+
1307
+ // `equals`
1308
+ // Can be called with any tinycolor input
1309
+ tinycolor.equals = function (color1, color2) {
1310
+ if (!color1 || !color2) { return false; }
1311
+ return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
1312
+ };
1313
+ tinycolor.random = function () {
1314
+ return tinycolor.fromRatio({
1315
+ r: mathRandom(),
1316
+ g: mathRandom(),
1317
+ b: mathRandom()
1318
+ });
1319
+ };
1320
+
1321
+
1322
+ // Modification Functions
1323
+ // ----------------------
1324
+ // Thanks to less.js for some of the basics here
1325
+ // <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>
1326
+
1327
+
1328
+ tinycolor.desaturate = function (color, amount) {
1329
+ var hsl = tinycolor(color).toHsl();
1330
+ hsl.s -= ((amount || 10) / 100);
1331
+ hsl.s = clamp01(hsl.s);
1332
+ return tinycolor(hsl);
1333
+ };
1334
+ tinycolor.saturate = function (color, amount) {
1335
+ var hsl = tinycolor(color).toHsl();
1336
+ hsl.s += ((amount || 10) / 100);
1337
+ hsl.s = clamp01(hsl.s);
1338
+ return tinycolor(hsl);
1339
+ };
1340
+ tinycolor.greyscale = function (color) {
1341
+ return tinycolor.desaturate(color, 100);
1342
+ };
1343
+ tinycolor.lighten = function (color, amount) {
1344
+ var hsl = tinycolor(color).toHsl();
1345
+ hsl.l += ((amount || 10) / 100);
1346
+ hsl.l = clamp01(hsl.l);
1347
+ return tinycolor(hsl);
1348
+ };
1349
+ tinycolor.darken = function (color, amount) {
1350
+ var hsl = tinycolor(color).toHsl();
1351
+ hsl.l -= ((amount || 10) / 100);
1352
+ hsl.l = clamp01(hsl.l);
1353
+ return tinycolor(hsl);
1354
+ };
1355
+ tinycolor.complement = function (color) {
1356
+ var hsl = tinycolor(color).toHsl();
1357
+ hsl.h = (hsl.h + 0.5) % 1;
1358
+ return tinycolor(hsl);
1359
+ };
1360
+
1361
+
1362
+ // Combination Functions
1363
+ // ---------------------
1364
+ // Thanks to jQuery xColor for some of the ideas behind these
1365
+ // <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>
1366
+
1367
+ tinycolor.triad = function (color) {
1368
+ var hsl = tinycolor(color).toHsl();
1369
+ var h = hsl.h * 360;
1370
+ return [
1371
+ tinycolor(color),
1372
+ tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
1373
+ tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
1374
+ ];
1375
+ };
1376
+ tinycolor.tetrad = function (color) {
1377
+ var hsl = tinycolor(color).toHsl();
1378
+ var h = hsl.h * 360;
1379
+ return [
1380
+ tinycolor(color),
1381
+ tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
1382
+ tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
1383
+ tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
1384
+ ];
1385
+ };
1386
+ tinycolor.splitcomplement = function (color) {
1387
+ var hsl = tinycolor(color).toHsl();
1388
+ var h = hsl.h * 360;
1389
+ return [
1390
+ tinycolor(color),
1391
+ tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l }),
1392
+ tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l })
1393
+ ];
1394
+ };
1395
+ tinycolor.analogous = function (color, results, slices) {
1396
+ results = results || 6;
1397
+ slices = slices || 30;
1398
+
1399
+ var hsl = tinycolor(color).toHsl();
1400
+ var part = 360 / slices;
1401
+ var ret = [tinycolor(color)];
1402
+
1403
+ hsl.h *= 360;
1404
+
1405
+ for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {
1406
+ hsl.h = (hsl.h + part) % 360;
1407
+ ret.push(tinycolor(hsl));
1408
+ }
1409
+ return ret;
1410
+ };
1411
+ tinycolor.monochromatic = function (color, results) {
1412
+ results = results || 6;
1413
+ var hsv = tinycolor(color).toHsv();
1414
+ var h = hsv.h, s = hsv.s, v = hsv.v;
1415
+ var ret = [];
1416
+ var modification = 1 / results;
1417
+
1418
+ while (results--) {
1419
+ ret.push(tinycolor({ h: h, s: s, v: v }));
1420
+ v = (v + modification) % 1;
1421
+ }
1422
+
1423
+ return ret;
1424
+ };
1425
+ tinycolor.readable = function (color1, color2) {
1426
+ var a = tinycolor(color1).toRgb(), b = tinycolor(color2).toRgb();
1427
+ return (
1428
+ (b.r - a.r) * (b.r - a.r) +
1429
+ (b.g - a.g) * (b.g - a.g) +
1430
+ (b.b - a.b) * (b.b - a.b)
1431
+ ) > 0x28A4;
1432
+ };
1433
+
1434
+ // Big List of Colors
1435
+ // ---------
1436
+ // <http://www.w3.org/TR/css3-color/#svg-color>
1437
+ var names = tinycolor.names = {
1438
+ aliceblue: "f0f8ff",
1439
+ antiquewhite: "faebd7",
1440
+ aqua: "0ff",
1441
+ aquamarine: "7fffd4",
1442
+ azure: "f0ffff",
1443
+ beige: "f5f5dc",
1444
+ bisque: "ffe4c4",
1445
+ black: "000",
1446
+ blanchedalmond: "ffebcd",
1447
+ blue: "00f",
1448
+ blueviolet: "8a2be2",
1449
+ brown: "a52a2a",
1450
+ burlywood: "deb887",
1451
+ burntsienna: "ea7e5d",
1452
+ cadetblue: "5f9ea0",
1453
+ chartreuse: "7fff00",
1454
+ chocolate: "d2691e",
1455
+ coral: "ff7f50",
1456
+ cornflowerblue: "6495ed",
1457
+ cornsilk: "fff8dc",
1458
+ crimson: "dc143c",
1459
+ cyan: "0ff",
1460
+ darkblue: "00008b",
1461
+ darkcyan: "008b8b",
1462
+ darkgoldenrod: "b8860b",
1463
+ darkgray: "a9a9a9",
1464
+ darkgreen: "006400",
1465
+ darkgrey: "a9a9a9",
1466
+ darkkhaki: "bdb76b",
1467
+ darkmagenta: "8b008b",
1468
+ darkolivegreen: "556b2f",
1469
+ darkorange: "ff8c00",
1470
+ darkorchid: "9932cc",
1471
+ darkred: "8b0000",
1472
+ darksalmon: "e9967a",
1473
+ darkseagreen: "8fbc8f",
1474
+ darkslateblue: "483d8b",
1475
+ darkslategray: "2f4f4f",
1476
+ darkslategrey: "2f4f4f",
1477
+ darkturquoise: "00ced1",
1478
+ darkviolet: "9400d3",
1479
+ deeppink: "ff1493",
1480
+ deepskyblue: "00bfff",
1481
+ dimgray: "696969",
1482
+ dimgrey: "696969",
1483
+ dodgerblue: "1e90ff",
1484
+ firebrick: "b22222",
1485
+ floralwhite: "fffaf0",
1486
+ forestgreen: "228b22",
1487
+ fuchsia: "f0f",
1488
+ gainsboro: "dcdcdc",
1489
+ ghostwhite: "f8f8ff",
1490
+ gold: "ffd700",
1491
+ goldenrod: "daa520",
1492
+ gray: "808080",
1493
+ green: "008000",
1494
+ greenyellow: "adff2f",
1495
+ grey: "808080",
1496
+ honeydew: "f0fff0",
1497
+ hotpink: "ff69b4",
1498
+ indianred: "cd5c5c",
1499
+ indigo: "4b0082",
1500
+ ivory: "fffff0",
1501
+ khaki: "f0e68c",
1502
+ lavender: "e6e6fa",
1503
+ lavenderblush: "fff0f5",
1504
+ lawngreen: "7cfc00",
1505
+ lemonchiffon: "fffacd",
1506
+ lightblue: "add8e6",
1507
+ lightcoral: "f08080",
1508
+ lightcyan: "e0ffff",
1509
+ lightgoldenrodyellow: "fafad2",
1510
+ lightgray: "d3d3d3",
1511
+ lightgreen: "90ee90",
1512
+ lightgrey: "d3d3d3",
1513
+ lightpink: "ffb6c1",
1514
+ lightsalmon: "ffa07a",
1515
+ lightseagreen: "20b2aa",
1516
+ lightskyblue: "87cefa",
1517
+ lightslategray: "789",
1518
+ lightslategrey: "789",
1519
+ lightsteelblue: "b0c4de",
1520
+ lightyellow: "ffffe0",
1521
+ lime: "0f0",
1522
+ limegreen: "32cd32",
1523
+ linen: "faf0e6",
1524
+ magenta: "f0f",
1525
+ maroon: "800000",
1526
+ mediumaquamarine: "66cdaa",
1527
+ mediumblue: "0000cd",
1528
+ mediumorchid: "ba55d3",
1529
+ mediumpurple: "9370db",
1530
+ mediumseagreen: "3cb371",
1531
+ mediumslateblue: "7b68ee",
1532
+ mediumspringgreen: "00fa9a",
1533
+ mediumturquoise: "48d1cc",
1534
+ mediumvioletred: "c71585",
1535
+ midnightblue: "191970",
1536
+ mintcream: "f5fffa",
1537
+ mistyrose: "ffe4e1",
1538
+ moccasin: "ffe4b5",
1539
+ navajowhite: "ffdead",
1540
+ navy: "000080",
1541
+ oldlace: "fdf5e6",
1542
+ olive: "808000",
1543
+ olivedrab: "6b8e23",
1544
+ orange: "ffa500",
1545
+ orangered: "ff4500",
1546
+ orchid: "da70d6",
1547
+ palegoldenrod: "eee8aa",
1548
+ palegreen: "98fb98",
1549
+ paleturquoise: "afeeee",
1550
+ palevioletred: "db7093",
1551
+ papayawhip: "ffefd5",
1552
+ peachpuff: "ffdab9",
1553
+ peru: "cd853f",
1554
+ pink: "ffc0cb",
1555
+ plum: "dda0dd",
1556
+ powderblue: "b0e0e6",
1557
+ purple: "800080",
1558
+ red: "f00",
1559
+ rosybrown: "bc8f8f",
1560
+ royalblue: "4169e1",
1561
+ saddlebrown: "8b4513",
1562
+ salmon: "fa8072",
1563
+ sandybrown: "f4a460",
1564
+ seagreen: "2e8b57",
1565
+ seashell: "fff5ee",
1566
+ sienna: "a0522d",
1567
+ silver: "c0c0c0",
1568
+ skyblue: "87ceeb",
1569
+ slateblue: "6a5acd",
1570
+ slategray: "708090",
1571
+ slategrey: "708090",
1572
+ snow: "fffafa",
1573
+ springgreen: "00ff7f",
1574
+ steelblue: "4682b4",
1575
+ tan: "d2b48c",
1576
+ teal: "008080",
1577
+ thistle: "d8bfd8",
1578
+ tomato: "ff6347",
1579
+ turquoise: "40e0d0",
1580
+ violet: "ee82ee",
1581
+ wheat: "f5deb3",
1582
+ white: "fff",
1583
+ whitesmoke: "f5f5f5",
1584
+ yellow: "ff0",
1585
+ yellowgreen: "9acd32"
1586
+ };
1587
+
1588
+ // Make it easy to access colors via `hexNames[hex]`
1589
+ var hexNames = tinycolor.hexNames = flip(names);
1590
+
1591
+
1592
+ // Utilities
1593
+ // ---------
1594
+
1595
+ // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }`
1596
+ function flip(o) {
1597
+ var flipped = {};
1598
+ for (var i in o) {
1599
+ if (o.hasOwnProperty(i)) {
1600
+ flipped[o[i]] = i;
1601
+ }
1602
+ }
1603
+ return flipped;
1604
+ }
1605
+
1606
+ // Take input from [0, n] and return it as [0, 1]
1607
+ function bound01(n, max) {
1608
+ if (isOnePointZero(n)) { n = "100%"; }
1609
+
1610
+ var processPercent = isPercentage(n);
1611
+ n = mathMin(max, mathMax(0, parseFloat(n)));
1612
+
1613
+ // Automatically convert percentage into number
1614
+ if (processPercent) {
1615
+ n = n * (max / 100);
1616
+ }
1617
+
1618
+ // Handle floating point rounding errors
1619
+ if (math.abs(n - max) < 0.000001) {
1620
+ return 1;
1621
+ }
1622
+ else if (n >= 1) {
1623
+ return (n % max) / parseFloat(max);
1624
+ }
1625
+ return n;
1626
+ }
1627
+
1628
+ // Force a number between 0 and 1
1629
+ function clamp01(val) {
1630
+ return mathMin(1, mathMax(0, val));
1631
+ }
1632
+
1633
+ // Parse an integer into hex
1634
+ function parseHex(val) {
1635
+ return parseInt(val, 16);
1636
+ }
1637
+
1638
+ // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
1639
+ // <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
1640
+ function isOnePointZero(n) {
1641
+ return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
1642
+ }
1643
+
1644
+ // Check to see if string passed in is a percentage
1645
+ function isPercentage(n) {
1646
+ return typeof n === "string" && n.indexOf('%') != -1;
1647
+ }
1648
+
1649
+ // Force a hex value to have 2 characters
1650
+ function pad2(c) {
1651
+ return c.length == 1 ? '0' + c : '' + c;
1652
+ }
1653
+
1654
+ var matchers = (function () {
1655
+
1656
+ // <http://www.w3.org/TR/css3-values/#integers>
1657
+ var CSS_INTEGER = "[-\\+]?\\d+%?";
1658
+
1659
+ // <http://www.w3.org/TR/css3-values/#number-value>
1660
+ var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
1661
+
1662
+ // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
1663
+ var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
1664
+
1665
+ // Actual matching.
1666
+ // Parentheses and commas are optional, but not required.
1667
+ // Whitespace can take the place of commas or opening paren
1668
+ var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
1669
+ var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
1670
+
1671
+ return {
1672
+ rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
1673
+ rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
1674
+ hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
1675
+ hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
1676
+ hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
1677
+ hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
1678
+ hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
1679
+ };
1680
+ })();
1681
+
1682
+ // `stringInputToObject`
1683
+ // Permissive string parsing. Take in a number of formats, and output an object
1684
+ // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
1685
+ function stringInputToObject(color) {
1686
+
1687
+ color = color.replace(trimLeft, '').replace(trimRight, '').toLowerCase();
1688
+ var named = false;
1689
+ if (names[color]) {
1690
+ color = names[color];
1691
+ named = true;
1692
+ }
1693
+ else if (color == 'transparent') {
1694
+ return { r: 0, g: 0, b: 0, a: 0 };
1695
+ }
1696
+
1697
+ // Try to match string input using regular expressions.
1698
+ // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
1699
+ // Just return an object and let the conversion functions handle that.
1700
+ // This way the result will be the same whether the tinycolor is initialized with string or object.
1701
+ var match;
1702
+ if ((match = matchers.rgb.exec(color))) {
1703
+ return { r: match[1], g: match[2], b: match[3] };
1704
+ }
1705
+ if ((match = matchers.rgba.exec(color))) {
1706
+ return { r: match[1], g: match[2], b: match[3], a: match[4] };
1707
+ }
1708
+ if ((match = matchers.hsl.exec(color))) {
1709
+ return { h: match[1], s: match[2], l: match[3] };
1710
+ }
1711
+ if ((match = matchers.hsla.exec(color))) {
1712
+ return { h: match[1], s: match[2], l: match[3], a: match[4] };
1713
+ }
1714
+ if ((match = matchers.hsv.exec(color))) {
1715
+ return { h: match[1], s: match[2], v: match[3] };
1716
+ }
1717
+ if ((match = matchers.hex6.exec(color))) {
1718
+ return {
1719
+ r: parseHex(match[1]),
1720
+ g: parseHex(match[2]),
1721
+ b: parseHex(match[3]),
1722
+ format: named ? "name" : "hex"
1723
+ };
1724
+ }
1725
+ if ((match = matchers.hex3.exec(color))) {
1726
+ return {
1727
+ r: parseHex(match[1] + '' + match[1]),
1728
+ g: parseHex(match[2] + '' + match[2]),
1729
+ b: parseHex(match[3] + '' + match[3]),
1730
+ format: named ? "name" : "hex"
1731
+ };
1732
+ }
1733
+
1734
+ return false;
1735
+ }
1736
+
1737
+ // Everything is ready, expose to window
1738
+ window.tinycolor = tinycolor;
1739
+
1740
+ })(this);
1741
+
1742
+ $(function () {
1743
+ if ($.fn.spectrum.load) {
1744
+ $.fn.spectrum.processNativeColorInputs();
1745
+ }
1746
+ });
1747
+
1748
+ })(window, jQuery);