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