PageSourceSearch

https://www.clergyfinancial.com/wp-content/plugins/woocommerce-cus…//assets/js/spectrum.js?ver=6.8.10

js clergyfinancial.com collected 2026-09-25 05:19:23 UTC 76,937 bytes, 2,255 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.