...
...
@@ -0,0 +1,2259 @@
1
+// Spectrum Colorpicker v1.4.1
2
+// https://github.com/bgrins/spectrum
3
+// Author: Brian Grinstead
4
+// License: MIT
5
+
6
+(function (window, $, undefined) {
7
+ "use strict";
8
+
9
+ var defaultOpts = {
10
+
11
+ // Callbacks
12
+ beforeShow: noop,
13
+ move: noop,
14
+ change: noop,
15
+ show: noop,
16
+ hide: noop,
17
+
18
+ // Options
19
+ color: false,
20
+ flat: false,
21
+ showInput: false,
22
+ allowEmpty: false,
23
+ showButtons: true,
24
+ clickoutFiresChange: false,
25
+ showInitial: false,
26
+ showPalette: false,
27
+ showPaletteOnly: false,
28
+ hideAfterPaletteSelect: false,
29
+ togglePaletteOnly: false,
30
+ showSelectionPalette: true,
31
+ localStorageKey: false,
32
+ appendTo: "body",
33
+ maxSelectionSize: 7,
34
+ cancelText: "cancel",
35
+ chooseText: "choose",
36
+ togglePaletteMoreText: "more",
37
+ togglePaletteLessText: "less",
38
+ clearText: "Clear Color Selection",
39
+ noColorSelectedText: "No Color Selected",
40
+ preferredFormat: false,
41
+ className: "", // Deprecated - use containerClassName and replacerClassName instead.
42
+ containerClassName: "",
43
+ replacerClassName: "",
44
+ showAlpha: false,
45
+ theme: "sp-light",
46
+ palette: [["#ffffff", "#000000", "#ff0000", "#ff8000", "#ffff00", "#008000", "#0000ff", "#4b0082", "#9400d3"]],
47
+ selectionPalette: [],
48
+ disabled: false
49
+ },
50
+ spectrums = [],
51
+ IE = !!/msie/i.exec( window.navigator.userAgent ),
52
+ rgbaSupport = (function() {
53
+ function contains( str, substr ) {
54
+ return !!~('' + str).indexOf(substr);
55
+ }
56
+
57
+ var elem = document.createElement('div');
58
+ var style = elem.style;
59
+ style.cssText = 'background-color:rgba(0,0,0,.5)';
60
+ return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
61
+ })(),
62
+ inputTypeColorSupport = (function() {
63
+ var colorInput = $("<input type='color' value='!' />")[0];
64
+ return colorInput.type === "color" && colorInput.value !== "!";
65
+ })(),
66
+ replaceInput = [
67
+ "<div class='sp-replacer'>",
68
+ "<div class='sp-preview'><div class='sp-preview-inner'></div></div>",
69
+ "<div class='sp-dd'>▼</div>",
70
+ "</div>"
71
+ ].join(''),
72
+ markup = (function () {
73
+
74
+ // IE does not support gradients with multiple stops, so we need to simulate
75
+ // that for the rainbow slider with 8 divs that each have a single gradient
76
+ var gradientFix = "";
77
+ if (IE) {
78
+ for (var i = 1; i <= 6; i++) {
79
+ gradientFix += "<div class='sp-" + i + "'></div>";
80
+ }
81
+ }
82
+
83
+ return [
84
+ "<div class='sp-container sp-hidden'>",
85
+ "<div class='sp-palette-container'>",
86
+ "<div class='sp-palette sp-thumb sp-cf'></div>",
87
+ "<div class='sp-palette-button-container sp-cf'>",
88
+ "<button type='button' class='sp-palette-toggle'></button>",
89
+ "</div>",
90
+ "</div>",
91
+ "<div class='sp-picker-container'>",
92
+ "<div class='sp-top sp-cf'>",
93
+ "<div class='sp-fill'></div>",
94
+ "<div class='sp-top-inner'>",
95
+ "<div class='sp-color'>",
96
+ "<div class='sp-sat'>",
97
+ "<div class='sp-val'>",
98
+ "<div class='sp-dragger'></div>",
99
+ "</div>",
100
+ "</div>",
101
+ "</div>",
102
+ "<div class='sp-clear sp-clear-display'>",
103
+ "</div>",
104
+ "<div class='sp-hue'>",
105
+ "<div class='sp-slider'></div>",
106
+ gradientFix,
107
+ "</div>",
108
+ "</div>",
109
+ "<div class='sp-alpha'><div class='sp-alpha-inner'><div class='sp-alpha-handle'></div></div></div>",
110
+ "</div>",
111
+ "<div class='sp-input-container sp-cf'>",
112
+ "<input class='sp-input' type='text' spellcheck='false' />",
113
+ "</div>",
114
+ "<div class='sp-initial sp-thumb sp-cf'></div>",
115
+ "<div class='sp-button-container sp-cf'>",
116
+ "<a class='sp-cancel' href='#'></a>",
117
+ "<button type='button' class='sp-choose'></button>",
118
+ "</div>",
119
+ "</div>",
120
+ "</div>"
121
+ ].join("");
122
+ })();
123
+
124
+ function paletteTemplate (p, color, className, opts) {
125
+ var html = [];
126
+ for (var i = 0; i < p.length; i++) {
127
+ var current = p[i];
128
+ if(current) {
129
+ var tiny = tinycolor(current);
130
+ var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light";
131
+ c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : "";
132
+ var formattedString = tiny.toString(opts.preferredFormat || "rgb");
133
+ var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter();
134
+ html.push('<span title="' + formattedString + '" data-color="' + tiny.toRgbString() + '" class="' + c + '"><span class="sp-thumb-inner" style="' + swatchStyle + ';" /></span>');
135
+ } else {
136
+ var cls = 'sp-clear-display';
137
+ html.push($('<div />')
138
+ .append($('<span data-color="" style="background-color:transparent;" class="' + cls + '"></span>')
139
+ .attr('title', opts.noColorSelectedText)
140
+ )
141
+ .html()
142
+ );
143
+ }
144
+ }
145
+ return "<div class='sp-cf " + className + "'>" + html.join('') + "</div>";
146
+ }
147
+
148
+ function hideAll() {
149
+ for (var i = 0; i < spectrums.length; i++) {
150
+ if (spectrums[i]) {
151
+ spectrums[i].hide();
152
+ }
153
+ }
154
+ }
155
+
156
+ function instanceOptions(o, callbackContext) {
157
+ var opts = $.extend({}, defaultOpts, o);
158
+ opts.callbacks = {
159
+ 'move': bind(opts.move, callbackContext),
160
+ 'change': bind(opts.change, callbackContext),
161
+ 'show': bind(opts.show, callbackContext),
162
+ 'hide': bind(opts.hide, callbackContext),
163
+ 'beforeShow': bind(opts.beforeShow, callbackContext)
164
+ };
165
+
166
+ return opts;
167
+ }
168
+
169
+ function spectrum(element, o) {
170
+
171
+ var opts = instanceOptions(o, element),
172
+ flat = opts.flat,
173
+ showSelectionPalette = opts.showSelectionPalette,
174
+ localStorageKey = opts.localStorageKey,
175
+ theme = opts.theme,
176
+ callbacks = opts.callbacks,
177
+ resize = throttle(reflow, 10),
178
+ visible = false,
179
+ dragWidth = 0,
180
+ dragHeight = 0,
181
+ dragHelperHeight = 0,
182
+ slideHeight = 0,
183
+ slideWidth = 0,
184
+ alphaWidth = 0,
185
+ alphaSlideHelperWidth = 0,
186
+ slideHelperHeight = 0,
187
+ currentHue = 0,
188
+ currentSaturation = 0,
189
+ currentValue = 0,
190
+ currentAlpha = 1,
191
+ palette = [],
192
+ paletteArray = [],
193
+ paletteLookup = {},
194
+ selectionPalette = opts.selectionPalette.slice(0),
195
+ maxSelectionSize = opts.maxSelectionSize,
196
+ draggingClass = "sp-dragging",
197
+ shiftMovementDirection = null;
198
+
199
+ var doc = element.ownerDocument,
200
+ body = doc.body,
201
+ boundElement = $(element),
202
+ disabled = false,
203
+ container = $(markup, doc).addClass(theme),
204
+ pickerContainer = container.find(".sp-picker-container"),
205
+ dragger = container.find(".sp-color"),
206
+ dragHelper = container.find(".sp-dragger"),
207
+ slider = container.find(".sp-hue"),
208
+ slideHelper = container.find(".sp-slider"),
209
+ alphaSliderInner = container.find(".sp-alpha-inner"),
210
+ alphaSlider = container.find(".sp-alpha"),
211
+ alphaSlideHelper = container.find(".sp-alpha-handle"),
212
+ textInput = container.find(".sp-input"),
213
+ paletteContainer = container.find(".sp-palette"),
214
+ initialColorContainer = container.find(".sp-initial"),
215
+ cancelButton = container.find(".sp-cancel"),
216
+ clearButton = container.find(".sp-clear"),
217
+ chooseButton = container.find(".sp-choose"),
218
+ toggleButton = container.find(".sp-palette-toggle"),
219
+ isInput = boundElement.is("input"),
220
+ isInputTypeColor = isInput && inputTypeColorSupport && boundElement.attr("type") === "color",
221
+ shouldReplace = isInput && !flat,
222
+ replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]),
223
+ offsetElement = (shouldReplace) ? replacer : boundElement,
224
+ previewElement = replacer.find(".sp-preview-inner"),
225
+ initialColor = opts.color || (isInput && boundElement.val()),
226
+ colorOnShow = false,
227
+ preferredFormat = opts.preferredFormat,
228
+ currentPreferredFormat = preferredFormat,
229
+ clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange,
230
+ isEmpty = !initialColor,
231
+ allowEmpty = opts.allowEmpty && !isInputTypeColor;
232
+
233
+ function applyOptions() {
234
+
235
+ if (opts.showPaletteOnly) {
236
+ opts.showPalette = true;
237
+ }
238
+
239
+ toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText);
240
+
241
+ if (opts.palette) {
242
+ palette = opts.palette.slice(0);
243
+ paletteArray = $.isArray(palette[0]) ? palette : [palette];
244
+ paletteLookup = {};
245
+ for (var i = 0; i < paletteArray.length; i++) {
246
+ for (var j = 0; j < paletteArray[i].length; j++) {
247
+ var rgb = tinycolor(paletteArray[i][j]).toRgbString();
248
+ paletteLookup[rgb] = true;
249
+ }
250
+ }
251
+ }
252
+
253
+ container.toggleClass("sp-flat", flat);
254
+ container.toggleClass("sp-input-disabled", !opts.showInput);
255
+ container.toggleClass("sp-alpha-enabled", opts.showAlpha);
256
+ container.toggleClass("sp-clear-enabled", allowEmpty);
257
+ container.toggleClass("sp-buttons-disabled", !opts.showButtons);
258
+ container.toggleClass("sp-palette-buttons-disabled", !opts.togglePaletteOnly);
259
+ container.toggleClass("sp-palette-disabled", !opts.showPalette);
260
+ container.toggleClass("sp-palette-only", opts.showPaletteOnly);
261
+ container.toggleClass("sp-initial-disabled", !opts.showInitial);
262
+ container.addClass(opts.className).addClass(opts.containerClassName);
263
+
264
+ reflow();
265
+ }
266
+
267
+ function initialize() {
268
+
269
+ if (IE) {
270
+ container.find("*:not(input)").attr("unselectable", "on");
271
+ }
272
+
273
+ applyOptions();
274
+
275
+ if (shouldReplace) {
276
+ boundElement.after(replacer).hide();
277
+ }
278
+
279
+ if (!allowEmpty) {
280
+ clearButton.hide();
281
+ }
282
+
283
+ if (flat) {
284
+ boundElement.after(container).hide();
285
+ }
286
+ else {
287
+
288
+ var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo);
289
+ if (appendTo.length !== 1) {
290
+ appendTo = $("body");
291
+ }
292
+
293
+ appendTo.append(container);
294
+ }
295
+
296
+ updateSelectionPaletteFromStorage();
297
+
298
+ offsetElement.bind("click.spectrum touchstart.spectrum", function (e) {
299
+ if (!disabled) {
300
+ toggle();
301
+ }
302
+
303
+ e.stopPropagation();
304
+
305
+ if (!$(e.target).is("input")) {
306
+ e.preventDefault();
307
+ }
308
+ });
309
+
310
+ if(boundElement.is(":disabled") || (opts.disabled === true)) {
311
+ disable();
312
+ }
313
+
314
+ // Prevent clicks from bubbling up to document. This would cause it to be hidden.
315
+ container.click(stopPropagation);
316
+
317
+ // Handle user typed input
318
+ textInput.change(setFromTextInput);
319
+ textInput.bind("paste", function () {
320
+ setTimeout(setFromTextInput, 1);
321
+ });
322
+ textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } });
323
+
324
+ cancelButton.text(opts.cancelText);
325
+ cancelButton.bind("click.spectrum", function (e) {
326
+ e.stopPropagation();
327
+ e.preventDefault();
328
+ hide("cancel");
329
+ });
330
+
331
+ clearButton.attr("title", opts.clearText);
332
+ clearButton.bind("click.spectrum", function (e) {
333
+ e.stopPropagation();
334
+ e.preventDefault();
335
+ isEmpty = true;
336
+ move();
337
+
338
+ if(flat) {
339
+ //for the flat style, this is a change event
340
+ updateOriginalInput(true);
341
+ }
342
+ });
343
+
344
+ chooseButton.text(opts.chooseText);
345
+ chooseButton.bind("click.spectrum", function (e) {
346
+ e.stopPropagation();
347
+ e.preventDefault();
348
+
349
+ if (isValid()) {
350
+ updateOriginalInput(true);
351
+ hide();
352
+ }
353
+ });
354
+
355
+ toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText);
356
+ toggleButton.bind("click.spectrum", function (e) {
357
+ e.stopPropagation();
358
+ e.preventDefault();
359
+
360
+ opts.showPaletteOnly = !opts.showPaletteOnly;
361
+
362
+ // To make sure the Picker area is drawn on the right, next to the
363
+ // Palette area (and not below the palette), first move the Palette
364
+ // to the left to make space for the picker, plus 5px extra.
365
+ // The 'applyOptions' function puts the whole container back into place
366
+ // and takes care of the button-text and the sp-palette-only CSS class.
367
+ if (!opts.showPaletteOnly && !flat) {
368
+ container.css('left', '-=' + (pickerContainer.outerWidth(true) + 5));
369
+ }
370
+ applyOptions();
371
+ });
372
+
373
+ draggable(alphaSlider, function (dragX, dragY, e) {
374
+ currentAlpha = (dragX / alphaWidth);
375
+ isEmpty = false;
376
+ if (e.shiftKey) {
377
+ currentAlpha = Math.round(currentAlpha * 10) / 10;
378
+ }
379
+
380
+ move();
381
+ }, dragStart, dragStop);
382
+
383
+ draggable(slider, function (dragX, dragY) {
384
+ currentHue = parseFloat(dragY / slideHeight);
385
+ isEmpty = false;
386
+ if (!opts.showAlpha) {
387
+ currentAlpha = 1;
388
+ }
389
+ move();
390
+ }, dragStart, dragStop);
391
+
392
+ draggable(dragger, function (dragX, dragY, e) {
393
+
394
+ // shift+drag should snap the movement to either the x or y axis.
395
+ if (!e.shiftKey) {
396
+ shiftMovementDirection = null;
397
+ }
398
+ else if (!shiftMovementDirection) {
399
+ var oldDragX = currentSaturation * dragWidth;
400
+ var oldDragY = dragHeight - (currentValue * dragHeight);
401
+ var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY);
402
+
403
+ shiftMovementDirection = furtherFromX ? "x" : "y";
404
+ }
405
+
406
+ var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x";
407
+ var setValue = !shiftMovementDirection || shiftMovementDirection === "y";
408
+
409
+ if (setSaturation) {
410
+ currentSaturation = parseFloat(dragX / dragWidth);
411
+ }
412
+ if (setValue) {
413
+ currentValue = parseFloat((dragHeight - dragY) / dragHeight);
414
+ }
415
+
416
+ isEmpty = false;
417
+ if (!opts.showAlpha) {
418
+ currentAlpha = 1;
419
+ }
420
+
421
+ move();
422
+
423
+ }, dragStart, dragStop);
424
+
425
+ if (!!initialColor) {
426
+ set(initialColor);
427
+
428
+ // In case color was black - update the preview UI and set the format
429
+ // since the set function will not run (default color is black).
430
+ updateUI();
431
+ currentPreferredFormat = preferredFormat || tinycolor(initialColor).format;
432
+
433
+ addColorToSelectionPalette(initialColor);
434
+ }
435
+ else {
436
+ updateUI();
437
+ }
438
+
439
+ if (flat) {
440
+ show();
441
+ }
442
+
443
+ function paletteElementClick(e) {
444
+ if (e.data && e.data.ignore) {
445
+ set($(e.target).closest(".sp-thumb-el").data("color"));
446
+ move();
447
+ }
448
+ else {
449
+ set($(e.target).closest(".sp-thumb-el").data("color"));
450
+ move();
451
+ updateOriginalInput(true);
452
+ if (opts.hideAfterPaletteSelect) {
453
+ hide();
454
+ }
455
+ }
456
+
457
+ return false;
458
+ }
459
+
460
+ var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum";
461
+ paletteContainer.delegate(".sp-thumb-el", paletteEvent, paletteElementClick);
462
+ initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, paletteElementClick);
463
+ }
464
+
465
+ function updateSelectionPaletteFromStorage() {
466
+
467
+ if (localStorageKey && window.localStorage) {
468
+
469
+ // Migrate old palettes over to new format. May want to remove this eventually.
470
+ try {
471
+ var oldPalette = window.localStorage[localStorageKey].split(",#");
472
+ if (oldPalette.length > 1) {
473
+ delete window.localStorage[localStorageKey];
474
+ $.each(oldPalette, function(i, c) {
475
+ addColorToSelectionPalette(c);
476
+ });
477
+ }
478
+ }
479
+ catch(e) { }
480
+
481
+ try {
482
+ selectionPalette = window.localStorage[localStorageKey].split(";");
483
+ }
484
+ catch (e) { }
485
+ }
486
+ }
487
+
488
+ function addColorToSelectionPalette(color) {
489
+ if (showSelectionPalette) {
490
+ var rgb = tinycolor(color).toRgbString();
491
+ if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) {
492
+ selectionPalette.push(rgb);
493
+ while(selectionPalette.length > maxSelectionSize) {
494
+ selectionPalette.shift();
495
+ }
496
+ }
497
+
498
+ if (localStorageKey && window.localStorage) {
499
+ try {
500
+ window.localStorage[localStorageKey] = selectionPalette.join(";");
501
+ }
502
+ catch(e) { }
503
+ }
504
+ }
505
+ }
506
+
507
+ function getUniqueSelectionPalette() {
508
+ var unique = [];
509
+ if (opts.showPalette) {
510
+ for (var i = 0; i < selectionPalette.length; i++) {
511
+ var rgb = tinycolor(selectionPalette[i]).toRgbString();
512
+
513
+ if (!paletteLookup[rgb]) {
514
+ unique.push(selectionPalette[i]);
515
+ }
516
+ }
517
+ }
518
+
519
+ return unique.reverse().slice(0, opts.maxSelectionSize);
520
+ }
521
+
522
+ function drawPalette() {
523
+
524
+ var currentColor = get();
525
+
526
+ var html = $.map(paletteArray, function (palette, i) {
527
+ return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts);
528
+ });
529
+
530
+ updateSelectionPaletteFromStorage();
531
+
532
+ if (selectionPalette) {
533
+ html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts));
534
+ }
535
+
536
+ paletteContainer.html(html.join(""));
537
+ }
538
+
539
+ function drawInitial() {
540
+ if (opts.showInitial) {
541
+ var initial = colorOnShow;
542
+ var current = get();
543
+ initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts));
544
+ }
545
+ }
546
+
547
+ function dragStart() {
548
+ if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) {
549
+ reflow();
550
+ }
551
+ container.addClass(draggingClass);
552
+ shiftMovementDirection = null;
553
+ boundElement.trigger('dragstart.spectrum', [ get() ]);
554
+ }
555
+
556
+ function dragStop() {
557
+ container.removeClass(draggingClass);
558
+ boundElement.trigger('dragstop.spectrum', [ get() ]);
559
+ }
560
+
561
+ function setFromTextInput() {
562
+
563
+ var value = textInput.val();
564
+
565
+ if ((value === null || value === "") && allowEmpty) {
566
+ set(null);
567
+ updateOriginalInput(true);
568
+ }
569
+ else {
570
+ var tiny = tinycolor(value);
571
+ if (tiny.isValid()) {
572
+ set(tiny);
573
+ updateOriginalInput(true);
574
+ }
575
+ else {
576
+ textInput.addClass("sp-validation-error");
577
+ }
578
+ }
579
+ }
580
+
581
+ function toggle() {
582
+ if (visible) {
583
+ hide();
584
+ }
585
+ else {
586
+ show();
587
+ }
588
+ }
589
+
590
+ function show() {
591
+ var event = $.Event('beforeShow.spectrum');
592
+
593
+ if (visible) {
594
+ reflow();
595
+ return;
596
+ }
597
+
598
+ boundElement.trigger(event, [ get() ]);
599
+
600
+ if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) {
601
+ return;
602
+ }
603
+
604
+ hideAll();
605
+ visible = true;
606
+
607
+ $(doc).bind("click.spectrum", hide);
608
+ $(window).bind("resize.spectrum", resize);
609
+ replacer.addClass("sp-active");
610
+ container.removeClass("sp-hidden");
611
+
612
+ reflow();
613
+ updateUI();
614
+
615
+ colorOnShow = get();
616
+
617
+ drawInitial();
618
+ callbacks.show(colorOnShow);
619
+ boundElement.trigger('show.spectrum', [ colorOnShow ]);
620
+ }
621
+
622
+ function hide(e) {
623
+
624
+ // Return on right click
625
+ if (e && e.type == "click" && e.button == 2) { return; }
626
+
627
+ // Return if hiding is unnecessary
628
+ if (!visible || flat) { return; }
629
+ visible = false;
630
+
631
+ $(doc).unbind("click.spectrum", hide);
632
+ $(window).unbind("resize.spectrum", resize);
633
+
634
+ replacer.removeClass("sp-active");
635
+ container.addClass("sp-hidden");
636
+
637
+ var colorHasChanged = !tinycolor.equals(get(), colorOnShow);
638
+
639
+ if (colorHasChanged) {
640
+ if (clickoutFiresChange && e !== "cancel") {
641
+ updateOriginalInput(true);
642
+ }
643
+ else {
644
+ revert();
645
+ }
646
+ }
647
+
648
+ callbacks.hide(get());
649
+ boundElement.trigger('hide.spectrum', [ get() ]);
650
+ }
651
+
652
+ function revert() {
653
+ set(colorOnShow, true);
654
+ }
655
+
656
+ function set(color, ignoreFormatChange) {
657
+ if (tinycolor.equals(color, get())) {
658
+ // Update UI just in case a validation error needs
659
+ // to be cleared.
660
+ updateUI();
661
+ return;
662
+ }
663
+
664
+ var newColor, newHsv;
665
+ if (!color && allowEmpty) {
666
+ isEmpty = true;
667
+ } else {
668
+ isEmpty = false;
669
+ newColor = tinycolor(color);
670
+ newHsv = newColor.toHsv();
671
+
672
+ currentHue = (newHsv.h % 360) / 360;
673
+ currentSaturation = newHsv.s;
674
+ currentValue = newHsv.v;
675
+ currentAlpha = newHsv.a;
676
+ }
677
+ updateUI();
678
+
679
+ if (newColor && newColor.isValid() && !ignoreFormatChange) {
680
+ currentPreferredFormat = preferredFormat || newColor.getFormat();
681
+ }
682
+ }
683
+
684
+ function get(opts) {
685
+ opts = opts || { };
686
+
687
+ if (allowEmpty && isEmpty) {
688
+ return null;
689
+ }
690
+
691
+ return tinycolor.fromRatio({
692
+ h: currentHue,
693
+ s: currentSaturation,
694
+ v: currentValue,
695
+ a: Math.round(currentAlpha * 100) / 100
696
+ }, { format: opts.format || currentPreferredFormat });
697
+ }
698
+
699
+ function isValid() {
700
+ return !textInput.hasClass("sp-validation-error");
701
+ }
702
+
703
+ function move() {
704
+ updateUI();
705
+
706
+ callbacks.move(get());
707
+ boundElement.trigger('move.spectrum', [ get() ]);
708
+ }
709
+
710
+ function updateUI() {
711
+
712
+ textInput.removeClass("sp-validation-error");
713
+
714
+ updateHelperLocations();
715
+
716
+ // Update dragger background color (gradients take care of saturation and value).
717
+ var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 });
718
+ dragger.css("background-color", flatColor.toHexString());
719
+
720
+ // Get a format that alpha will be included in (hex and names ignore alpha)
721
+ var format = currentPreferredFormat;
722
+ if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) {
723
+ if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") {
724
+ format = "rgb";
725
+ }
726
+ }
727
+
728
+ var realColor = get({ format: format }),
729
+ displayColor = '';
730
+
731
+ //reset background info for preview element
732
+ previewElement.removeClass("sp-clear-display");
733
+ previewElement.css('background-color', 'transparent');
734
+
735
+ if (!realColor && allowEmpty) {
736
+ // Update the replaced elements background with icon indicating no color selection
737
+ previewElement.addClass("sp-clear-display");
738
+ }
739
+ else {
740
+ var realHex = realColor.toHexString(),
741
+ realRgb = realColor.toRgbString();
742
+
743
+ // Update the replaced elements background color (with actual selected color)
744
+ if (rgbaSupport || realColor.alpha === 1) {
745
+ previewElement.css("background-color", realRgb);
746
+ }
747
+ else {
748
+ previewElement.css("background-color", "transparent");
749
+ previewElement.css("filter", realColor.toFilter());
750
+ }
751
+
752
+ if (opts.showAlpha) {
753
+ var rgb = realColor.toRgb();
754
+ rgb.a = 0;
755
+ var realAlpha = tinycolor(rgb).toRgbString();
756
+ var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")";
757
+
758
+ if (IE) {
759
+ alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex));
760
+ }
761
+ else {
762
+ alphaSliderInner.css("background", "-webkit-" + gradient);
763
+ alphaSliderInner.css("background", "-moz-" + gradient);
764
+ alphaSliderInner.css("background", "-ms-" + gradient);
765
+ // Use current syntax gradient on unprefixed property.
766
+ alphaSliderInner.css("background",
767
+ "linear-gradient(to right, " + realAlpha + ", " + realHex + ")");
768
+ }
769
+ }
770
+
771
+ displayColor = realColor.toString(format);
772
+ }
773
+
774
+ // Update the text entry input as it changes happen
775
+ if (opts.showInput) {
776
+ textInput.val(displayColor);
777
+ }
778
+
779
+ if (opts.showPalette) {
780
+ drawPalette();
781
+ }
782
+
783
+ drawInitial();
784
+ }
785
+
786
+ function updateHelperLocations() {
787
+ var s = currentSaturation;
788
+ var v = currentValue;
789
+
790
+ if(allowEmpty && isEmpty) {
791
+ //if selected color is empty, hide the helpers
792
+ alphaSlideHelper.hide();
793
+ slideHelper.hide();
794
+ dragHelper.hide();
795
+ }
796
+ else {
797
+ //make sure helpers are visible
798
+ alphaSlideHelper.show();
799
+ slideHelper.show();
800
+ dragHelper.show();
801
+
802
+ // Where to show the little circle in that displays your current selected color
803
+ var dragX = s * dragWidth;
804
+ var dragY = dragHeight - (v * dragHeight);
805
+ dragX = Math.max(
806
+ -dragHelperHeight,
807
+ Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight)
808
+ );
809
+ dragY = Math.max(
810
+ -dragHelperHeight,
811
+ Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight)
812
+ );
813
+ dragHelper.css({
814
+ "top": dragY + "px",
815
+ "left": dragX + "px"
816
+ });
817
+
818
+ var alphaX = currentAlpha * alphaWidth;
819
+ alphaSlideHelper.css({
820
+ "left": (alphaX - (alphaSlideHelperWidth / 2)) + "px"
821
+ });
822
+
823
+ // Where to show the bar that displays your current selected hue
824
+ var slideY = (currentHue) * slideHeight;
825
+ slideHelper.css({
826
+ "top": (slideY - slideHelperHeight) + "px"
827
+ });
828
+ }
829
+ }
830
+
831
+ function updateOriginalInput(fireCallback) {
832
+ var color = get(),
833
+ displayColor = '',
834
+ hasChanged = !tinycolor.equals(color, colorOnShow);
835
+
836
+ if (color) {
837
+ displayColor = color.toString(currentPreferredFormat);
838
+ // Update the selection palette with the current color
839
+ addColorToSelectionPalette(color);
840
+ }
841
+
842
+ if (isInput) {
843
+ boundElement.val(displayColor);
844
+ }
845
+
846
+ colorOnShow = color;
847
+
848
+ if (fireCallback && hasChanged) {
849
+ callbacks.change(color);
850
+ boundElement.trigger('change', [ color ]);
851
+ }
852
+ }
853
+
854
+ function reflow() {
855
+ dragWidth = dragger.width();
856
+ dragHeight = dragger.height();
857
+ dragHelperHeight = dragHelper.height();
858
+ slideWidth = slider.width();
859
+ slideHeight = slider.height();
860
+ slideHelperHeight = slideHelper.height();
861
+ alphaWidth = alphaSlider.width();
862
+ alphaSlideHelperWidth = alphaSlideHelper.width();
863
+
864
+ if (!flat) {
865
+ container.css("position", "absolute");
866
+ container.offset(getOffset(container, offsetElement));
867
+ }
868
+
869
+ updateHelperLocations();
870
+
871
+ if (opts.showPalette) {
872
+ drawPalette();
873
+ }
874
+
875
+ boundElement.trigger('reflow.spectrum');
876
+ }
877
+
878
+ function destroy() {
879
+ boundElement.show();
880
+ offsetElement.unbind("click.spectrum touchstart.spectrum");
881
+ container.remove();
882
+ replacer.remove();
883
+ spectrums[spect.id] = null;
884
+ }
885
+
886
+ function option(optionName, optionValue) {
887
+ if (optionName === undefined) {
888
+ return $.extend({}, opts);
889
+ }
890
+ if (optionValue === undefined) {
891
+ return opts[optionName];
892
+ }
893
+
894
+ opts[optionName] = optionValue;
895
+ applyOptions();
896
+ }
897
+
898
+ function enable() {
899
+ disabled = false;
900
+ boundElement.attr("disabled", false);
901
+ offsetElement.removeClass("sp-disabled");
902
+ }
903
+
904
+ function disable() {
905
+ hide();
906
+ disabled = true;
907
+ boundElement.attr("disabled", true);
908
+ offsetElement.addClass("sp-disabled");
909
+ }
910
+
911
+ initialize();
912
+
913
+ var spect = {
914
+ show: show,
915
+ hide: hide,
916
+ toggle: toggle,
917
+ reflow: reflow,
918
+ option: option,
919
+ enable: enable,
920
+ disable: disable,
921
+ set: function (c) {
922
+ set(c);
923
+ updateOriginalInput();
924
+ },
925
+ get: get,
926
+ destroy: destroy,
927
+ container: container
928
+ };
929
+
930
+ spect.id = spectrums.push(spect) - 1;
931
+
932
+ return spect;
933
+ }
934
+
935
+ /**
936
+ * checkOffset - get the offset below/above and left/right element depending on screen position
937
+ * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js
938
+ */
939
+ function getOffset(picker, input) {
940
+ var extraY = 0;
941
+ var dpWidth = picker.outerWidth();
942
+ var dpHeight = picker.outerHeight();
943
+ var inputHeight = input.outerHeight();
944
+ var doc = picker[0].ownerDocument;
945
+ var docElem = doc.documentElement;
946
+ var viewWidth = docElem.clientWidth + $(doc).scrollLeft();
947
+ var viewHeight = docElem.clientHeight + $(doc).scrollTop();
948
+ var offset = input.offset();
949
+ offset.top += inputHeight;
950
+
951
+ offset.left -=
952
+ Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
953
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
954
+
955
+ offset.top -=
956
+ Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
957
+ Math.abs(dpHeight + inputHeight - extraY) : extraY));
958
+
959
+ return offset;
960
+ }
961
+
962
+ /**
963
+ * noop - do nothing
964
+ */
965
+ function noop() {
966
+
967
+ }
968
+
969
+ /**
970
+ * stopPropagation - makes the code only doing this a little easier to read in line
971
+ */
972
+ function stopPropagation(e) {
973
+ e.stopPropagation();
974
+ }
975
+
976
+ /**
977
+ * Create a function bound to a given object
978
+ * Thanks to underscore.js
979
+ */
980
+ function bind(func, obj) {
981
+ var slice = Array.prototype.slice;
982
+ var args = slice.call(arguments, 2);
983
+ return function () {
984
+ return func.apply(obj, args.concat(slice.call(arguments)));
985
+ };
986
+ }
987
+
988
+ /**
989
+ * Lightweight drag helper. Handles containment within the element, so that
990
+ * when dragging, the x is within [0,element.width] and y is within [0,element.height]
991
+ */
992
+ function draggable(element, onmove, onstart, onstop) {
993
+ onmove = onmove || function () { };
994
+ onstart = onstart || function () { };
995
+ onstop = onstop || function () { };
996
+ var doc = element.ownerDocument || document;
997
+ var dragging = false;
998
+ var offset = {};
999
+ var maxHeight = 0;
1000
+ var maxWidth = 0;
1001
+ var hasTouch = ('ontouchstart' in window);
1002
+
1003
+ var duringDragEvents = {};
1004
+ duringDragEvents["selectstart"] = prevent;
1005
+ duringDragEvents["dragstart"] = prevent;
1006
+ duringDragEvents["touchmove mousemove"] = move;
1007
+ duringDragEvents["touchend mouseup"] = stop;
1008
+
1009
+ function prevent(e) {
1010
+ if (e.stopPropagation) {
1011
+ e.stopPropagation();
1012
+ }
1013
+ if (e.preventDefault) {
1014
+ e.preventDefault();
1015
+ }
1016
+ e.returnValue = false;
1017
+ }
1018
+
1019
+ function move(e) {
1020
+ if (dragging) {
1021
+ // Mouseup happened outside of window
1022
+ if (IE && document.documentMode < 9 && !e.button) {
1023
+ return stop();
1024
+ }
1025
+
1026
+ var touches = e.originalEvent.touches;
1027
+ var pageX = touches ? touches[0].pageX : e.pageX;
1028
+ var pageY = touches ? touches[0].pageY : e.pageY;
1029
+
1030
+ var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth));
1031
+ var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight));
1032
+
1033
+ if (hasTouch) {
1034
+ // Stop scrolling in iOS
1035
+ prevent(e);
1036
+ }
1037
+
1038
+ onmove.apply(element, [dragX, dragY, e]);
1039
+ }
1040
+ }
1041
+
1042
+ function start(e) {
1043
+ var rightclick = (e.which) ? (e.which == 3) : (e.button == 2);
1044
+ var touches = e.originalEvent.touches;
1045
+
1046
+ if (!rightclick && !dragging) {
1047
+ if (onstart.apply(element, arguments) !== false) {
1048
+ dragging = true;
1049
+ maxHeight = $(element).height();
1050
+ maxWidth = $(element).width();
1051
+ offset = $(element).offset();
1052
+
1053
+ $(doc).bind(duringDragEvents);
1054
+ $(doc.body).addClass("sp-dragging");
1055
+
1056
+ if (!hasTouch) {
1057
+ move(e);
1058
+ }
1059
+
1060
+ prevent(e);
1061
+ }
1062
+ }
1063
+ }
1064
+
1065
+ function stop() {
1066
+ if (dragging) {
1067
+ $(doc).unbind(duringDragEvents);
1068
+ $(doc.body).removeClass("sp-dragging");
1069
+ onstop.apply(element, arguments);
1070
+ }
1071
+ dragging = false;
1072
+ }
1073
+
1074
+ $(element).bind("touchstart mousedown", start);
1075
+ }
1076
+
1077
+ function throttle(func, wait, debounce) {
1078
+ var timeout;
1079
+ return function () {
1080
+ var context = this, args = arguments;
1081
+ var throttler = function () {
1082
+ timeout = null;
1083
+ func.apply(context, args);
1084
+ };
1085
+ if (debounce) clearTimeout(timeout);
1086
+ if (debounce || !timeout) timeout = setTimeout(throttler, wait);
1087
+ };
1088
+ }
1089
+
1090
+ /**
1091
+ * Define a jQuery plugin
1092
+ */
1093
+ var dataID = "spectrum.id";
1094
+ $.fn.spectrum = function (opts, extra) {
1095
+
1096
+ if (typeof opts == "string") {
1097
+
1098
+ var returnValue = this;
1099
+ var args = Array.prototype.slice.call( arguments, 1 );
1100
+
1101
+ this.each(function () {
1102
+ var spect = spectrums[$(this).data(dataID)];
1103
+ if (spect) {
1104
+ var method = spect[opts];
1105
+ if (!method) {
1106
+ throw new Error( "Spectrum: no such method: '" + opts + "'" );
1107
+ }
1108
+
1109
+ if (opts == "get") {
1110
+ returnValue = spect.get();
1111
+ }
1112
+ else if (opts == "container") {
1113
+ returnValue = spect.container;
1114
+ }
1115
+ else if (opts == "option") {
1116
+ returnValue = spect.option.apply(spect, args);
1117
+ }
1118
+ else if (opts == "destroy") {
1119
+ spect.destroy();
1120
+ $(this).removeData(dataID);
1121
+ }
1122
+ else {
1123
+ method.apply(spect, args);
1124
+ }
1125
+ }
1126
+ });
1127
+
1128
+ return returnValue;
1129
+ }
1130
+
1131
+ // Initializing a new instance of spectrum
1132
+ return this.spectrum("destroy").each(function () {
1133
+ var options = $.extend({}, opts, $(this).data());
1134
+ var spect = spectrum(this, options);
1135
+ $(this).data(dataID, spect.id);
1136
+ });
1137
+ };
1138
+
1139
+ $.fn.spectrum.load = true;
1140
+ $.fn.spectrum.loadOpts = {};
1141
+ $.fn.spectrum.draggable = draggable;
1142
+ $.fn.spectrum.defaults = defaultOpts;
1143
+
1144
+ $.spectrum = { };
1145
+ $.spectrum.localization = { };
1146
+ $.spectrum.palettes = { };
1147
+
1148
+ $.fn.spectrum.processNativeColorInputs = function () {
1149
+ if (!inputTypeColorSupport) {
1150
+ $("input[type=color]").spectrum({
1151
+ preferredFormat: "hex6"
1152
+ });
1153
+ }
1154
+ };
1155
+
1156
+ // TinyColor v1.0.0
1157
+ // https://github.com/bgrins/TinyColor
1158
+ // Brian Grinstead, MIT License
1159
+
1160
+ (function() {
1161
+
1162
+ var trimLeft = /^[\s,#]+/,
1163
+ trimRight = /\s+$/,
1164
+ tinyCounter = 0,
1165
+ math = Math,
1166
+ mathRound = math.round,
1167
+ mathMin = math.min,
1168
+ mathMax = math.max,
1169
+ mathRandom = math.random;
1170
+
1171
+ var tinycolor = function tinycolor (color, opts) {
1172
+
1173
+ color = (color) ? color : '';
1174
+ opts = opts || { };
1175
+
1176
+ // If input is already a tinycolor, return itself
1177
+ if (color instanceof tinycolor) {
1178
+ return color;
1179
+ }
1180
+ // If we are called as a function, call using new instead
1181
+ if (!(this instanceof tinycolor)) {
1182
+ return new tinycolor(color, opts);
1183
+ }
1184
+
1185
+ var rgb = inputToRGB(color);
1186
+ this._r = rgb.r,
1187
+ this._g = rgb.g,
1188
+ this._b = rgb.b,
1189
+ this._a = rgb.a,
1190
+ this._roundA = mathRound(100*this._a) / 100,
1191
+ this._format = opts.format || rgb.format;
1192
+ this._gradientType = opts.gradientType;
1193
+
1194
+ // Don't let the range of [0,255] come back in [0,1].
1195
+ // Potentially lose a little bit of precision here, but will fix issues where
1196
+ // .5 gets interpreted as half of the total, instead of half of 1
1197
+ // If it was supposed to be 128, this was already taken care of by `inputToRgb`
1198
+ if (this._r < 1) { this._r = mathRound(this._r); }
1199
+ if (this._g < 1) { this._g = mathRound(this._g); }
1200
+ if (this._b < 1) { this._b = mathRound(this._b); }
1201
+
1202
+ this._ok = rgb.ok;
1203
+ this._tc_id = tinyCounter++;
1204
+ };
1205
+
1206
+ tinycolor.prototype = {
1207
+ isDark: function() {
1208
+ return this.getBrightness() < 128;
1209
+ },
1210
+ isLight: function() {
1211
+ return !this.isDark();
1212
+ },
1213
+ isValid: function() {
1214
+ return this._ok;
1215
+ },
1216
+ getFormat: function() {
1217
+ return this._format;
1218
+ },
1219
+ getAlpha: function() {
1220
+ return this._a;
1221
+ },
1222
+ getBrightness: function() {
1223
+ var rgb = this.toRgb();
1224
+ return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
1225
+ },
1226
+ setAlpha: function(value) {
1227
+ this._a = boundAlpha(value);
1228
+ this._roundA = mathRound(100*this._a) / 100;
1229
+ return this;
1230
+ },
1231
+ toHsv: function() {
1232
+ var hsv = rgbToHsv(this._r, this._g, this._b);
1233
+ return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a };
1234
+ },
1235
+ toHsvString: function() {
1236
+ var hsv = rgbToHsv(this._r, this._g, this._b);
1237
+ var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
1238
+ return (this._a == 1) ?
1239
+ "hsv(" + h + ", " + s + "%, " + v + "%)" :
1240
+ "hsva(" + h + ", " + s + "%, " + v + "%, "+ this._roundA + ")";
1241
+ },
1242
+ toHsl: function() {
1243
+ var hsl = rgbToHsl(this._r, this._g, this._b);
1244
+ return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a };
1245
+ },
1246
+ toHslString: function() {
1247
+ var hsl = rgbToHsl(this._r, this._g, this._b);
1248
+ var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
1249
+ return (this._a == 1) ?
1250
+ "hsl(" + h + ", " + s + "%, " + l + "%)" :
1251
+ "hsla(" + h + ", " + s + "%, " + l + "%, "+ this._roundA + ")";
1252
+ },
1253
+ toHex: function(allow3Char) {
1254
+ return rgbToHex(this._r, this._g, this._b, allow3Char);
1255
+ },
1256
+ toHexString: function(allow3Char) {
1257
+ return '#' + this.toHex(allow3Char);
1258
+ },
1259
+ toHex8: function() {
1260
+ return rgbaToHex(this._r, this._g, this._b, this._a);
1261
+ },
1262
+ toHex8String: function() {
1263
+ return '#' + this.toHex8();
1264
+ },
1265
+ toRgb: function() {
1266
+ return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a };
1267
+ },
1268
+ toRgbString: function() {
1269
+ return (this._a == 1) ?
1270
+ "rgb(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ")" :
1271
+ "rgba(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ", " + this._roundA + ")";
1272
+ },
1273
+ toPercentageRgb: function() {
1274
+ return { r: mathRound(bound01(this._r, 255) * 100) + "%", g: mathRound(bound01(this._g, 255) * 100) + "%", b: mathRound(bound01(this._b, 255) * 100) + "%", a: this._a };
1275
+ },
1276
+ toPercentageRgbString: function() {
1277
+ return (this._a == 1) ?
1278
+ "rgb(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%)" :
1279
+ "rgba(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")";
1280
+ },
1281
+ toName: function() {
1282
+ if (this._a === 0) {
1283
+ return "transparent";
1284
+ }
1285
+
1286
+ if (this._a < 1) {
1287
+ return false;
1288
+ }
1289
+
1290
+ return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false;
1291
+ },
1292
+ toFilter: function(secondColor) {
1293
+ var hex8String = '#' + rgbaToHex(this._r, this._g, this._b, this._a);
1294
+ var secondHex8String = hex8String;
1295
+ var gradientType = this._gradientType ? "GradientType = 1, " : "";
1296
+
1297
+ if (secondColor) {
1298
+ var s = tinycolor(secondColor);
1299
+ secondHex8String = s.toHex8String();
1300
+ }
1301
+
1302
+ return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")";
1303
+ },
1304
+ toString: function(format) {
1305
+ var formatSet = !!format;
1306
+ format = format || this._format;
1307
+
1308
+ var formattedString = false;
1309
+ var hasAlpha = this._a < 1 && this._a >= 0;
1310
+ var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "name");
1311
+
1312
+ if (needsAlphaFormat) {
1313
+ // Special case for "transparent", all other non-alpha formats
1314
+ // will return rgba when there is transparency.
1315
+ if (format === "name" && this._a === 0) {
1316
+ return this.toName();
1317
+ }
1318
+ return this.toRgbString();
1319
+ }
1320
+ if (format === "rgb") {
1321
+ formattedString = this.toRgbString();
1322
+ }
1323
+ if (format === "prgb") {
1324
+ formattedString = this.toPercentageRgbString();
1325
+ }
1326
+ if (format === "hex" || format === "hex6") {
1327
+ formattedString = this.toHexString();
1328
+ }
1329
+ if (format === "hex3") {
1330
+ formattedString = this.toHexString(true);
1331
+ }
1332
+ if (format === "hex8") {
1333
+ formattedString = this.toHex8String();
1334
+ }
1335
+ if (format === "name") {
1336
+ formattedString = this.toName();
1337
+ }
1338
+ if (format === "hsl") {
1339
+ formattedString = this.toHslString();
1340
+ }
1341
+ if (format === "hsv") {
1342
+ formattedString = this.toHsvString();
1343
+ }
1344
+
1345
+ return formattedString || this.toHexString();
1346
+ },
1347
+
1348
+ _applyModification: function(fn, args) {
1349
+ var color = fn.apply(null, [this].concat([].slice.call(args)));
1350
+ this._r = color._r;
1351
+ this._g = color._g;
1352
+ this._b = color._b;
1353
+ this.setAlpha(color._a);
1354
+ return this;
1355
+ },
1356
+ lighten: function() {
1357
+ return this._applyModification(lighten, arguments);
1358
+ },
1359
+ brighten: function() {
1360
+ return this._applyModification(brighten, arguments);
1361
+ },
1362
+ darken: function() {
1363
+ return this._applyModification(darken, arguments);
1364
+ },
1365
+ desaturate: function() {
1366
+ return this._applyModification(desaturate, arguments);
1367
+ },
1368
+ saturate: function() {
1369
+ return this._applyModification(saturate, arguments);
1370
+ },
1371
+ greyscale: function() {
1372
+ return this._applyModification(greyscale, arguments);
1373
+ },
1374
+ spin: function() {
1375
+ return this._applyModification(spin, arguments);
1376
+ },
1377
+
1378
+ _applyCombination: function(fn, args) {
1379
+ return fn.apply(null, [this].concat([].slice.call(args)));
1380
+ },
1381
+ analogous: function() {
1382
+ return this._applyCombination(analogous, arguments);
1383
+ },
1384
+ complement: function() {
1385
+ return this._applyCombination(complement, arguments);
1386
+ },
1387
+ monochromatic: function() {
1388
+ return this._applyCombination(monochromatic, arguments);
1389
+ },
1390
+ splitcomplement: function() {
1391
+ return this._applyCombination(splitcomplement, arguments);
1392
+ },
1393
+ triad: function() {
1394
+ return this._applyCombination(triad, arguments);
1395
+ },
1396
+ tetrad: function() {
1397
+ return this._applyCombination(tetrad, arguments);
1398
+ }
1399
+ };
1400
+
1401
+ // If input is an object, force 1 into "1.0" to handle ratios properly
1402
+ // String input requires "1.0" as input, so 1 will be treated as 1
1403
+ tinycolor.fromRatio = function(color, opts) {
1404
+ if (typeof color == "object") {
1405
+ var newColor = {};
1406
+ for (var i in color) {
1407
+ if (color.hasOwnProperty(i)) {
1408
+ if (i === "a") {
1409
+ newColor[i] = color[i];
1410
+ }
1411
+ else {
1412
+ newColor[i] = convertToPercentage(color[i]);
1413
+ }
1414
+ }
1415
+ }
1416
+ color = newColor;
1417
+ }
1418
+
1419
+ return tinycolor(color, opts);
1420
+ };
1421
+
1422
+ // Given a string or object, convert that input to RGB
1423
+ // Possible string inputs:
1424
+ //
1425
+ // "red"
1426
+ // "#f00" or "f00"
1427
+ // "#ff0000" or "ff0000"
1428
+ // "#ff000000" or "ff000000"
1429
+ // "rgb 255 0 0" or "rgb (255, 0, 0)"
1430
+ // "rgb 1.0 0 0" or "rgb (1, 0, 0)"
1431
+ // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
1432
+ // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
1433
+ // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
1434
+ // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
1435
+ // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
1436
+ //
1437
+ function inputToRGB(color) {
1438
+
1439
+ var rgb = { r: 0, g: 0, b: 0 };
1440
+ var a = 1;
1441
+ var ok = false;
1442
+ var format = false;
1443
+
1444
+ if (typeof color == "string") {
1445
+ color = stringInputToObject(color);
1446
+ }
1447
+
1448
+ if (typeof color == "object") {
1449
+ if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) {
1450
+ rgb = rgbToRgb(color.r, color.g, color.b);
1451
+ ok = true;
1452
+ format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
1453
+ }
1454
+ else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
1455
+ color.s = convertToPercentage(color.s);
1456
+ color.v = convertToPercentage(color.v);
1457
+ rgb = hsvToRgb(color.h, color.s, color.v);
1458
+ ok = true;
1459
+ format = "hsv";
1460
+ }
1461
+ else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
1462
+ color.s = convertToPercentage(color.s);
1463
+ color.l = convertToPercentage(color.l);
1464
+ rgb = hslToRgb(color.h, color.s, color.l);
1465
+ ok = true;
1466
+ format = "hsl";
1467
+ }
1468
+
1469
+ if (color.hasOwnProperty("a")) {
1470
+ a = color.a;
1471
+ }
1472
+ }
1473
+
1474
+ a = boundAlpha(a);
1475
+
1476
+ return {
1477
+ ok: ok,
1478
+ format: color.format || format,
1479
+ r: mathMin(255, mathMax(rgb.r, 0)),
1480
+ g: mathMin(255, mathMax(rgb.g, 0)),
1481
+ b: mathMin(255, mathMax(rgb.b, 0)),
1482
+ a: a
1483
+ };
1484
+ }
1485
+
1486
+
1487
+ // Conversion Functions
1488
+ // --------------------
1489
+
1490
+ // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
1491
+ // <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
1492
+
1493
+ // `rgbToRgb`
1494
+ // Handle bounds / percentage checking to conform to CSS color spec
1495
+ // <http://www.w3.org/TR/css3-color/>
1496
+ // *Assumes:* r, g, b in [0, 255] or [0, 1]
1497
+ // *Returns:* { r, g, b } in [0, 255]
1498
+ function rgbToRgb(r, g, b){
1499
+ return {
1500
+ r: bound01(r, 255) * 255,
1501
+ g: bound01(g, 255) * 255,
1502
+ b: bound01(b, 255) * 255
1503
+ };
1504
+ }
1505
+
1506
+ // `rgbToHsl`
1507
+ // Converts an RGB color value to HSL.
1508
+ // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
1509
+ // *Returns:* { h, s, l } in [0,1]
1510
+ function rgbToHsl(r, g, b) {
1511
+
1512
+ r = bound01(r, 255);
1513
+ g = bound01(g, 255);
1514
+ b = bound01(b, 255);
1515
+
1516
+ var max = mathMax(r, g, b), min = mathMin(r, g, b);
1517
+ var h, s, l = (max + min) / 2;
1518
+
1519
+ if(max == min) {
1520
+ h = s = 0; // achromatic
1521
+ }
1522
+ else {
1523
+ var d = max - min;
1524
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1525
+ switch(max) {
1526
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1527
+ case g: h = (b - r) / d + 2; break;
1528
+ case b: h = (r - g) / d + 4; break;
1529
+ }
1530
+
1531
+ h /= 6;
1532
+ }
1533
+
1534
+ return { h: h, s: s, l: l };
1535
+ }
1536
+
1537
+ // `hslToRgb`
1538
+ // Converts an HSL color value to RGB.
1539
+ // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
1540
+ // *Returns:* { r, g, b } in the set [0, 255]
1541
+ function hslToRgb(h, s, l) {
1542
+ var r, g, b;
1543
+
1544
+ h = bound01(h, 360);
1545
+ s = bound01(s, 100);
1546
+ l = bound01(l, 100);
1547
+
1548
+ function hue2rgb(p, q, t) {
1549
+ if(t < 0) t += 1;
1550
+ if(t > 1) t -= 1;
1551
+ if(t < 1/6) return p + (q - p) * 6 * t;
1552
+ if(t < 1/2) return q;
1553
+ if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
1554
+ return p;
1555
+ }
1556
+
1557
+ if(s === 0) {
1558
+ r = g = b = l; // achromatic
1559
+ }
1560
+ else {
1561
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1562
+ var p = 2 * l - q;
1563
+ r = hue2rgb(p, q, h + 1/3);
1564
+ g = hue2rgb(p, q, h);
1565
+ b = hue2rgb(p, q, h - 1/3);
1566
+ }
1567
+
1568
+ return { r: r * 255, g: g * 255, b: b * 255 };
1569
+ }
1570
+
1571
+ // `rgbToHsv`
1572
+ // Converts an RGB color value to HSV
1573
+ // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
1574
+ // *Returns:* { h, s, v } in [0,1]
1575
+ function rgbToHsv(r, g, b) {
1576
+
1577
+ r = bound01(r, 255);
1578
+ g = bound01(g, 255);
1579
+ b = bound01(b, 255);
1580
+
1581
+ var max = mathMax(r, g, b), min = mathMin(r, g, b);
1582
+ var h, s, v = max;
1583
+
1584
+ var d = max - min;
1585
+ s = max === 0 ? 0 : d / max;
1586
+
1587
+ if(max == min) {
1588
+ h = 0; // achromatic
1589
+ }
1590
+ else {
1591
+ switch(max) {
1592
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1593
+ case g: h = (b - r) / d + 2; break;
1594
+ case b: h = (r - g) / d + 4; break;
1595
+ }
1596
+ h /= 6;
1597
+ }
1598
+ return { h: h, s: s, v: v };
1599
+ }
1600
+
1601
+ // `hsvToRgb`
1602
+ // Converts an HSV color value to RGB.
1603
+ // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
1604
+ // *Returns:* { r, g, b } in the set [0, 255]
1605
+ function hsvToRgb(h, s, v) {
1606
+
1607
+ h = bound01(h, 360) * 6;
1608
+ s = bound01(s, 100);
1609
+ v = bound01(v, 100);
1610
+
1611
+ var i = math.floor(h),
1612
+ f = h - i,
1613
+ p = v * (1 - s),
1614
+ q = v * (1 - f * s),
1615
+ t = v * (1 - (1 - f) * s),
1616
+ mod = i % 6,
1617
+ r = [v, q, p, p, t, v][mod],
1618
+ g = [t, v, v, q, p, p][mod],
1619
+ b = [p, p, t, v, v, q][mod];
1620
+
1621
+ return { r: r * 255, g: g * 255, b: b * 255 };
1622
+ }
1623
+
1624
+ // `rgbToHex`
1625
+ // Converts an RGB color to hex
1626
+ // Assumes r, g, and b are contained in the set [0, 255]
1627
+ // Returns a 3 or 6 character hex
1628
+ function rgbToHex(r, g, b, allow3Char) {
1629
+
1630
+ var hex = [
1631
+ pad2(mathRound(r).toString(16)),
1632
+ pad2(mathRound(g).toString(16)),
1633
+ pad2(mathRound(b).toString(16))
1634
+ ];
1635
+
1636
+ // Return a 3 character hex if possible
1637
+ if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
1638
+ return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
1639
+ }
1640
+
1641
+ return hex.join("");
1642
+ }
1643
+ // `rgbaToHex`
1644
+ // Converts an RGBA color plus alpha transparency to hex
1645
+ // Assumes r, g, b and a are contained in the set [0, 255]
1646
+ // Returns an 8 character hex
1647
+ function rgbaToHex(r, g, b, a) {
1648
+
1649
+ var hex = [
1650
+ pad2(convertDecimalToHex(a)),
1651
+ pad2(mathRound(r).toString(16)),
1652
+ pad2(mathRound(g).toString(16)),
1653
+ pad2(mathRound(b).toString(16))
1654
+ ];
1655
+
1656
+ return hex.join("");
1657
+ }
1658
+
1659
+ // `equals`
1660
+ // Can be called with any tinycolor input
1661
+ tinycolor.equals = function (color1, color2) {
1662
+ if (!color1 || !color2) { return false; }
1663
+ return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
1664
+ };
1665
+ tinycolor.random = function() {
1666
+ return tinycolor.fromRatio({
1667
+ r: mathRandom(),
1668
+ g: mathRandom(),
1669
+ b: mathRandom()
1670
+ });
1671
+ };
1672
+
1673
+
1674
+ // Modification Functions
1675
+ // ----------------------
1676
+ // Thanks to less.js for some of the basics here
1677
+ // <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>
1678
+
1679
+ function desaturate(color, amount) {
1680
+ amount = (amount === 0) ? 0 : (amount || 10);
1681
+ var hsl = tinycolor(color).toHsl();
1682
+ hsl.s -= amount / 100;
1683
+ hsl.s = clamp01(hsl.s);
1684
+ return tinycolor(hsl);
1685
+ }
1686
+
1687
+ function saturate(color, amount) {
1688
+ amount = (amount === 0) ? 0 : (amount || 10);
1689
+ var hsl = tinycolor(color).toHsl();
1690
+ hsl.s += amount / 100;
1691
+ hsl.s = clamp01(hsl.s);
1692
+ return tinycolor(hsl);
1693
+ }
1694
+
1695
+ function greyscale(color) {
1696
+ return tinycolor(color).desaturate(100);
1697
+ }
1698
+
1699
+ function lighten (color, amount) {
1700
+ amount = (amount === 0) ? 0 : (amount || 10);
1701
+ var hsl = tinycolor(color).toHsl();
1702
+ hsl.l += amount / 100;
1703
+ hsl.l = clamp01(hsl.l);
1704
+ return tinycolor(hsl);
1705
+ }
1706
+
1707
+ function brighten(color, amount) {
1708
+ amount = (amount === 0) ? 0 : (amount || 10);
1709
+ var rgb = tinycolor(color).toRgb();
1710
+ rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100))));
1711
+ rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100))));
1712
+ rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100))));
1713
+ return tinycolor(rgb);
1714
+ }
1715
+
1716
+ function darken (color, amount) {
1717
+ amount = (amount === 0) ? 0 : (amount || 10);
1718
+ var hsl = tinycolor(color).toHsl();
1719
+ hsl.l -= amount / 100;
1720
+ hsl.l = clamp01(hsl.l);
1721
+ return tinycolor(hsl);
1722
+ }
1723
+
1724
+ // Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.
1725
+ // Values outside of this range will be wrapped into this range.
1726
+ function spin(color, amount) {
1727
+ var hsl = tinycolor(color).toHsl();
1728
+ var hue = (mathRound(hsl.h) + amount) % 360;
1729
+ hsl.h = hue < 0 ? 360 + hue : hue;
1730
+ return tinycolor(hsl);
1731
+ }
1732
+
1733
+ // Combination Functions
1734
+ // ---------------------
1735
+ // Thanks to jQuery xColor for some of the ideas behind these
1736
+ // <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>
1737
+
1738
+ function complement(color) {
1739
+ var hsl = tinycolor(color).toHsl();
1740
+ hsl.h = (hsl.h + 180) % 360;
1741
+ return tinycolor(hsl);
1742
+ }
1743
+
1744
+ function triad(color) {
1745
+ var hsl = tinycolor(color).toHsl();
1746
+ var h = hsl.h;
1747
+ return [
1748
+ tinycolor(color),
1749
+ tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
1750
+ tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
1751
+ ];
1752
+ }
1753
+
1754
+ function tetrad(color) {
1755
+ var hsl = tinycolor(color).toHsl();
1756
+ var h = hsl.h;
1757
+ return [
1758
+ tinycolor(color),
1759
+ tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
1760
+ tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
1761
+ tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
1762
+ ];
1763
+ }
1764
+
1765
+ function splitcomplement(color) {
1766
+ var hsl = tinycolor(color).toHsl();
1767
+ var h = hsl.h;
1768
+ return [
1769
+ tinycolor(color),
1770
+ tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}),
1771
+ tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l})
1772
+ ];
1773
+ }
1774
+
1775
+ function analogous(color, results, slices) {
1776
+ results = results || 6;
1777
+ slices = slices || 30;
1778
+
1779
+ var hsl = tinycolor(color).toHsl();
1780
+ var part = 360 / slices;
1781
+ var ret = [tinycolor(color)];
1782
+
1783
+ for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {
1784
+ hsl.h = (hsl.h + part) % 360;
1785
+ ret.push(tinycolor(hsl));
1786
+ }
1787
+ return ret;
1788
+ }
1789
+
1790
+ function monochromatic(color, results) {
1791
+ results = results || 6;
1792
+ var hsv = tinycolor(color).toHsv();
1793
+ var h = hsv.h, s = hsv.s, v = hsv.v;
1794
+ var ret = [];
1795
+ var modification = 1 / results;
1796
+
1797
+ while (results--) {
1798
+ ret.push(tinycolor({ h: h, s: s, v: v}));
1799
+ v = (v + modification) % 1;
1800
+ }
1801
+
1802
+ return ret;
1803
+ }
1804
+
1805
+ // Utility Functions
1806
+ // ---------------------
1807
+
1808
+ tinycolor.mix = function(color1, color2, amount) {
1809
+ amount = (amount === 0) ? 0 : (amount || 50);
1810
+
1811
+ var rgb1 = tinycolor(color1).toRgb();
1812
+ var rgb2 = tinycolor(color2).toRgb();
1813
+
1814
+ var p = amount / 100;
1815
+ var w = p * 2 - 1;
1816
+ var a = rgb2.a - rgb1.a;
1817
+
1818
+ var w1;
1819
+
1820
+ if (w * a == -1) {
1821
+ w1 = w;
1822
+ } else {
1823
+ w1 = (w + a) / (1 + w * a);
1824
+ }
1825
+
1826
+ w1 = (w1 + 1) / 2;
1827
+
1828
+ var w2 = 1 - w1;
1829
+
1830
+ var rgba = {
1831
+ r: rgb2.r * w1 + rgb1.r * w2,
1832
+ g: rgb2.g * w1 + rgb1.g * w2,
1833
+ b: rgb2.b * w1 + rgb1.b * w2,
1834
+ a: rgb2.a * p + rgb1.a * (1 - p)
1835
+ };
1836
+
1837
+ return tinycolor(rgba);
1838
+ };
1839
+
1840
+
1841
+ // Readability Functions
1842
+ // ---------------------
1843
+ // <http://www.w3.org/TR/AERT#color-contrast>
1844
+
1845
+ // `readability`
1846
+ // Analyze the 2 colors and returns an object with the following properties:
1847
+ // `brightness`: difference in brightness between the two colors
1848
+ // `color`: difference in color/hue between the two colors
1849
+ tinycolor.readability = function(color1, color2) {
1850
+ var c1 = tinycolor(color1);
1851
+ var c2 = tinycolor(color2);
1852
+ var rgb1 = c1.toRgb();
1853
+ var rgb2 = c2.toRgb();
1854
+ var brightnessA = c1.getBrightness();
1855
+ var brightnessB = c2.getBrightness();
1856
+ var colorDiff = (
1857
+ Math.max(rgb1.r, rgb2.r) - Math.min(rgb1.r, rgb2.r) +
1858
+ Math.max(rgb1.g, rgb2.g) - Math.min(rgb1.g, rgb2.g) +
1859
+ Math.max(rgb1.b, rgb2.b) - Math.min(rgb1.b, rgb2.b)
1860
+ );
1861
+
1862
+ return {
1863
+ brightness: Math.abs(brightnessA - brightnessB),
1864
+ color: colorDiff
1865
+ };
1866
+ };
1867
+
1868
+ // `readable`
1869
+ // http://www.w3.org/TR/AERT#color-contrast
1870
+ // Ensure that foreground and background color combinations provide sufficient contrast.
1871
+ // *Example*
1872
+ // tinycolor.isReadable("#000", "#111") => false
1873
+ tinycolor.isReadable = function(color1, color2) {
1874
+ var readability = tinycolor.readability(color1, color2);
1875
+ return readability.brightness > 125 && readability.color > 500;
1876
+ };
1877
+
1878
+ // `mostReadable`
1879
+ // Given a base color and a list of possible foreground or background
1880
+ // colors for that base, returns the most readable color.
1881
+ // *Example*
1882
+ // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000"
1883
+ tinycolor.mostReadable = function(baseColor, colorList) {
1884
+ var bestColor = null;
1885
+ var bestScore = 0;
1886
+ var bestIsReadable = false;
1887
+ for (var i=0; i < colorList.length; i++) {
1888
+
1889
+ // We normalize both around the "acceptable" breaking point,
1890
+ // but rank brightness constrast higher than hue.
1891
+
1892
+ var readability = tinycolor.readability(baseColor, colorList[i]);
1893
+ var readable = readability.brightness > 125 && readability.color > 500;
1894
+ var score = 3 * (readability.brightness / 125) + (readability.color / 500);
1895
+
1896
+ if ((readable && ! bestIsReadable) ||
1897
+ (readable && bestIsReadable && score > bestScore) ||
1898
+ ((! readable) && (! bestIsReadable) && score > bestScore)) {
1899
+ bestIsReadable = readable;
1900
+ bestScore = score;
1901
+ bestColor = tinycolor(colorList[i]);
1902
+ }
1903
+ }
1904
+ return bestColor;
1905
+ };
1906
+
1907
+
1908
+ // Big List of Colors
1909
+ // ------------------
1910
+ // <http://www.w3.org/TR/css3-color/#svg-color>
1911
+ var names = tinycolor.names = {
1912
+ aliceblue: "f0f8ff",
1913
+ antiquewhite: "faebd7",
1914
+ aqua: "0ff",
1915
+ aquamarine: "7fffd4",
1916
+ azure: "f0ffff",
1917
+ beige: "f5f5dc",
1918
+ bisque: "ffe4c4",
1919
+ black: "000",
1920
+ blanchedalmond: "ffebcd",
1921
+ blue: "00f",
1922
+ blueviolet: "8a2be2",
1923
+ brown: "a52a2a",
1924
+ burlywood: "deb887",
1925
+ burntsienna: "ea7e5d",
1926
+ cadetblue: "5f9ea0",
1927
+ chartreuse: "7fff00",
1928
+ chocolate: "d2691e",
1929
+ coral: "ff7f50",
1930
+ cornflowerblue: "6495ed",
1931
+ cornsilk: "fff8dc",
1932
+ crimson: "dc143c",
1933
+ cyan: "0ff",
1934
+ darkblue: "00008b",
1935
+ darkcyan: "008b8b",
1936
+ darkgoldenrod: "b8860b",
1937
+ darkgray: "a9a9a9",
1938
+ darkgreen: "006400",
1939
+ darkgrey: "a9a9a9",
1940
+ darkkhaki: "bdb76b",
1941
+ darkmagenta: "8b008b",
1942
+ darkolivegreen: "556b2f",
1943
+ darkorange: "ff8c00",
1944
+ darkorchid: "9932cc",
1945
+ darkred: "8b0000",
1946
+ darksalmon: "e9967a",
1947
+ darkseagreen: "8fbc8f",
1948
+ darkslateblue: "483d8b",
1949
+ darkslategray: "2f4f4f",
1950
+ darkslategrey: "2f4f4f",
1951
+ darkturquoise: "00ced1",
1952
+ darkviolet: "9400d3",
1953
+ deeppink: "ff1493",
1954
+ deepskyblue: "00bfff",
1955
+ dimgray: "696969",
1956
+ dimgrey: "696969",
1957
+ dodgerblue: "1e90ff",
1958
+ firebrick: "b22222",
1959
+ floralwhite: "fffaf0",
1960
+ forestgreen: "228b22",
1961
+ fuchsia: "f0f",
1962
+ gainsboro: "dcdcdc",
1963
+ ghostwhite: "f8f8ff",
1964
+ gold: "ffd700",
1965
+ goldenrod: "daa520",
1966
+ gray: "808080",
1967
+ green: "008000",
1968
+ greenyellow: "adff2f",
1969
+ grey: "808080",
1970
+ honeydew: "f0fff0",
1971
+ hotpink: "ff69b4",
1972
+ indianred: "cd5c5c",
1973
+ indigo: "4b0082",
1974
+ ivory: "fffff0",
1975
+ khaki: "f0e68c",
1976
+ lavender: "e6e6fa",
1977
+ lavenderblush: "fff0f5",
1978
+ lawngreen: "7cfc00",
1979
+ lemonchiffon: "fffacd",
1980
+ lightblue: "add8e6",
1981
+ lightcoral: "f08080",
1982
+ lightcyan: "e0ffff",
1983
+ lightgoldenrodyellow: "fafad2",
1984
+ lightgray: "d3d3d3",
1985
+ lightgreen: "90ee90",
1986
+ lightgrey: "d3d3d3",
1987
+ lightpink: "ffb6c1",
1988
+ lightsalmon: "ffa07a",
1989
+ lightseagreen: "20b2aa",
1990
+ lightskyblue: "87cefa",
1991
+ lightslategray: "789",
1992
+ lightslategrey: "789",
1993
+ lightsteelblue: "b0c4de",
1994
+ lightyellow: "ffffe0",
1995
+ lime: "0f0",
1996
+ limegreen: "32cd32",
1997
+ linen: "faf0e6",
1998
+ magenta: "f0f",
1999
+ maroon: "800000",
2000
+ mediumaquamarine: "66cdaa",
2001
+ mediumblue: "0000cd",
2002
+ mediumorchid: "ba55d3",
2003
+ mediumpurple: "9370db",
2004
+ mediumseagreen: "3cb371",
2005
+ mediumslateblue: "7b68ee",
2006
+ mediumspringgreen: "00fa9a",
2007
+ mediumturquoise: "48d1cc",
2008
+ mediumvioletred: "c71585",
2009
+ midnightblue: "191970",
2010
+ mintcream: "f5fffa",
2011
+ mistyrose: "ffe4e1",
2012
+ moccasin: "ffe4b5",
2013
+ navajowhite: "ffdead",
2014
+ navy: "000080",
2015
+ oldlace: "fdf5e6",
2016
+ olive: "808000",
2017
+ olivedrab: "6b8e23",
2018
+ orange: "ffa500",
2019
+ orangered: "ff4500",
2020
+ orchid: "da70d6",
2021
+ palegoldenrod: "eee8aa",
2022
+ palegreen: "98fb98",
2023
+ paleturquoise: "afeeee",
2024
+ palevioletred: "db7093",
2025
+ papayawhip: "ffefd5",
2026
+ peachpuff: "ffdab9",
2027
+ peru: "cd853f",
2028
+ pink: "ffc0cb",
2029
+ plum: "dda0dd",
2030
+ powderblue: "b0e0e6",
2031
+ purple: "800080",
2032
+ red: "f00",
2033
+ rosybrown: "bc8f8f",
2034
+ royalblue: "4169e1",
2035
+ saddlebrown: "8b4513",
2036
+ salmon: "fa8072",
2037
+ sandybrown: "f4a460",
2038
+ seagreen: "2e8b57",
2039
+ seashell: "fff5ee",
2040
+ sienna: "a0522d",
2041
+ silver: "c0c0c0",
2042
+ skyblue: "87ceeb",
2043
+ slateblue: "6a5acd",
2044
+ slategray: "708090",
2045
+ slategrey: "708090",
2046
+ snow: "fffafa",
2047
+ springgreen: "00ff7f",
2048
+ steelblue: "4682b4",
2049
+ tan: "d2b48c",
2050
+ teal: "008080",
2051
+ thistle: "d8bfd8",
2052
+ tomato: "ff6347",
2053
+ turquoise: "40e0d0",
2054
+ violet: "ee82ee",
2055
+ wheat: "f5deb3",
2056
+ white: "fff",
2057
+ whitesmoke: "f5f5f5",
2058
+ yellow: "ff0",
2059
+ yellowgreen: "9acd32"
2060
+ };
2061
+
2062
+ // Make it easy to access colors via `hexNames[hex]`
2063
+ var hexNames = tinycolor.hexNames = flip(names);
2064
+
2065
+
2066
+ // Utilities
2067
+ // ---------
2068
+
2069
+ // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }`
2070
+ function flip(o) {
2071
+ var flipped = { };
2072
+ for (var i in o) {
2073
+ if (o.hasOwnProperty(i)) {
2074
+ flipped[o[i]] = i;
2075
+ }
2076
+ }
2077
+ return flipped;
2078
+ }
2079
+
2080
+ // Return a valid alpha value [0,1] with all invalid values being set to 1
2081
+ function boundAlpha(a) {
2082
+ a = parseFloat(a);
2083
+
2084
+ if (isNaN(a) || a < 0 || a > 1) {
2085
+ a = 1;
2086
+ }
2087
+
2088
+ return a;
2089
+ }
2090
+
2091
+ // Take input from [0, n] and return it as [0, 1]
2092
+ function bound01(n, max) {
2093
+ if (isOnePointZero(n)) { n = "100%"; }
2094
+
2095
+ var processPercent = isPercentage(n);
2096
+ n = mathMin(max, mathMax(0, parseFloat(n)));
2097
+
2098
+ // Automatically convert percentage into number
2099
+ if (processPercent) {
2100
+ n = parseInt(n * max, 10) / 100;
2101
+ }
2102
+
2103
+ // Handle floating point rounding errors
2104
+ if ((math.abs(n - max) < 0.000001)) {
2105
+ return 1;
2106
+ }
2107
+
2108
+ // Convert into [0, 1] range if it isn't already
2109
+ return (n % max) / parseFloat(max);
2110
+ }
2111
+
2112
+ // Force a number between 0 and 1
2113
+ function clamp01(val) {
2114
+ return mathMin(1, mathMax(0, val));
2115
+ }
2116
+
2117
+ // Parse a base-16 hex value into a base-10 integer
2118
+ function parseIntFromHex(val) {
2119
+ return parseInt(val, 16);
2120
+ }
2121
+
2122
+ // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
2123
+ // <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
2124
+ function isOnePointZero(n) {
2125
+ return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
2126
+ }
2127
+
2128
+ // Check to see if string passed in is a percentage
2129
+ function isPercentage(n) {
2130
+ return typeof n === "string" && n.indexOf('%') != -1;
2131
+ }
2132
+
2133
+ // Force a hex value to have 2 characters
2134
+ function pad2(c) {
2135
+ return c.length == 1 ? '0' + c : '' + c;
2136
+ }
2137
+
2138
+ // Replace a decimal with it's percentage value
2139
+ function convertToPercentage(n) {
2140
+ if (n <= 1) {
2141
+ n = (n * 100) + "%";
2142
+ }
2143
+
2144
+ return n;
2145
+ }
2146
+
2147
+ // Converts a decimal to a hex value
2148
+ function convertDecimalToHex(d) {
2149
+ return Math.round(parseFloat(d) * 255).toString(16);
2150
+ }
2151
+ // Converts a hex value to a decimal
2152
+ function convertHexToDecimal(h) {
2153
+ return (parseIntFromHex(h) / 255);
2154
+ }
2155
+
2156
+ var matchers = (function() {
2157
+
2158
+ // <http://www.w3.org/TR/css3-values/#integers>
2159
+ var CSS_INTEGER = "[-\\+]?\\d+%?";
2160
+
2161
+ // <http://www.w3.org/TR/css3-values/#number-value>
2162
+ var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
2163
+
2164
+ // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
2165
+ var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
2166
+
2167
+ // Actual matching.
2168
+ // Parentheses and commas are optional, but not required.
2169
+ // Whitespace can take the place of commas or opening paren
2170
+ var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
2171
+ var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
2172
+
2173
+ return {
2174
+ rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
2175
+ rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
2176
+ hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
2177
+ hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
2178
+ hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
2179
+ hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
2180
+ hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
2181
+ hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
2182
+ };
2183
+ })();
2184
+
2185
+ // `stringInputToObject`
2186
+ // Permissive string parsing. Take in a number of formats, and output an object
2187
+ // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
2188
+ function stringInputToObject(color) {
2189
+
2190
+ color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase();
2191
+ var named = false;
2192
+ if (names[color]) {
2193
+ color = names[color];
2194
+ named = true;
2195
+ }
2196
+ else if (color == 'transparent') {
2197
+ return { r: 0, g: 0, b: 0, a: 0, format: "name" };
2198
+ }
2199
+
2200
+ // Try to match string input using regular expressions.
2201
+ // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
2202
+ // Just return an object and let the conversion functions handle that.
2203
+ // This way the result will be the same whether the tinycolor is initialized with string or object.
2204
+ var match;
2205
+ if ((match = matchers.rgb.exec(color))) {
2206
+ return { r: match[1], g: match[2], b: match[3] };
2207
+ }
2208
+ if ((match = matchers.rgba.exec(color))) {
2209
+ return { r: match[1], g: match[2], b: match[3], a: match[4] };
2210
+ }
2211
+ if ((match = matchers.hsl.exec(color))) {
2212
+ return { h: match[1], s: match[2], l: match[3] };
2213
+ }
2214
+ if ((match = matchers.hsla.exec(color))) {
2215
+ return { h: match[1], s: match[2], l: match[3], a: match[4] };
2216
+ }
2217
+ if ((match = matchers.hsv.exec(color))) {
2218
+ return { h: match[1], s: match[2], v: match[3] };
2219
+ }
2220
+ if ((match = matchers.hex8.exec(color))) {
2221
+ return {
2222
+ a: convertHexToDecimal(match[1]),
2223
+ r: parseIntFromHex(match[2]),
2224
+ g: parseIntFromHex(match[3]),
2225
+ b: parseIntFromHex(match[4]),
2226
+ format: named ? "name" : "hex8"
2227
+ };
2228
+ }
2229
+ if ((match = matchers.hex6.exec(color))) {
2230
+ return {
2231
+ r: parseIntFromHex(match[1]),
2232
+ g: parseIntFromHex(match[2]),
2233
+ b: parseIntFromHex(match[3]),
2234
+ format: named ? "name" : "hex"
2235
+ };
2236
+ }
2237
+ if ((match = matchers.hex3.exec(color))) {
2238
+ return {
2239
+ r: parseIntFromHex(match[1] + '' + match[1]),
2240
+ g: parseIntFromHex(match[2] + '' + match[2]),
2241
+ b: parseIntFromHex(match[3] + '' + match[3]),
2242
+ format: named ? "name" : "hex"
2243
+ };
2244
+ }
2245
+
2246
+ return false;
2247
+ }
2248
+
2249
+ window.tinycolor = tinycolor;
2250
+ })();
2251
+
2252
+
2253
+ $(function () {
2254
+ if ($.fn.spectrum.load) {
2255
+ $.fn.spectrum.processNativeColorInputs();
2256
+ }
2257
+ });
2258
+
2259
+})(window, jQuery);
...
...