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