1 /*! 2 * Copyright (c) 2021 Momo Bassit. 3 * Licensed under the MIT License (MIT) 4 * https://github.com/mdbassit/Coloris 5 */ 6 if(typeof LANG == 'undefined') var LANG = (typeof getLanguage != 'undefined') ? getLanguage() : 'en'; 7 const _coloris_label = { 8 ko: { 9 save: 'ì ì¥', 10 cancel: 'ì·¨ì', 11 alpha: 'ë¶í¬ëª ë', 12 alpha_info: `ìì í¬ëª ìíì ëë¤.<br>컬ë¬ë¥¼ ë³´ë ¤ë©´ ìëì ë¶í¬ëª ë를<br>ëì¬ì£¼ì¸ì.`, 13 hex: '컬ë¬', 14 guide: `RGB ë°©ì ìì ì½ë í기ë²ì ëë¤.`, 15 }, 16 en: { 17 save: 'SAVE', 18 cancel: 'CANCEL', 19 alpha: 'Opacity', 20 alpha_info: `It is completely transparent.<br>Please adjust the transparency to see the color.`, 21 hex: 'Color', 22 guide: `The color is expressed as an RGB color code.`, 23 } 24 }; 25 26 27 (function (window, document, Math, undefined) { 28 29 var checkReturnFuncArr = ['getColorSelectorPnInfo','getColorInfo','getChangeColorVal','getColorRegex']; 30 var checkUsedFuncArr = []; 31 32 var ctx = document.createElement('canvas').getContext('2d'); 33 var currentColor = { r: 0, g: 0, b: 0, h: 0, s: 0, v: 0, a: 1 }; 34 var container,picker,colorArea,colorMarker,colorPreview,colorValue,clearButton,closeButton, 35 hueSlider,hueMarker,alphaSlider,alphaMarker,currentEl,currentFormat,oldColor,keyboardNav, 36 colorCursor,hexInput,alphaInput,cancelButton,btnBox,picker_backdrop, 37 colorAreaDims = {}; 38 39 // Default settings 40 var settings = { 41 el: '.coloris', //'[data-coloris]', 42 parent: 'body', 43 theme: 'default', 44 themeMode: 'light', 45 rtl: false, 46 wrap: true, 47 margin: 2, 48 format: 'hex', 49 formatToggle: false, 50 swatches: [], 51 swatchesOnly: false, 52 alpha: true, 53 forceAlpha: false, 54 focusInput: false, 55 selectInput: false, 56 inline: false, 57 defaultColor: '#000000',
58 clearButton: false, 59 clearLabel: 'Clear', 60 closeButton: true, //false, 61 closeLabel: _coloris_label[(LANG === 'ko') ? 'ko' : 'en'].save, //'Close', 62 cancelButton: true, 63 cancelLabel: _coloris_label[(LANG === 'ko') ? 'ko' : 'en'].cancel, 64 onChange: function onChange() {return undefined;}, 65 a11y: { 66 open: 'Open color picker', 67 cancel: 'Cancel the selected color', 68 close: 'Save color picker', //'Close color picker', 69 clear: 'Clear the selected color', 70 marker: 'Saturation: {s}. Brightness: {v}.', 71 hueSlider: 'Hue slider', 72 alphaSlider: 'Opacity slider', 73 alphaInput: 'Opacity value field', 74 alphaLabel: _coloris_label[(LANG === 'ko') ? 'ko' : 'en'].alpha, 75 hexInput: 'Color Hex value field', 76 hexLabel: _coloris_label[(LANG === 'ko') ? 'ko' : 'en'].hex, 77 input: 'Color value field', 78 inputLabel: 'Color', 79 format: 'Color format', 80 swatch: 'Color swatch', 81 instruction: 'Saturation and brightness selector. Use up, down, left and right arrow keys to select.' 82 } 83 }; 84 85 86 // Virtual instances cache 87 var instances = {}; 88 var currentInstanceId = ''; 89 var defaultInstance = {}; 90 var hasInstance = false; 91 92 /** 93 * Configure the color picker. 94 * @param {object} options Configuration options. 95 */ 96 function configure(options) { 97 if (typeof options !== 'object') { 98 return; 99 } 100 101 for (var key in options) { 102 switch (key) { 103 case 'el': 104 bindFields(options.el); 105 if (options.wrap !== false) { 106 wrapFields(options.el); 107 } 108 break; 109 case 'parent': 110 container = document.querySelector(options.parent); 111 if (container) { 112 container.appendChild(picker); 113 container.appendChild(picker_backdrop); 114 settings.parent = options.parent; 115 116 // document.body is special 117 if (container === document.body) { 118 container = undefined; 119 } 120 } 121 break; 122 case 'themeMode': 123 settings.themeMode = options.themeMode; 124 if (options.themeMode === 'auto' && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) { 125 settings.themeMode = 'dark'; 126 } 127 // The lack of a break statement is intentional 128 case 'theme': 129 if (options.theme) { 130 settings.theme = options.theme; 131 } 132 133 // Set the theme and color scheme 134 picker.className = "clr-picker clr-" + settings.theme + " clr-" + settings.themeMode; 135 136 // Update the color picker's position if inline mode is in use 137 if (settings.inline) { 138 updatePickerPosition(); 139 } 140 break; 141 case 'rtl': 142 settings.rtl = !!options.rtl; 143 document.querySelectorAll('.clr-field').forEach(function (field) {return field.classList.toggle('clr-rtl', settings.rtl);}); 144 break; 145 case 'margin': 146 options.margin *= 1; 147 settings.margin = !isNaN(options.margin) ? options.margin : settings.margin; 148 break; 149 case 'wrap': 150 if (options.el && options.wrap) { 151 wrapFields(options.el); 152 } 153 break; 154 case 'formatToggle': 155 settings.formatToggle = !!options.formatToggle; 156 getEl('clr-format').style.display = settings.formatToggle ? 'block' : 'none'; 157 if (settings.formatToggle) { 158 settings.format = 'auto'; 159 } 160 break; 161 case 'swatches': 162 if (Array.isArray(options.swatches)) {(function () { 163 var swatches = []; 164 165 options.swatches.forEach(function (swatch, i) { 166 swatches.push("<button type=\"button\" id=\"clr-swatch-" + i + "\" aria-labelledby=\"clr-swatch-label clr-swatch-" + i + "\" style=\"color: " + swatch + ";\">" + swatch + "</button>"); 167 }); 168 169 getEl('clr-swatches').innerHTML = swatches.length ? "<div>" + swatches.join('') + "</div>" : ''; 170 settings.swatches = options.swatches.slice();})(); 171 } 172 break; 173 case 'swatchesOnly': 174 settings.swatchesOnly = !!options.swatchesOnly; 175 picker.setAttribute('data-minimal', settings.swatchesOnly); 176 break; 177 case 'alpha': 178 settings.alpha = !!options.alpha; 179 picker.setAttribute('data-alpha', settings.alpha); 180 break; 181 case 'inline': 182 settings.inline = !!options.inline; 183 picker.setAttribute('data-inline', settings.inline); 184 185 if (settings.inline) { 186 var defaultColor = options.defaultColor || settings.defaultColor; 187 188 currentFormat = getColorFormatFromStr(defaultColor); 189 updatePickerPosition(); 190 setColorFromStr(defaultColor); 191 } 192 break; 193 case 'clearButton': 194 // Backward compatibility 195 if (typeof options.clearButton === 'object') { 196 if (options.clearButton.label) { 197 settings.clearLabel = options.clearButton.label; 198 clearButton.innerHTML = settings.clearLabel; 199 } 200 201 options.clearButton = options.clearButton.show; 202 } 203 settings.clearButton = !!options.clearButton; 204 clearButton.style.display = settings.clearButton ? 'block' : 'none'; 205 break; 206 case 'clearLabel': 207 settings.clearLabel = options.clearLabel; 208 clearButton.innerHTML = settings.clearLabel; 209 break; 210 211 case 'closeButton': 212 settings.closeButton = !!options.closeButton; 213 214 if (settings.closeButton) { 215 // picker.insertBefore(closeButton, colorPreview); 216 btnBox.append(closeButton); 217 } else { 218 // colorPreview.appendChild(closeButton); 219 paletteBox.appendChild(closeButton); 220 } 221 break; 222 case 'closeLabel': 223 settings.closeLabel = options.closeLabel; 224 closeButton.innerHTML = settings.closeLabel; 225 break; 226 227 case 'cancelButton': 228 settings.cancelButton = !!options.cancelButton; 229 230 if (settings.cancelButton) { 231 // picker.insertBefore(cancelButton, colorPreview); 232 btnBox.append(cancelButton); 233 } else { 234 // colorPreview.appendChild(cancelButton); 235 paletteBox.appendChild(cancelButton); 236 } 237 break; 238 case 'cancelLabel': 239 settings.cancelLabel = options.cancelLabel; 240 cancelButton.innerHTML = settings.cancelLabel; 241 break; 242 243 case 'a11y': 244 var labels = options.a11y; 245 var update = false;
246 247 if (typeof labels === 'object') { 248 for (var label in labels) { 249 if (labels[label] && settings.a11y[label]) { 250 settings.a11y[label] = labels[label]; 251 update = true; 252 } 253 } 254 } 255 256 if (update) { 257 var openLabel = getEl('clr-open-label'); 258 var swatchLabel = getEl('clr-swatch-label'); 259 260 openLabel.innerHTML = settings.a11y.open; 261 swatchLabel.innerHTML = settings.a11y.swatch; 262 closeButton.setAttribute('aria-label', settings.a11y.close); 263 clearButton.setAttribute('aria-label', settings.a11y.clear); 264 CancelButton.setAttribute('aria-label', settings.a11y.cancel); 265 hueSlider.setAttribute('aria-label', settings.a11y.hueSlider); 266 alphaInput.setAttribute('aria-label', settings.a11y.alphaInput); 267 alphaSlider.setAttribute('aria-label', settings.a11y.alphaSlider); 268 colorValue.setAttribute('aria-label', settings.a11y.input); 269 colorArea.setAttribute('aria-label', settings.a11y.instruction); 270 } 271 break; 272 default: 273 settings[key] = options[key];} 274 275 } 276 } 277 278 /** 279 * Add or update a virtual instance. 280 * @param {String} selector The CSS selector of the elements to which the instance is attached. 281 * @param {Object} options Per-instance options to apply. 282 */ 283 function setVirtualInstance(selector, options) { 284 if (typeof selector === 'string' && typeof options === 'object') { 285 instances[selector] = options; 286 hasInstance = true; 287 } 288 } 289 290 function returnInstance() { 291 return instances; 292 } 293 294 /** 295 * Remove a virtual instance. 296 * @param {String} selector The CSS selector of the elements to which the instance is attached. 297 */ 298 function removeVirtualInstance(selector) { 299 delete instances[selector]; 300 301 if (Object.keys(instances).length === 0) { 302 hasInstance = false; 303 304 if (selector === currentInstanceId) { 305 resetVirtualInstance(); 306 } 307 } 308 } 309 310 /** 311 * Attach a virtual instance to an element if it matches a selector. 312 * @param {Object} element Target element that will receive a virtual instance if applicable. 313 */ 314 function attachVirtualInstance(element) { 315 if (hasInstance) { 316 // These options can only be set globally, not per instance 317 var unsupportedOptions = ['el', 'wrap', 'rtl', 'inline', 'defaultColor', 'a11y'];var _loop = function _loop( 318 319 selector) { 320 var options = instances[selector]; 321 322 // If the element matches an instance's CSS selector 323 if (element.matches(selector)) { 324 currentInstanceId = selector; 325 defaultInstance = {}; 326 327 // Delete unsupported options 328 unsupportedOptions.forEach(function (option) {return delete options[option];}); 329 330 // Back up the default options so we can restore them later 331 for (var option in options) { 332 defaultInstance[option] = Array.isArray(settings[option]) ? settings[option].slice() : settings[option]; 333 } 334 335 // Set the instance's options 336 configure(options); 337 return "break"; 338 }};for (var selector in instances) {var _ret = _loop(selector);if (_ret === "break") break; 339 } 340 } 341 } 342 343 /** 344 * Revert any per-instance options that were previously applied. 345 */ 346 function resetVirtualInstance() { 347 if (Object.keys(defaultInstance).length > 0) { 348 configure(defaultInstance); 349 currentInstanceId = ''; 350 defaultInstance = {}; 351 } 352 } 353 354 355 function getCurrentLanguage(_s) { 356 if(typeof LANG == 'undefined') return; 357 358 var curlang = (LANG === 'ko') ? 'ko' : 'en'; 359 360 _s.cancelLabel = _coloris_label[curlang].cancel; 361 _s.closeLabel = _coloris_label[curlang].save; 362 _s.a11y.alphaLabel = _coloris_label[curlang].alpha; 363 _s.a11y.hexLabel = _coloris_label[curlang].hex; 364 365 $('#clr-picker .clr-color-info.hex .info-label').text(_s.a11y.hexLabel); 366 $('#clr-picker .clr-color-info.alpha .info-label').text(_s.a11y.alphaLabel); 367 $('#clr-picker #clr-cancel').text(_s.cancelLabel); 368 $('#clr-picker #clr-close').text(_s.closeLabel); 369 370 return _s; 371 } 372 373 /** 374 * Bind the color picker to input fields that match the selector. 375 * @param {string} selector One or more selectors pointing to input fields. 376 */ 377 function bindFields(selector) { 378 // Show the color picker on click on the input fields that match the selector 379 $(document).off('click input', selector); 380 381 addListener(document, 'click', selector, function (event) {
382 settings = getCurrentLanguage(settings); 383 384 // Skip if inline mode is in use 385 if (settings.inline) { 386 return; 387 } 388 389 // Apply any per-instance options first 390 attachVirtualInstance(event.target); 391 392 currentEl = event.target; 393 oldColor = currentEl.value; 394 currentFormat = getColorFormatFromStr(oldColor); 395 396 settings.alpha = (currentEl.classList.contains('clr-alphaoff')) ? false : true; 397 picker.setAttribute('data-alpha', settings.alpha); 398 picker.classList.add('clr-open'); 399 paletteBox.classList.add('ready'); 400 401 updatePickerPosition(); 402 setColorFromStr(oldColor); 403 404 $('#clr-color-comment').addClass('hide'); 405 $('.back-black').addClass('hide'); 406 if(alphaInput.value == 0) { 407 $('#clr-color-comment').removeClass('hide'); 408 $('.back-black').removeClass('hide'); 409 } 410 411 if (settings.focusInput || settings.selectInput) { 412 if(settings.focusInput) colorValue.focus({ preventScroll: true }); 413 if(settings.selectInput) colorValue.setSelectionRange(currentEl.selectionStart, currentEl.selectionEnd); 414 } 415 416 if (settings.selectInput) { 417 colorValue.select(); 418 } 419 420 // Always focus the first element when using keyboard navigation 421 if (keyboardNav || settings.swatchesOnly) { 422 getFocusableElements().shift().focus(); 423 } 424 425 // Trigger an "open" event 426 currentEl.dispatchEvent(new Event('open', { bubbles: true })); 427 }); 428 429 // Update the color preview of the input fields that match the selector 430 addListener(document, 'input', selector, function (event) { 431 var parent = event.target.parentNode; 432 433 // Only update the preview if the field has been previously wrapped 434 if (parent.classList.contains('clr-field')) { 435 parent.style.color = event.target.value; 436 } 437 }); 438 } 439 440 /** 441 * Update the color picker's position and the color gradient's offset 442 */ 443 function updatePickerPosition() { 444 var parent = container; 445 var scrollY = window.scrollY; 446 var pickerWidth = picker.offsetWidth; 447 var pickerHeight = picker.offsetHeight; 448 var reposition = { left: false, top: false }; 449 var parentStyle, parentMarginTop, parentBorderTop; 450 var offset = { x: 0, y: 0 }; 451 452 if (parent) { 453 parentStyle = window.getComputedStyle(parent); 454 parentMarginTop = parseFloat(parentStyle.marginTop); 455 parentBorderTop = parseFloat(parentStyle.borderTopWidth); 456 457 offset = parent.getBoundingClientRect(); 458 offset.y += parentBorderTop + scrollY; 459 } 460 461 if (!settings.inline) { 462 var coords = currentEl.getBoundingClientRect(); 463 var left = coords.x; 464 var top = scrollY + coords.y + coords.height + settings.margin; 465 466 // If the color picker is inside a custom container 467 // set the position relative to it 468 if (parent) { 469 left -= offset.x; 470 top -= offset.y; 471 472 if (left + pickerWidth > parent.clientWidth) { 473 left += coords.width - pickerWidth; 474 reposition.left = true; 475 } 476 477 if (top + pickerHeight > parent.clientHeight - parentMarginTop) { 478 if (pickerHeight + settings.margin <= coords.top - (offset.y - scrollY)) { 479 top -= coords.height + pickerHeight + settings.margin * 2; 480 reposition.top = true; 481 } 482 } 483 484 top += parent.scrollTop; 485 486 // Otherwise set the position relative to the whole document 487 } else { 488 if (left + pickerWidth > document.documentElement.clientWidth) { 489 left += coords.width - pickerWidth; 490 reposition.left = true; 491 } 492 493 if (top + pickerHeight - scrollY > document.documentElement.clientHeight) { 494 if (pickerHeight + settings.margin <= coords.top) { 495 top = scrollY + coords.y - pickerHeight - settings.margin; 496 reposition.top = true; 497 } 498 } 499 } 500 501 if(top < 0) { 502 top = 0; 503 left -= 23; 504 } 505 if(top > document.documentElement.clientHeight - pickerHeight 506 && (!$('body').hasClass('off-config') && !$('html').hasClass('_scroll')) 507 ) { 508 top = document.documentElement.clientHeight - pickerHeight; 509 left -= 23; 510 } 511 512 picker.classList.toggle('clr-left', reposition.left); 513 picker.classList.toggle('clr-top', reposition.top); 514 picker.style.left = left + "px"; 515 picker.style.top = top + "px"; 516 offset.x += picker.offsetLeft; 517 offset.y += picker.offsetTop; 518 } 519 520 colorAreaDims = { 521 width: colorArea.offsetWidth, 522 height: colorArea.offsetHeight, 523 x: colorArea.offsetLeft + offset.x, 524 y: colorArea.offsetTop + offset.y }; 525 526 } 527 528 /** 529 * Wrap the linked input fields in a div that adds a color preview. 530 * @param {string} selector One or more selectors pointing to input fields. 531 */ 532 function excludeColorFieldAutofill(field) {
533 if (!field.matches('input[type="text"], input:not([type]), input[type="number"]')) return; 534 field.setAttribute('autocomplete', 'off'); 535 field.setAttribute('autocorrect', 'off'); 536 field.setAttribute('autocapitalize', 'off'); 537 field.setAttribute('spellcheck', 'false'); 538 field.setAttribute('data-1p-ignore', 'true'); 539 field.setAttribute('data-bwignore', 'true'); 540 } 541 542 function wrapFields(selector) { 543 document.querySelectorAll(selector).forEach(function (field) { 544 excludeColorFieldAutofill(field); 545 var parentNode = field.parentNode; 546 547 if (!parentNode.classList.contains('clr-field')) { 548 var wrapper = document.createElement('div'); 549 var classes = 'clr-field'; 550 551 if (settings.rtl || field.classList.contains('clr-rtl')) { 552 classes += ' clr-rtl'; 553 } 554 555 wrapper.innerHTML = "<button type=\"button\" aria-labelledby=\"clr-open-label\"></button>"; 556 parentNode.insertBefore(wrapper, field); 557 wrapper.setAttribute('class', classes); 558 wrapper.style.color = field.value; 559 wrapper.appendChild(field); 560 } 561 }); 562 } 563 564 /** 565 * Close the color picker. 566 * @param {boolean} [revert] If true, revert the color to the original value. 567 */ 568 function closePicker(revert) { 569 if (currentEl && !settings.inline) { 570 var prevEl = currentEl; 571 572 // Revert the color to the original value if needed 573 if (revert) { 574 // This will prevent the "change" event on the colorValue input to execute its handler 575 currentEl = undefined; 576 577 if (oldColor !== prevEl.value) { 578 prevEl.value = oldColor; 579 580 // Trigger an "input" event to force update the thumbnail next to the input field 581 prevEl.dispatchEvent(new Event('input', { bubbles: true })); 582 } 583 } 584 585 // Trigger a "change" event if needed 586 setTimeout(function () {// Add this to the end of the event loop 587 if (oldColor !== prevEl.value) { 588 prevEl.dispatchEvent(new Event('change', { bubbles: true })); 589 } 590 }); 591 592 // Hide the picker dialog 593 picker.classList.remove('clr-open'); 594 595 // Reset any previously set per-instance options 596 if (hasInstance) { 597 resetVirtualInstance(); 598 } 599 600 // Trigger a "close" event 601 prevEl.dispatchEvent(new Event('close', { bubbles: true })); 602 603 if (settings.focusInput) { 604 prevEl.focus({ preventScroll: false }); 605 } 606 607 // This essentially marks the picker as closed 608 currentEl = undefined; 609 } 610 } 611 612 /** 613 * Set the active color from a string. 614 * @param {string} str String representing a color. 615 */ 616 function setColorFromStr(str) { 617 var rgba = strToRGBA(str); 618 var hsva = RGBAtoHSVA(rgba); 619 620 updateMarkerA11yLabel(hsva.s, hsva.v); 621 updateColor(rgba, hsva); 622 623 // Update the UI 624 hueSlider.value = hsva.h; 625 picker.style.color = "hsl(" + hsva.h + ", 100%, 50%)"; 626 hueMarker.style.left = hsva.h / 360 * 100 + "%"; 627 628 colorMarker.style.left = colorAreaDims.width * hsva.s / 100 + "px"; 629 colorMarker.style.top = colorAreaDims.height - colorAreaDims.height * hsva.v / 100 + "px"; 630 631 alphaSlider.value = hsva.a * 100; 632 alphaMarker.style.left = hsva.a * 100 + "%"; 633 alphaInput.value = alphaSlider.value; 634 } 635 636 /** 637 * Guess the color format from a string. 638 * @param {string} str String representing a color. 639 * @return {string} The color format. 640 */ 641 function getColorFormatFromStr(str) { 642 var format = str.substring(0, 3).toLowerCase(); 643 644 if (format === 'rgb' || format === 'hsl') { 645 return format; 646 } 647 648 return 'hex'; 649 } 650 651 /** 652 * Copy the active color to the linked input field. 653 * @param {number} [color] Color value to override the active color. 654 */ 655 function pickColor(color) { 656 color = color !== undefined ? color : colorValue.value; 657 658 if (currentEl) { 659 currentEl.value = color; 660 currentEl.dispatchEvent(new Event('input', { bubbles: true })); 661 } 662 663 if (settings.onChange) { 664 settings.onChange.call(window, color, currentEl); 665 } 666 667 document.dispatchEvent(new CustomEvent('coloris:pick', { detail: { color: color, currentEl: currentEl } })); 668 } 669 670 /** 671 * Set the active color based on a specific point in the color gradient. 672 * @param {number} x Left position. 673 * @param {number} y Top position. 674 */ 675 function setColorAtPosition(x, y) { 676 var hsva = { 677 h: hueSlider.value * 1, 678 s: x / colorAreaDims.width * 100, 679 v: 100 - y / colorAreaDims.height * 100,
680 a: alphaSlider.value / 100 }; 681 682 var rgba = HSVAtoRGBA(hsva); 683 684 updateMarkerA11yLabel(hsva.s, hsva.v); 685 updateColor(rgba, hsva); 686 // pickColor(); 687 } 688 689 /** 690 * Update the color marker's accessibility label. 691 * @param {number} saturation 692 * @param {number} value 693 */ 694 function updateMarkerA11yLabel(saturation, value) { 695 var label = settings.a11y.marker; 696 697 saturation = saturation.toFixed(1) * 1; 698 value = value.toFixed(1) * 1; 699 label = label.replace('{s}', saturation); 700 label = label.replace('{v}', value); 701 colorMarker.setAttribute('aria-label', label); 702 } 703 704 // 705 /** 706 * Get the pageX and pageY positions of the pointer. 707 * @param {object} event The MouseEvent or TouchEvent object. 708 * @return {object} The pageX and pageY positions. 709 */ 710 function getPointerPosition(event) { 711 return { 712 pageX: event.changedTouches ? event.changedTouches[0].pageX : event.pageX, 713 pageY: event.changedTouches ? event.changedTouches[0].pageY : event.pageY }; 714 715 } 716 717 /** 718 * Move the color marker when dragged. 719 * @param {object} event The MouseEvent object. 720 */ 721 function moveMarker(event) { 722 var pointer = getPointerPosition(event); 723 var x = pointer.pageX - colorAreaDims.x; 724 var y = pointer.pageY - colorAreaDims.y; 725 726 if (container) { 727 y += container.scrollTop; 728 } 729 730 setMarkerPosition(x, y); 731 732 // Prevent scrolling while dragging the marker 733 event.preventDefault(); 734 event.stopPropagation(); 735 } 736 737 /** 738 * Move the color marker when the arrow keys are pressed. 739 * @param {number} offsetX The horizontal amount to move. 740 * @param {number} offsetY The vertical amount to move. 741 */ 742 function moveMarkerOnKeydown(offsetX, offsetY) { 743 var x = colorMarker.style.left.replace('px', '') * 1 + offsetX; 744 var y = colorMarker.style.top.replace('px', '') * 1 + offsetY; 745 746 setMarkerPosition(x, y); 747 } 748 749 /** 750 * Set the color marker's position. 751 * @param {number} x Left position. 752 * @param {number} y Top position. 753 */ 754 function setMarkerPosition(x, y) { 755 756 // .clr-picker padding val 757 x -= 22; 758 y -= 20; 759 760 // Make sure the marker doesn't go out of bounds 761 x = x < 0 ? 0 : x > colorAreaDims.width ? colorAreaDims.width : x; 762 y = y < 0 ? 0 : y > colorAreaDims.height ? colorAreaDims.height : y; 763 764 // Set the position 765 colorMarker.style.left = x + 'px'; 766 colorMarker.style.top = y + 'px'; 767 768 colorCursor.style.lfet = x + 'px'; 769 colorCursor.style.top = y + 'px'; 770 771 // Update the color 772 setColorAtPosition(x, y); 773 774 // Make sure the marker is focused
775 colorMarker.focus(); 776 } 777 778 /** 779 * Update the color picker's input field and preview thumb. 780 * @param {Object} rgba Red, green, blue and alpha values. 781 * @param {Object} [hsva] Hue, saturation, value and alpha values. 782 */ 783 function updateColor(rgba, hsva) {if (rgba === void 0) {rgba = {};}if (hsva === void 0) {hsva = {};} 784 var format = settings.format; 785 786 for (var key in rgba) { 787 currentColor[key] = rgba[key]; 788 } 789 790 for (var _key in hsva) { 791 currentColor[_key] = hsva[_key]; 792 } 793 794 var hex = RGBAToHex(currentColor); 795 var opaqueHex = hex.substring(0, 7); 796 var hex_zero = (hex.substring(7) != '') ? hex.substring(7) : 'ff'; 797 798 colorMarker.style.color = opaqueHex; 799 alphaMarker.parentNode.style.color = opaqueHex; 800 alphaMarker.style.color = hex; 801 colorPreview.style.color = hex; 802 if(paletteBox.classList.contains('ready')) { 803 colorCurrent.style.color = hex; 804 paletteBox.classList.remove('ready'); 805 } 806 807 // Force repaint the color and alpha gradients as a workaround for a Google Chrome bug 808 colorArea.style.display = 'none'; 809 colorArea.offsetHeight; 810 colorArea.style.display = ''; 811 alphaMarker.nextElementSibling.style.display = 'none'; 812 alphaMarker.nextElementSibling.offsetHeight; 813 alphaMarker.nextElementSibling.style.display = ''; 814 815 if (format === 'mixed') { 816 format = currentColor.a === 1 ? 'hex' : 'rgb'; 817 } else if (format === 'auto') { 818 format = currentFormat; 819 } 820 821 alphaInput.value = alphaSlider.value; 822 hexInput.value = hex.slice(0,7); 823 824 switch (format) { 825 case 'hex': 826 colorValue.value = hex; 827 break; 828 case 'rgb': 829 colorValue.value = RGBAToStr(currentColor); 830 break; 831 case 'hsl': 832 colorValue.value = HSLAToStr(HSVAtoHSLA(currentColor)); 833 break; 834 } 835 836 // Select the current format in the format switcher 837 document.querySelector(".clr-format [value=\"" + format + "\"]").checked = true; 838 } 839 840 /** 841 * Set the hue when its slider is moved. 842 */ 843 function setHue() { 844 var hue = hueSlider.value * 1; 845 var x = colorMarker.style.left.replace('px', '') * 1; 846 var y = colorMarker.style.top.replace('px', '') * 1; 847 848 picker.style.color = "hsl(" + hue + ", 100%, 50%)"; 849 hueMarker.style.left = hue / 360 * 100 + "%"; 850 851 setColorAtPosition(x, y); 852 } 853 854 /** 855 * Set the alpha when its slider is moved. 856 */ 857 function setAlpha() { 858 var alpha = alphaSlider.value / 100; 859 860 if(alphaSlider.value > 0) { 861 $('#clr-color-comment').addClass('hide'); 862 $('.back-black').addClass('hide'); 863 } else { 864 $('#clr-color-comment').removeClass('hide'); 865 $('.back-black').removeClass('hide'); 866 } 867 868 alphaMarker.style.left = alpha * 100 + "%"; 869 updateColor({ a: alpha }); 870 // pickColor(); 871 } 872 function setAlphaInput() { 873 if(alphaInput.value < 1 || !alphaInput.value) alphaInput.value = 0; 874 else if(alphaInput.value > 100) alphaInput.value = 100; 875 876 if(alphaInput.value > 0) { 877 $('#clr-color-comment, .back-black').addClass('hide'); 878 } else { 879 $('#clr-color-comment, .back-black').removeClass('hide'); 880 } 881 882 var alpha = alphaInput.value / 100; 883 884 alphaSlider.value = alphaInput.value; 885 alphaMarker.style.left = alpha * 100 + "%"; 886 updateColor({ a: alpha }); 887 // pickColor(); 888 } 889 890 891 /** 892 * Convert HSVA to RGBA. 893 * @param {object} hsva Hue, saturation, value and alpha values. 894 * @return {object} Red, green, blue and alpha values. 895 */ 896 function HSVAtoRGBA(hsva) { 897 var saturation = hsva.s / 100; 898 var value = hsva.v / 100; 899 var chroma = saturation * value; 900 var hueBy60 = hsva.h / 60; 901 var x = chroma * (1 - Math.abs(hueBy60 % 2 - 1)); 902 var m = value - chroma; 903 904 chroma = chroma + m; 905 x = x + m; 906 907 var index = Math.floor(hueBy60) % 6; 908 var red = [chroma, x, m, m, x, chroma][index]; 909 var green = [x, chroma, chroma, x, m, m][index]; 910 var blue = [m, m, x, chroma, chroma, x][index]; 911 912 return { 913 r: Math.round(red * 255), 914 g: Math.round(green * 255), 915 b: Math.round(blue * 255), 916 a: hsva.a }; 917 918 } 919 920 /** 921 * Convert HSVA to HSLA. 922 * @param {object} hsva Hue, saturation, value and alpha values. 923 * @return {object} Hue, saturation, lightness and alpha values. 924 */ 925 function HSVAtoHSLA(hsva) { 926 var value = hsva.v / 100; 927 var lightness = value * (1 - hsva.s / 100 / 2); 928 var saturation; 929 930 if (lightness > 0 && lightness < 1) { 931 saturation = Math.round((value - lightness) / Math.min(lightness, 1 - lightness) * 100); 932 } 933 934 return { 935 h: hsva.h, 936 s: saturation || 0, 937 l: Math.round(lightness * 100), 938 a: hsva.a }; 939 940 } 941 942 /** 943 * Convert RGBA to HSVA. 944 * @param {object} rgba Red, green, blue and alpha values. 945 * @return {object} Hue, saturation, value and alpha values. 946 */ 947 function RGBAtoHSVA(rgba) { 948 var red = rgba.r / 255; 949 var green = rgba.g / 255; 950 var blue = rgba.b / 255; 951 var xmax = Math.max(red, green, blue); 952 var xmin = Math.min(red, green, blue); 953 var chroma = xmax - xmin; 954 var value = xmax; 955 var hue = 0; 956 var saturation = 0; 957 958 if (chroma) { 959 if (xmax === red) {hue = (green - blue) / chroma;} 960 if (xmax === green) {hue = 2 + (blue - red) / chroma;} 961 if (xmax === blue) {hue = 4 + (red - green) / chroma;} 962 if (xmax) {saturation = chroma / xmax;} 963 } 964 965 hue = Math.floor(hue * 60); 966 967 return { 968 h: hue < 0 ? hue + 360 : hue, 969 s: Math.round(saturation * 100), 970 v: Math.round(value * 100), 971 a: rgba.a }; 972 973 } 974 975 /** 976 * Parse a string to RGBA. 977 * @param {string} str String representing a color. 978 * @return {object} Red, green, blue and alpha values. 979 */ 980 function strToRGBA(str) { 981 var regex = /^((rgba)|rgb)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i; 982 var match, rgba; 983 984 // Default to black for invalid color strings 985 ctx.fillStyle = '#000'; 986 987 // Use canvas to convert the string to a valid color string 988 ctx.fillStyle = str; 989 match = regex.exec(ctx.fillStyle); 990 991 if (match) { 992 rgba = { 993 r: match[3] * 1, 994 g: match[4] * 1, 995 b: match[5] * 1, 996 a: match[6] * 1 }; 997 998 999 // Workaround to mitigate a Chromium bug where the alpha value is rounded incorrectly 1000 rgba.a = +rgba.a.toFixed(2); 1001 1002 } else { 1003 match = ctx.fillStyle.replace('#', '').match(/.{2}/g).map(function (h) {return parseInt(h, 16);}); 1004 rgba = { 1005 r: match[0], 1006 g: match[1], 1007 b: match[2], 1008 a: 1 }; 1009 1010 } 1011 1012 return rgba; 1013 } 1014 1015 /** 1016 * Convert RGBA to Hex. 1017 * @param {object} rgba Red, green, blue and alpha values. 1018 * @return {string} Hex color string. 1019 */ 1020 function RGBAToHex(rgba) { 1021 var R = rgba.r.toString(16); 1022 var G = rgba.g.toString(16); 1023 var B = rgba.b.toString(16); 1024 var A = ''; 1025
1026 if (rgba.r < 16) { 1027 R = '0' + R; 1028 } 1029 1030 if (rgba.g < 16) { 1031 G = '0' + G; 1032 } 1033 1034 if (rgba.b < 16) { 1035 B = '0' + B; 1036 } 1037 1038 if (settings.alpha && (rgba.a < 1 || settings.forceAlpha)) { 1039 var alpha = rgba.a * 255 | 0; 1040 A = alpha.toString(16); 1041 1042 if (alpha < 16) { 1043 A = '0' + A; 1044 } 1045 } 1046 1047 return '#' + R + G + B + A; 1048 } 1049 1050 /** 1051 * Convert RGBA values to a CSS rgb/rgba string. 1052 * @param {object} rgba Red, green, blue and alpha values. 1053 * @return {string} CSS color string. 1054 */ 1055 function RGBAToStr(rgba) { 1056 if (!settings.alpha || rgba.a === 1 && !settings.forceAlpha) { 1057 return "rgb(" + rgba.r + ", " + rgba.g + ", " + rgba.b + ")"; 1058 } else { 1059 return "rgba(" + rgba.r + ", " + rgba.g + ", " + rgba.b + ", " + rgba.a + ")"; 1060 } 1061 } 1062 1063 /** 1064 * Convert HSLA values to a CSS hsl/hsla string. 1065 * @param {object} hsla Hue, saturation, lightness and alpha values. 1066 * @return {string} CSS color string. 1067 */ 1068 function HSLAToStr(hsla) { 1069 if (!settings.alpha || hsla.a === 1 && !settings.forceAlpha) { 1070 return "hsl(" + hsla.h + ", " + hsla.s + "%, " + hsla.l + "%)"; 1071 } else { 1072 return "hsla(" + hsla.h + ", " + hsla.s + "%, " + hsla.l + "%, " + hsla.a + ")"; 1073 } 1074 } 1075 1076 /** 1077 * Init the color picker. 1078 */ 1079 function init() { 1080 // Render the UI 1081 var checkEditorMode = (typeof PAGE_MODE != 'undefined' && PAGE_MODE == 'c'); 1082 var alphaInfoLabel = checkEditorMode ? _coloris_label[(LANG === 'ko') ? 'ko' : 'en'].alpha_info : ''; 1083 1084 container = undefined; 1085 picker_backdrop = document.createElement('div'); 1086 picker_backdrop.setAttribute('id', 'clr-picker-backdrop'); 1087 picker_backdrop.className = 'clr-picker-backdrop'; 1088 1089 picker = document.createElement('div'); 1090 picker.setAttribute('id', 'clr-picker'); 1091 picker.className = 'clr-picker'; 1092 picker.innerHTML = ` 1093 <div class="clr-body"> 1094 <div class="clr-section top"> 1095 <div id="clr-color-area" class="clr-gradient" role="application" aria-label="${settings.a11y.instruction}"> 1096 <div id="clr-color-marker" class="clr-marker" tabindex="0"></div> 1097 <div id="clr-color-cursor" class="clr-cursor" tabindex="-1"></div> 1098 <div class="back-black"></div> 1099 <div id="clr-color-comment" class="clr-comment" tabindex="-2">${alphaInfoLabel}</div> 1100 </div> 1101 <div class="clr-hue"> 1102 <input id="clr-hue-slider" inputmode="none" onfocus="this.blur()" name="clr-hue-slider" type="range" min="0" max="360" step="1" aria-label="${settings.a11y.hueSlider}"> 1103 <div id="clr-hue-marker" class="clr-hue-marker"></div> 1104 </div> 1105 <div class="clr-color-info hex"> 1106 <div class="info-label"> 1107 ${settings.a11y.hexLabel} 1108 </div> 1109 <div class="info-val"> 1110 <input id="clr-hex-value" name="clr-hex-value" class="clr-hex-value" type="text" value="" aria-label="${settings.a11y.hexInput}"> 1111 </div> 1112 </div> 1113 <div class="clr-alpha"> 1114 <input id="clr-alpha-slider" inputmode="none" onfocus="this.blur()" name="clr-alpha-slider" type="range" min="0" max="100" step="1" aria-label="${settings.a11y.alphaSlider}"> 1115 <div id="clr-alpha-marker" class="clr-alpha-marker"></div> 1116 <span></span> 1117 </div> 1118 <div class="clr-color-info alpha"> 1119 <div class="info-label"> 1120 ${settings.a11y.alphaLabel} 1121 </div> 1122 <div class="info-val"> 1123 <input id="clr-alpha-value" name="clr-alpha-value" class="clr-alpha-value" type="number" value="" aria-label="${settings.a11y.alphaInput}"> 1124 </div> 1125 </div> 1126 </div> 1127 <div class="clr-section center"> 1128 <div id="clr-format" class="clr-format"> 1129 <fieldset class="clr-segmented"> 1130 <legend>${settings.a11y.format}</legend> 1131 <input id="clr-f1" type="radio" name="clr-format" value="hex"> 1132 <label for="clr-f1">Hex</label> 1133 <input id="clr-f2" type="radio" name="clr-format" value="rgb"> 1134 <label for="clr-f2">RGB</label> 1135 <input id="clr-f3" type="radio" name="clr-format" value="hsl"> 1136 <label for="clr-f3">HSL</label>
1137 <span></span> 1138 </fieldset> 1139 </div> 1140 <div class="clr-color-info color hide"> 1141 <div class="info-label"> 1142 ${settings.a11y.inputLabel} 1143 <span class="bc-tooltip colorisguide">${tooltipSVG('top','',`${_coloris_label[(LANG === 'ko') ? 'ko' : 'en'].guide}`,'')}</span> 1144 </div> 1145 <div class="info-val"> 1146 <input id="clr-color-value" name="clr-color-value" class="clr-color" type="text" value="" spellcheck="false" aria-label="${settings.a11y.input}"> 1147 </div> 1148 </div> 1149 <div id="clr-swatches" class="clr-swatches"></div> 1150 </div> 1151 <div class="clr-section bottom"> 1152 <div class="clr-palette-box ready" id="clr-palette-box"> 1153 <div id="clr-color-preview" class="clr-preview"></div> 1154 <div id="clr-color-current" class="clr-current"></div> 1155 </div> 1156 <div class="clr-btn-box" id="clr-btn-box"> 1157 <button type="button" id="clr-clear" class="clr-clear" aria-label="${settings.a11y.clear}">${settings.clearLabel}</button> 1158 <button type="button" id="clr-cancel" class="clr-cancel" aria-label="${settings.a11y.cancel}">${settings.cancelLabel}</button> 1159 <button type="button" id="clr-close" class="clr-close" aria-label="${settings.a11y.close}">${settings.closeLabel}</button> 1160 </div> 1161 </div> 1162 <span id="clr-open-label" hidden>${settings.a11y.open}</span> 1163 <span id="clr-swatch-label" hidden>${settings.a11y.swatch}</span> 1164 </div> 1165 `; 1166 1167 /* 1168 picker.innerHTML = 1169 "<input id=\"clr-color-value\" name=\"clr-color-value\" class=\"clr-color\" type=\"text\" value=\"\" spellcheck=\"false\" aria-label=\"" + settings.a11y.input + "\">" + ("<div id=\"clr-color-area\" class=\"clr-gradient\" role=\"application\" aria-label=\"" + 1170 settings.a11y.instruction + "\">") + 1171 '<div id="clr-color-marker" class="clr-marker" tabindex="0"></div>' + 1172 '</div>' + 1173 '<div class="clr-hue">' + ("<input id=\"clr-hue-slider\" name=\"clr-hue-slider\" type=\"range\" min=\"0\" max=\"360\" step=\"1\" aria-label=\"" + 1174 settings.a11y.hueSlider + "\">") + 1175 '<div id="clr-hue-marker"></div>' + 1176 '</div>' + 1177 '<div class="clr-alpha">' + ("<input id=\"clr-alpha-slider\" name=\"clr-alpha-slider\" type=\"range\" min=\"0\" max=\"100\" step=\"1\" aria-label=\"" + 1178 settings.a11y.alphaSlider + "\">") + 1179 '<div id="clr-alpha-marker"></div>' + 1180 '<span></span>' + 1181 '</div>' + 1182 '<div id="clr-format" class="clr-format">' + 1183 '<fieldset class="clr-segmented">' + ("<legend>" + 1184 settings.a11y.format + "</legend>") + 1185 '<input id="clr-f1" type="radio" name="clr-format" value="hex">' + 1186 '<label for="clr-f1">Hex</label>' + 1187 '<input id="clr-f2" type="radio" name="clr-format" value="rgb">' + 1188 '<label for="clr-f2">RGB</label>' + 1189 '<input id="clr-f3" type="radio" name="clr-format" value="hsl">' + 1190 '<label for="clr-f3">HSL</label>' + 1191 '<span></span>' + 1192 '</fieldset>' + 1193 '</div>' + 1194 '<div id="clr-swatches" class="clr-swatches"></div>' + ("<button type=\"button\" id=\"clr-clear\" class=\"clr-clear\" aria-label=\"" + 1195 settings.a11y.clear + "\">" + settings.clearLabel + "</button>") + 1196 '<div id="clr-color-preview" class="clr-preview">' + ("<button type=\"button\" id=\"clr-close\" class=\"clr-close\" aria-label=\"" + 1197 settings.a11y.close + "\">" + settings.closeLabel + "</button>") + 1198 '</div>' + ("<span id=\"clr-open-label\" hidden>" + 1199 settings.a11y.open + "</span>") + ("<span id=\"clr-swatch-label\" hidden>" + 1200 settings.a11y.swatch + "</span>"); 1201 */ 1202 1203 1204 // Append the color picker to the DOM 1205 picker.querySelectorAll('input').forEach(excludeColorFieldAutofill); 1206 document.body.appendChild(picker); 1207 document.body.appendChild(picker_backdrop); 1208 1209 // Reference the UI elements 1210 colorArea = getEl('clr-color-area'); 1211 colorMarker = getEl('clr-color-marker'); 1212 colorCursor = getEl('clr-color-cursor'); 1213 btnBox = getEl('clr-btn-box'); 1214 clearButton = getEl('clr-clear'); 1215 cancelButton = getEl('clr-cancel'); 1216 closeButton = getEl('clr-close'); 1217 paletteBox = getEl('clr-palette-box'); 1218 colorPreview = getEl('clr-color-preview'); 1219 colorCurrent = getEl('clr-color-current'); 1220 colorValue = getEl('clr-color-value'); 1221 hueSlider = getEl('clr-hue-slider'); 1222 hueMarker = getEl('clr-hue-marker'); 1223 hexInput = getEl('clr-hex-value'); 1224 alphaInput = getEl('clr-alpha-value'); 1225 alphaSlider = getEl('clr-alpha-slider'); 1226 alphaMarker = getEl('clr-alpha-marker'); 1227 1228 // Bind the picker to the default selector 1229 bindFields(settings.el); 1230 wrapFields(settings.el); 1231 1232 addListener(picker_backdrop, 'mousedown', function (event) { 1233 closePicker(true); 1234 }); 1235 1236 addListener(picker, 'mousedown', function (event) { 1237 picker.classList.remove('clr-keyboard-nav'); 1238 event.stopPropagation(); 1239 }); 1240 1241 addListener(colorArea, 'mousedown', function (event) { 1242 addListener(document, 'mousemove', moveMarker); 1243 }); 1244 1245 addListener(colorArea, 'touchstart', function (event) { 1246 document.addEventListener('touchmove', moveMarker, { passive: false }); 1247 }); 1248 1249 addListener(colorArea, 'mousemove', function (event) { 1250 var tmpColorCursor = document.querySelector('.clr-cursor'); 1251 tmpColorCursor.style.top = (event.pageY - Math.round($('#clr-color-area').offset().top) + 1) + 'px'; 1252 tmpColorCursor.style.left = (event.pageX - Math.round($('#clr-color-area').offset().left) - 1) + 'px'; 1253 }); 1254 1255 addListener(colorMarker, 'mousedown', function (event) { 1256 addListener(document, 'mousemove', moveMarker); 1257 }); 1258 1259 addListener(colorMarker, 'touchstart', function (event) { 1260 document.addEventListener('touchmove', moveMarker, { passive: false }); 1261 }); 1262 1263 addListener(colorValue, 'change', function (event) { 1264 var value = colorValue.value; 1265 1266 if (currentEl || settings.inline) { 1267 var color = value === '' ? value : setColorFromStr(value); 1268 pickColor(color); 1269 } 1270 1271 $('#clr-color-comment').addClass('hide'); 1272 $('.back-black').addClass('hide'); 1273 if(alphaInput.value == 0) { 1274 $('#clr-color-comment').removeClass('hide'); 1275 $('.back-black').removeClass('hide'); 1276 } 1277 });
1278 addListener(colorValue, 'keyup', function(e) { if(e.which == 13) { $(this).closest('.clr-picker').find('.clr-close').click(); } }); 1279 1280 addListener(clearButton, 'click', function (event) { 1281 pickColor(''); 1282 closePicker(); 1283 }); 1284 1285 addListener(closeButton, 'click', function (event) { 1286 pickColor(); 1287 closePicker(); 1288 }); 1289 1290 addListener(cancelButton, 'click', function (event) { 1291 closePicker(true); 1292 }); 1293 1294 addListener(getEl('clr-format'), 'click', '.clr-format input', function (event) { 1295 currentFormat = event.target.value; 1296 updateColor(); 1297 pickColor(); 1298 }); 1299 1300 addListener(picker, 'click', '.clr-swatches button', function (event) { 1301 setColorFromStr(event.target.textContent); 1302 // pickColor(); 1303 1304 if (settings.swatchesOnly) { 1305 closePicker(); 1306 } 1307 }); 1308 1309 addListener(document, 'mouseup', function (event) { 1310 document.removeEventListener('mousemove', moveMarker); 1311 }); 1312 1313 addListener(document, 'touchend', function (event) { 1314 document.removeEventListener('touchmove', moveMarker); 1315 }); 1316 1317 addListener(document, 'mousedown', function (event) { 1318 keyboardNav = false;
1319 picker.classList.remove('clr-keyboard-nav'); 1320 closePicker(); 1321 }); 1322 1323 addListener(document, 'keydown', function (event) { 1324 var key = event.key; 1325 var target = event.target; 1326 var shiftKey = event.shiftKey; 1327 var navKeys = ['Tab', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight']; 1328 1329 if (key === 'Escape') { 1330 closePicker(true); 1331 1332 // Display focus rings when using the keyboard 1333 } else if (navKeys.includes(key)) { 1334 keyboardNav = true; 1335 picker.classList.add('clr-keyboard-nav'); 1336 } 1337 1338 // Trap the focus within the color picker while it's open 1339 if (key === 'Tab' && target.matches('.clr-picker *')) { 1340 var focusables = getFocusableElements(); 1341 var firstFocusable = focusables.shift(); 1342 var lastFocusable = focusables.pop(); 1343 1344 if (shiftKey && target === firstFocusable) { 1345 lastFocusable.focus(); 1346 event.preventDefault(); 1347 } else if (!shiftKey && target === lastFocusable) { 1348 firstFocusable.focus(); 1349 event.preventDefault(); 1350 } 1351 } 1352 }); 1353 1354 addListener(document, 'click', '.clr-field button', function (event) { 1355 // Reset any previously set per-instance options 1356 if (hasInstance) { 1357 resetVirtualInstance(); 1358 } 1359 1360 // Open the color picker 1361 event.target.nextElementSibling.dispatchEvent(new Event('click', { bubbles: true })); 1362 }); 1363 1364 addListener(colorMarker, 'keydown', function (event) { 1365 var movements = { 1366 ArrowUp: [0, -1], 1367 ArrowDown: [0, 1], 1368 ArrowLeft: [-1, 0], 1369 ArrowRight: [1, 0] }; 1370 1371 1372 if (Object.keys(movements).includes(event.key)) { 1373 moveMarkerOnKeydown.apply(void 0, movements[event.key]); 1374 event.preventDefault(); 1375 } 1376 }); 1377 1378 addListener(colorArea, 'click', moveMarker); 1379 addListener(hueSlider, 'input', setHue); 1380 1381 addListener(alphaInput, 'input', setAlphaInput); 1382 addListener(alphaInput, 'keyup', function(e) { if(e.which == 13) { $(this).closest('.clr-picker').find('.clr-close').click(); } }); 1383 addListener(alphaSlider, 'input', setAlpha); 1384 1385 addListener(hexInput, 'change', function (event) { 1386 var hex6 = hexInput.value, 1387 alpha = (settings.alpha) ? alphaInput.value : 100, 1388 new_color = getChangeColorVal([hex6,'a',alpha / 100]); 1389 1390 if (currentEl || settings.inline) { 1391 var color = new_color === '' ? hex6 : setColorFromStr(new_color); 1392 pickColor(color); 1393 } 1394 }); 1395 addListener(hexInput, 'keyup', function(e) { if(e.which == 13) { $(this).closest('.clr-picker').find('.clr-close').click(); } }); 1396 1397 } 1398 1399 /** 1400 * Return a list of focusable elements within the color picker. 1401 * @return {array} The list of focusable DOM elemnts. 1402 */ 1403 function getFocusableElements() { 1404 var controls = Array.from(picker.querySelectorAll('input, button')); 1405 var focusables = controls.filter(function (node) {return !!node.offsetWidth;}); 1406 1407 return focusables; 1408 } 1409 1410 /** 1411 * Shortcut for getElementById to optimize the minified JS. 1412 * @param {string} id The element id. 1413 * @return {object} The DOM element with the provided id. 1414 */ 1415 function getEl(id) { 1416 return document.getElementById(id); 1417 } 1418 1419 /** 1420 * Shortcut for addEventListener to optimize the minified JS. 1421 * @param {object} context The context to which the listener is attached. 1422 * @param {string} type Event type. 1423 * @param {(string|function)} selector Event target if delegation is used, event handler if not. 1424 * @param {function} [fn] Event handler if delegation is used. 1425 */ 1426 function addListener(context, type, selector, fn) { 1427 var matches = Element.prototype.matches || Element.prototype.msMatchesSelector; 1428 1429 // Delegate event to the target of the selector 1430 if (typeof selector === 'string') { 1431 context.addEventListener(type, function (event) { 1432 if (matches.call(event.target, selector)) { 1433 fn.call(event.target, event); 1434 } 1435 }); 1436 1437 // If the selector is not a string then it's a function 1438 // in which case we need a regular event listener 1439 } else { 1440 fn = selector;
1441 context.addEventListener(type, fn); 1442 } 1443 } 1444 1445 /** 1446 * Call a function only when the DOM is ready. 1447 * @param {function} fn The function to call. 1448 * @param {array} [args] Arguments to pass to the function. 1449 */ 1450 function DOMReady(fn, args) { 1451 args = args !== undefined ? args : []; 1452 1453 if($.inArray(fn.name, checkReturnFuncArr) > -1) return fn(args); 1454 1455 if (document.readyState !== 'loading') { 1456 fn.apply(void 0, args); 1457 } else { 1458 document.addEventListener('DOMContentLoaded', function () { 1459 fn.apply(void 0, args); 1460 }); 1461 } 1462 } 1463 1464 1465 function getColorSelectorPnInfo(args_arr) { 1466 var css = args_arr[0], 1467 elname = (typeof args_arr[1] != 'undefined') ? args_arr[1] : '', 1468 selector = (typeof args_arr[2] != 'undefined') ? args_arr[2] : '', 1469 pn = (typeof args_arr[3] != 'undefined') ? args_arr[3] : '', 1470 withcss = (typeof args_arr[4] != 'undefined') ? args_arr[4] : '', 1471 result = {'selector':selector, 'pn':pn, 'color':''} 1472 1473 var this_selector = '', 1474 this_pn = '', 1475 this_color = '', 1476 this_css = {}; 1477 1478 var elnameRegex = new RegExp('^\.' + elname), 1479 checkSelectorWidthElname = (selector.match(elnameRegex) != null) ? true : false; 1480 1481 $.each(selector.split(','), function(i,s) { 1482 if(i > 0) this_selector += ','; 1483 this_selector += (checkSelectorWidthElname) ? s.trim() : '.' + elname + ' ' + s.trim(); 1484 1485 var tmp_pn = pn.split(','), 1486 tmp_s = s.trim(), 1487 tmp_changepn = s.match(/^(.*?)(?=\([^)]*\)$)/); 1488 if(tmp_changepn != null) { 1489 tmp_pn = s.substring(tmp_changepn[0].length + 1, s.length - 1).split('/'); 1490 tmp_s = tmp_changepn[0].trim(); 1491 } 1492 1493 var tmp_selector = (checkSelectorWidthElname) ? tmp_s : '.' + elname + ' ' + tmp_s, 1494 tmp_style = style.get(css,tmp_selector); 1495 if(typeof this_css[tmp_selector] == 'undefined') this_css[tmp_selector] = {}; 1496 1497 if(withcss) { 1498 $.each(withcss.split(','), function(i,v) { 1499 if(!v) return; 1500 1501 if($.inArray(v, ['fill','color','background','background-color','border-color','border','border-top','border-bottom','border-left','border-right']) > -1) { 1502 if(tmp_pn.indexOf(v) < 0) tmp_pn.push(v); 1503 return; 1504 } 1505 1506 var tmp_v = ''; 1507 switch(v) { 1508 case 'font-family': tmp_v = tmp_style.txName; break; 1509 case 'font-size': tmp_v = tmp_style.txSize; break; 1510 default: tmp_v = style.getCssProperty(css,tmp_selector,v); break; 1511 } 1512 1513 this_css[tmp_selector][v] = {'val': tmp_v}; 1514 }); 1515 } 1516 1517 $.each(tmp_pn, function(i,v) { 1518 var tmp_color = ''; 1519 switch(v) { 1520 case 'fill': tmp_color = tmp_style.fill; break; 1521 case 'color': tmp_color = tmp_style.txColor; break; 1522 case 'background': 1523 case 'background-color': tmp_color = tmp_style.bgColor; break; 1524 case 'border-color': 1525 case 'border': 1526 case 'border-top': 1527 case 'border-bottom': 1528 case 'border-left': 1529 case 'border-right': tmp_color = tmp_style.borderColor; break; 1530 default: break; 1531 } 1532 1533 if(v) { 1534 this_css[tmp_selector][v] = { 1535 'val': style.getCssProperty(css,tmp_selector,v), 1536 'color': Coloris.getColorInfo(tmp_color,'org'), 1537 }; 1538 1539 if(typeof this_css[tmp_selector][v]['val'] != 'string') this_css[tmp_selector][v]['val'] = this_css[tmp_selector][v]['val'].pop(); 1540 1541 if(pn.split(',').length > 1 && pn.split(',').indexOf(v) > -1) { 1542 this_css[tmp_selector][v]['checkPass'] = (this_css[tmp_selector][v]['color'] == '' && $.inArray(this_css[tmp_selector][v]['val'], ['initial','inherit']) > -1) ? true : false; 1543 } 1544 } 1545 1546 1547 if(i == 0) { 1548 this_pn = v; 1549 this_color = tmp_color; 1550 } 1551 }); 1552 }); 1553 1554 return { 1555 'selector': this_selector, 1556 'pn': this_pn, 1557 'color': this_color, 1558 'css': this_css, 1559 } 1560 } 1561 1562 function getColorInfo(args_arr) { 1563 var tmp_str = args_arr[0], 1564 return_type = (typeof args_arr[1] != 'undefined' && args_arr[1]) ? args_arr[1] : 'hex8'; 1565 1566 var str = (typeof tmp_str == 'string') ? tmp_str : tmp_str.pop(), 1567 colorRegex = getColorRegex(), 1568 tmp_matches = str.match(colorRegex); 1569 if(tmp_matches != null) str = tmp_matches.pop(); 1570 if(return_type == 'org') return str; 1571 1572 var this_rgba = strToRGBA(str), 1573 this_hex = RGBAToHex(this_rgba); 1574 1575 if(return_type == 'hex' || return_type == 'rgb') { 1576 this_rgba['a'] = 1; 1577 return (return_type == 'rgb') ? RGBAToStr(this_rgba) : RGBAToHex(this_rgba); 1578 } 1579 else if(return_type == 'rgba') return RGBAToStr(this_rgba); 1580 else if(return_type == 'alpha') return this_rgba['a']; 1581 else return this_hex; 1582 } 1583 1584 function getColorRegex() {
1585 return new RegExp(/(#([a-fA-F0-9]{3,8})\b|rgba?\(\s*(\d{1,3}\s*,\s*){2}\d{1,3}\s*(,\s*\d*(?:\.\d+)?)?\s*\)|hsla?\(\s*\d{1,3}\s*,\s*\d{1,3}%\s*,\s*\d{1,3}%\s*(,\s*\d*(?:\.\d+)?)?\s*\)|\btransparent\b|\binherit\b|\binitial\b|\bunset\b|\brevert\b)/g); 1586 } 1587 1588 function getChangeColorVal(args_arr) { 1589 var str = args_arr[0], 1590 change_key = (typeof args_arr[1] != 'undefined' && args_arr[1]) ? args_arr[1] : '', 1591 change_val = (typeof args_arr[2] != 'undefined' && args_arr[2]) ? args_arr[2] : ''; 1592 1593 var this_rgba = strToRGBA(str), 1594 this_hex = RGBAToHex(this_rgba); 1595 if(change_key == '' && change_val == '') return this_hex.substring(0, 7); 1596 if(change_key == 'rgb_str') return this_rgba.r+','+this_rgba.g+','+this_rgba.b; 1597 1598 if(change_key && typeof this_rgba[change_key] != 'undefined') { 1599 this_rgba[change_key] = change_val * 1; 1600 } 1601 1602 var org_alpha = settings.alpha; 1603 if(change_key == 'a') settings.alpha = true; 1604 var hex = RGBAToHex(this_rgba); 1605 if(change_key == 'a') settings.alpha = org_alpha; 1606 1607 if(this_rgba.a < 1) return 'rgba('+this_rgba.r+','+this_rgba.g+','+this_rgba.b+','+this_rgba.a+')'; 1608 else return hex; 1609 // opaqueHex = hex.substring(0, 7); 1610 } 1611 1612 1613 // Polyfill for Nodelist.forEach 1614 if (NodeList !== undefined && NodeList.prototype && !NodeList.prototype.forEach) { 1615 NodeList.prototype.forEach = Array.prototype.forEach; 1616 } 1617 1618 // Expose the color picker to the global scope 1619 window.Coloris = function () { 1620 var methods = { 1621 set: configure, 1622 wrap: wrapFields, 1623 close: closePicker, 1624 setInstance: setVirtualInstance, 1625 removeInstance: removeVirtualInstance, 1626 updatePosition: updatePickerPosition, 1627 ready: DOMReady 1628 }; 1629 1630 $.each(checkUsedFuncArr, function(i,fname) { 1631 methods[fname] = eval(fname); 1632 }); 1633 1634 $.each(checkReturnFuncArr, function(i,fname) { 1635 methods[fname] = eval(fname); 1636 }); 1637 1638 function Coloris(options) { 1639 DOMReady(function () { 1640 if (options) { 1641 if (typeof options === 'string') { 1642 bindFields(options); 1643 } else { 1644 configure(options); 1645 } 1646 } 1647 }); 1648 } 1649 1650 var _loop2 = function _loop2(key) { 1651 Coloris[key] = function () { 1652 for (var _len = arguments.length, args = new Array(_len), _key2 = 0; _key2 < _len; _key2++) { 1653 args[_key2] = arguments[_key2]; 1654 } 1655 1656 if($.inArray(key, checkReturnFuncArr) > -1) return DOMReady(methods[key], args); 1657 else DOMReady(methods[key], args); 1658 }; 1659 }; 1660 1661 1662 for (var key in methods) { 1663 _loop2(key); 1664 } 1665 1666 return Coloris; 1667 }(); 1668 1669 // Init the color picker when the DOM is ready 1670 DOMReady(init); 1671 1672 })(window, document, Math);
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.