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