1/*! 2 * pickadate.js v3.6.4, 2019/05/25 3 * By Amsul, http://amsul.ca 4 * Hosted on http://amsul.github.io/pickadate.js 5 * Licensed under MIT 6 */ 7 8(function (factory) { 9 10 // AMD. 11 if (typeof define == 'function' && define.amd) 12 define('picker', ['jquery'], factory) 13 14 // Node.js/browserify. 15 else if (typeof exports == 'object') 16 module.exports = factory(require('jquery')) 17 18 // Browser globals. 19 else if (typeof window == 'object') 20 window.Picker = factory(jQuery) 21 22 else this.Picker = factory(jQuery) 23 24}(function ($) { 25 26 var $window = $(window) 27 var $document = $(document) 28 var $html = $(document.documentElement) 29 var supportsTransitions = document.documentElement.style.transition != null 30 31 32 /** 33 * The picker constructor that creates a blank picker. 34 */ 35 function PickerConstructor(ELEMENT, NAME, COMPONENT, OPTIONS) { 36 37 // If thereâs no element, return the picker constructor. 38 if (!ELEMENT) return PickerConstructor 39 40 41 var 42 IS_DEFAULT_THEME = false, 43 44 45 // The state of the picker. 46 STATE = { 47 id: ELEMENT.id || 'P' + Math.abs(~~(Math.random() * new Date())), 48 handlingOpen: false, 49 }, 50 51 52 // Merge the defaults and options passed. 53 SETTINGS = COMPONENT ? $.extend(true, {}, COMPONENT.defaults, OPTIONS) : OPTIONS || {}, 54 55 56 // Merge the default classes with the settings classes. 57 CLASSES = $.extend({}, PickerConstructor.klasses(), SETTINGS.klass), 58 59 60 // The element node wrapper into a jQuery object. 61 $ELEMENT = $(ELEMENT), 62 63 64 // Pseudo picker constructor. 65 PickerInstance = function () { 66 return this.start() 67 }, 68 69 70 // The picker prototype. 71 P = PickerInstance.prototype = { 72 73 constructor: PickerInstance, 74 75 $node: $ELEMENT, 76 77 78 /** 79 * Initialize everything 80 */ 81 start: function () { 82 83 // If itâs already started, do nothing. 84 if (STATE && STATE.start) return P 85 86 87 // Update the picker states. 88 STATE.methods = {} 89 STATE.start = true 90 STATE.open = false 91 STATE.type = ELEMENT.type 92 93 94 // Confirm focus state, convert into text input to remove UA stylings, 95 // and set as readonly to prevent keyboard popup. 96 ELEMENT.autofocus = ELEMENT == getActiveElement() 97 ELEMENT.readOnly = !SETTINGS.editable 98 SETTINGS.id = ELEMENT.id = ELEMENT.id || STATE.id 99 if (ELEMENT.type != 'text') { 100 ELEMENT.type = 'text' 101 } 102 103 // Create a new picker component with the settings. 104 P.component = new COMPONENT(P, SETTINGS) 105 106 107 // Create the picker root and then prepare it. 108 P.$root = $('<div class="' + CLASSES.picker + '" id="' + ELEMENT.id + '_root" />') 109 prepareElementRoot() 110 111 112 // Create the picker holder and then prepare it. 113 P.$holder = $(createWrappedComponent()).appendTo(P.$root) 114 prepareElementHolder() 115 116 117 // If thereâs a format for the hidden input element, create the element. 118 if (SETTINGS.formatSubmit) { 119 prepareElementHidden() 120 } 121 122 123 // Prepare the input element. 124 prepareElement() 125 126 127 // Insert the hidden input as specified in the settings. 128 if (SETTINGS.containerHidden) $(SETTINGS.containerHidden).append(P._hidden) 129 else $ELEMENT.after(P._hidden) 130 131 132 // Insert the root as specified in the settings. 133 if (SETTINGS.container) $(SETTINGS.container).append(P.$root) 134 else $ELEMENT.after(P.$root) 135 136 137 // Bind the default component and settings events. 138 P.on({ 139 start: P.component.onStart, 140 render: P.component.onRender, 141 stop: P.component.onStop, 142 open: P.component.onOpen, 143 close: P.component.onClose, 144 set: P.component.onSet 145 }).on({ 146 start: SETTINGS.onStart, 147 render: SETTINGS.onRender, 148 stop: SETTINGS.onStop, 149 open: SETTINGS.onOpen, 150 close: SETTINGS.onClose, 151 set: SETTINGS.onSet 152 }) 153 154 155 // Once weâre all set, check the theme in use. 156 IS_DEFAULT_THEME = isUsingDefaultTheme(P.$holder[0]) 157 158 159 // If the element has autofocus, open the picker. 160 if (ELEMENT.autofocus) { 161 P.open() 162 } 163 164 165 // Trigger queued the âstartâ and ârenderâ events. 166 return P.trigger('start').trigger('render') 167 }, //start 168 169 170 /**
171 * Render a new picker 172 */ 173 render: function (entireComponent) { 174 175 // Insert a new component holder in the root or box. 176 if (entireComponent) { 177 P.$holder = $(createWrappedComponent()) 178 prepareElementHolder() 179 P.$root.html(P.$holder) 180 } 181 else P.$root.find('.' + CLASSES.box).html(P.component.nodes(STATE.open)) 182 183 // Trigger the queued ârenderâ events. 184 return P.trigger('render') 185 }, //render 186 187 188 /** 189 * Destroy everything 190 */ 191 stop: function () { 192 193 // If itâs already stopped, do nothing. 194 if (!STATE.start) return P 195 196 // Then close the picker. 197 P.close() 198 199 // Remove the hidden field. 200 if (P._hidden) { 201 P._hidden.parentNode.removeChild(P._hidden) 202 } 203 204 // Remove the root. 205 P.$root.remove() 206 207 // Remove the input class, remove the stored data, and unbind 208 // the events (after a tick for IE - see `P.close`). 209 $ELEMENT.removeClass(CLASSES.input).removeData(NAME) 210 setTimeout(function () { 211 $ELEMENT.off('.' + STATE.id) 212 }, 0) 213 214 // Restore the element state 215 ELEMENT.type = STATE.type 216 ELEMENT.readOnly = false 217 218 // Trigger the queued âstopâ events. 219 P.trigger('stop') 220 221 // Reset the picker states. 222 STATE.methods = {} 223 STATE.start = false 224 225 return P 226 }, //stop 227 228 229 /** 230 * Open up the picker 231 */ 232 open: function (dontGiveFocus) { 233 234 // If itâs already open, do nothing. 235 if (STATE.open) return P 236 237 // Add the âactiveâ class. 238 $ELEMENT.addClass(CLASSES.active) 239 240 // * A Firefox bug, when `html` has `overflow:hidden`, results in 241 // killing transitions :(. So add the âopenedâ state on the next tick. 242 // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 243 setTimeout(function () { 244 245 // Add the âopenedâ class to the picker root. 246 P.$root.addClass(CLASSES.opened) 247 aria(P.$root[0], 'hidden', false) 248 249 }, 0) 250 251 // If we have to give focus, bind the element and doc events. 252 if (dontGiveFocus !== false) { 253 254 // Set it as open. 255 STATE.open = true 256 257 // Prevent the page from scrolling. 258 if (IS_DEFAULT_THEME) { 259 $('body'). 260 css('overflow', 'hidden'). 261 css('padding-right', '+=' + getScrollbarWidth()) 262 } 263 264 // Pass focus to the root elementâs jQuery object. 265 focusPickerOnceOpened() 266 267 // Bind the document events. 268 $document.on('click.' + STATE.id + ' focusin.' + STATE.id, function (event) { 269 // If the picker is currently midway through processing 270 // the opening sequence of events then don't handle clicks 271 // on any part of the DOM. This is caused by a bug in Chrome 73 272 // where a click event is being generated with the incorrect 273 // path in it. 274 // In short, if someone does a click that finishes after the 275 // new element is created then the path contains only the 276 // parent element and not the input element itself. 277 if (STATE.handlingOpen) { 278 return; 279 } 280 281 var target = getRealEventTarget(event, ELEMENT) 282 283 // If the target of the event is not the element, close the picker picker. 284 // * Donât worry about clicks or focusins on the root because those donât bubble up. 285 // Also, for Firefox, a click on an `option` element bubbles up directly 286 // to the doc. So make sure the target wasn't the doc. 287 // * In Firefox stopPropagation() doesnât prevent right-click events from bubbling, 288 // which causes the picker to unexpectedly close when right-clicking it. So make 289 // sure the event wasnât a right-click. 290 // * In Chrome 62 and up, password autofill causes a simulated focusin event which 291 // closes the picker. 292 if (!event.isSimulated && target != ELEMENT && target != document && event.which != 3) { 293 294 // If the target was the holder that c
294overs the screen, 295 // keep the element focused to maintain tabindex. 296 P.close(target === P.$holder[0]) 297 } 298 299 }).on('keydown.' + STATE.id, function (event) { 300 301 var 302 // Get the keycode. 303 keycode = event.keyCode, 304 305 // Translate that to a selection change. 306 keycodeToMove = P.component.key[keycode], 307 308 // Grab the target. 309 target = getRealEventTarget(event, ELEMENT) 310 311 312 // On escape, close the picker and give focus. 313 if (keycode == 27) { 314 P.close(true) 315 } 316 317 318 // Check if there is a key movement or âenterâ keypress on the element. 319 else if (target == P.$holder[0] && (keycodeToMove || keycode == 13)) { 320 321 // Prevent the default action to stop page movement. 322 event.preventDefault() 323 324 // Trigger the key movement action. 325 if (keycodeToMove) { 326 PickerConstructor._.trigger(P.component.key.go, P, [PickerConstructor._.trigger(keycodeToMove)]) 327 } 328 329 // On âenterâ, if the highlighted item isnât disabled, set the value and close. 330 else if (!P.$root.find('.' + CLASSES.highlighted).hasClass(CLASSES.disabled)) { 331 P.set('select', P.component.item.highlight) 332 if (SETTINGS.closeOnSelect) { 333 P.close(true) 334 } 335 } 336 } 337 338 339 // If the target is within the root and âenterâ is pressed, 340 // prevent the default action and trigger a click on the target instead. 341 else if ($.contains(P.$root[0], target) && keycode == 13) { 342 event.preventDefault() 343 target.click() 344 } 345 }) 346 } 347 348 // Trigger the queued âopenâ events. 349 return P.trigger('open') 350 }, //open 351 352 353 /** 354 * Close the picker 355 */ 356 close: function (giveFocus) { 357 358 // If we need to give focus, do it before changing states. 359 if (giveFocus) { 360 if (SETTINGS.editable) { 361 ELEMENT.focus() 362 } 363 else { 364 // ....ah yes! It wouldâve been incomplete without a crazy workaround for IE :| 365 // The focus is triggered *after* the close has completed - causing it 366 // to open again. So unbind and rebind the event at the next tick. 367 P.$holder.off('focus.toOpen').focus() 368 setTimeout(function () { 369 P.$holder.on('focus.toOpen', handleFocusToOpenEvent) 370 }, 0) 371 } 372 } 373 374 // Remove the âactiveâ class. 375 $ELEMENT.removeClass(CLASSES.active) 376 377 // * A Firefox bug, when `html` has `overflow:hidden`, results in 378 // killing transitions :(. So remove the âopenedâ state on the next tick. 379 // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=625289 380 setTimeout(function () { 381 382 // Remove the âopenedâ and âfocusedâ class from the picker root. 383 P.$root.removeClass(CLASSES.opened + ' ' + CLASSES.focused) 384 aria(P.$root[0], 'hidden', true) 385 386 }, 0) 387 388 // If itâs already closed, do nothing more. 389 if (!STATE.open) return P 390 391 // Set it as closed. 392 STATE.open = false 393 394 // Allow the page to scroll. 395 if (IS_DEFAULT_THEME) { 396 $('body'). 397 css('overflow', ''). 398 css('padding-right', '-=' + getScrollbarWidth()) 399 } 400 401 // Unbind the document events. 402 $document.off('.' + STATE.id) 403 404 // Trigger the queued âcloseâ events. 405 return P.trigger('close') 406 }, //close 407 408 409 /** 410 * Clear the values 411 */ 412 clear: function (options) { 413 return P.set('clear', null, options) 414 }, //clear 415 416 417 /** 418 * Set something 419 */ 420 set: function (thing, value, options) { 421 422 var thingItem, thingValue, 423 thingIsObject = $.isPlainObject(thing), 424 thingObject = thingIsObject ? thing : {} 425 426 // Make sure we have usable options. 427 options = thingIsObject && $.isPlainObject(value) ? value : options || {} 428 429 if (thing) { 430 431 // If the thing isnât an object, make it one. 432 if (!thingIsObject) { 433 thingObject[thing] = value 434 } 435 436 // Go through the things of items to set. 437 for (thingItem in thingObject) { 438 439 // Grab the value of the thing. 440 thingValue = thingObject[thingItem] 441 442 // First, if the item exists and thereâs a value, set it. 443 if (thingItem in P.component.item) { 444 if (thingValue === undefined) thingValue = null 445 P.component.set(thingItem, thingValue, options) 446 } 447 448 // Then, check to update the element value and broadcast a change. 449 if ((thingItem == 'select' || thingItem == 'clear') && SETTINGS.updateInput) { 450 $ELEMENT. 451 val(thingItem == 'clear' ? '' : P.get(thingItem, SETTINGS.format)). 452 trigger('change') 453 } 454 } 455 456 // Render a new picker. 457 P.render() 458 } 459 460 // When the method isnât muted, trigger queued âsetâ events and pass the `thingObject`. 461 return options.muted ? P : P.trigger('set', thingObject) 462 }, //set 463 464 465 /** 466 * Get something 467 */ 468 get: function (thing, format) { 469 470 // Make sure thereâs something to get. 471 thing = thing || 'value' 472 473 // If a picker state exists, return that. 474 if (STATE[thing] != null) { 475 return STATE[thing] 476 } 477 478 // Return the submission value, if that. 479 if (thing == 'valueSubmit') { 480 if (P._hidden) { 481 return P._hidden.value 482 } 483 thing = 'value' 484 } 485 486 // Return the value, if that. 487 if (thing == 'value') { 488 return ELEMENT.value 489 } 490 491 // Check if a component item exists, return that. 492 if (thing in P.component.item) { 493 if (typeof format == 'string') { 494 var thingValue = P.component.get(thing) 495 return thingValue ? 496 PickerConstructor._.trigger( 497 P.component.formats.toString, 498 P.component, 499 [format, thingValue] 500 ) : '' 501 } 502 return P.component.get(thing) 503 } 504 }, //get 505 506 507 508 /** 509 * Bind events on the things. 510 */ 511 on: function (thing, method, internal) { 512 513 var thingName, thingMethod, 514 thingIsObject = $.isPlainObject(thing), 515 thingObject = thingIsObject ? thing : {} 516 517 if (thing) { 518 519 // If the thing isnât an object, make it one. 520 if (!thingIsObject) { 521 thingObject[thing] = method 522 } 523 524 // Go through the things to bind to. 525 for (thingName in thingObject) { 526 527 // Grab the method of the thing. 528 thingMethod = thingObject[thingName] 529 530 // If it was an internal binding, prefix it. 531 if (internal) { 532 thingName = '_' + thingName 533 } 534 535 // Make sure the thing methods collection exists. 536 STATE.methods[thingName] = STATE.methods[thingName] || [] 537 538 // Add the method to the relative method collection. 539 STATE.methods[thingName].push(thingMethod) 540 } 541 } 542 543 return P 544 }, //on 545 546 547 548 /** 549 * Unbind events on the things. 550 */ 551 off: function () { 552 var i, thingName, 553 names = arguments; 554 for (i = 0, namesCount = names.length; i < namesCount; i += 1) { 555 thingName = names[i] 556 if (thingName in STATE.methods) { 557 delete STATE.methods[thingName] 558 } 559 } 560 return P 561 }, 562 563 564 /** 565 * Fire off method events. 566 */ 567 trigger: function (name, data) { 568 var _trigger = function (name) { 569 var methodList = STATE.methods[name] 570 if (methodList) { 571 methodList.map(function (method) { 572 PickerConstructor._.trigger(method, P, [data]) 573 }) 574 } 575 } 576 _trigger('_' + name) 577 _trigger(name) 578 return P 579 }
579 //trigger 580 } //PickerInstance.prototype 581 582 583 /** 584 * Wrap the picker holder components together. 585 */ 586 function createWrappedComponent() { 587 588 // Create a picker wrapper holder 589 return PickerConstructor._.node('div', 590 591 // Create a picker wrapper node 592 PickerConstructor._.node('div', 593 594 // Create a picker frame 595 PickerConstructor._.node('div', 596 597 // Create a picker box node 598 PickerConstructor._.node('div', 599 600 // Create the components nodes. 601 P.component.nodes(STATE.open), 602 603 // The picker box class 604 CLASSES.box 605 ), 606 607 // Picker wrap class 608 CLASSES.wrap 609 ), 610 611 // Picker frame class 612 CLASSES.frame 613 ), 614 615 // Picker holder class 616 CLASSES.holder, 617 618 'tabindex="-1"' 619 ) //endreturn 620 } //createWrappedComponent 621 622 /** 623 * Prepare the input element with all bindings. 624 */ 625 function prepareElement() { 626 627 $ELEMENT. 628 629 // Store the picker data by component name. 630 data(NAME, P). 631 632 // Add the âinputâ class name. 633 addClass(CLASSES.input). 634 635 // If thereâs a `data-value`, update the value of the element. 636 val($ELEMENT.data('value') ? 637 P.get('select', SETTINGS.format) : 638 ELEMENT.value 639 ). 640 641 // On focus/click, open the picker. 642 on('focus.' + STATE.id + ' click.' + STATE.id, 643 function (event) { 644 event.preventDefault() 645 P.open() 646 } 647 ) 648 649 // Mousedown handler to capture when the user starts interacting 650 // with the picker. This is used in working around a bug in Chrome 73. 651 .on('mousedown', function () { 652 STATE.handlingOpen = true; 653 var handler = function () { 654 // By default mouseup events are fired before a click event. 655 // By using a timeout we can force the mouseup to be handled 656 // after the corresponding click event is handled. 657 setTimeout(function () { 658 $(document).off('mouseup', handler); 659 STATE.handlingOpen = false; 660 }, 0); 661 }; 662 $(document).on('mouseup', handler); 663 }); 664 665 666 // Only bind keydown events if the element isnât editable. 667 if (!SETTINGS.editable) { 668 669 $ELEMENT. 670 671 // Handle keyboard event based on the picker being opened or not. 672 on('keydown.' + STATE.id, handleKeydownEvent) 673 } 674 675 676 // Update the aria attributes. 677 aria(ELEMENT, { 678 haspopup: true, 679 readonly: false, 680 owns: ELEMENT.id + '_root' 681 }) 682 } 683 684 685 /** 686 * Prepare the root picker element with all bindings. 687 */ 688 function prepareElementRoot() { 689 aria(P.$root[0], 'hidden', true) 690 } 691 692 693 /** 694 * Prepare the holder picker element with all bindings. 695 */ 696 function prepareElementHolder() { 697 698 P.$holder. 699 700 on({ 701 702 // For iOS8. 703 keydown: handleKeydownEvent, 704 705 'focus.toOpen': handleFocusToOpenEvent, 706 707 blur: function () { 708 // Remove the âtargetâ class. 709 $ELEMENT.removeClass(CLASSES.target) 710 }, 711 712 // When something within the holder is focused, stop from bubbling 713 // to the doc and remove the âfocusedâ state from the root. 714 focusin: function (event) { 715 P.$root.removeClass(CLASSES.focused) 716 event.stopPropagation() 717 }, 718 719 // When something within the holder is clicked, stop it 720 // from bubbling to the doc. 721 'mousedown click': function (event) { 722 723 var target = getRealEventTarget(event, ELEMENT) 724 725 // Make sure the target isnât the root holder so it can bubble up. 726 if (target != P.$holder[0]) { 727 728 event.stopPropagation() 729 730 // * For mousedown events, cancel the default action in order to 731 // prevent cases where focus is shifted onto external elements 732 // when using things like jQuery mobile or MagnificPopup (ref: #249 & #120). 733 // Also, for Firefox, donât prevent action on the `option` element. 734 if (event.type == 'mousedown' && !$(target).is('input, select, textarea, button, option')) { 735 736 event.preventDefault() 737 738 // Re-focus onto the holder so that users can click away 739 // from elements focused within the picker. 740 P.$holder.eq(0).focus() 741 } 742 } 743 } 744 745 }). 746 747 // If thereâs a click on an actionable element, carry out the actions.
748 on('click', '[data-pick], [data-nav], [data-clear], [data-close]', function () { 749 750 var $target = $(this), 751 targetData = $target.data(), 752 targetDisabled = $target.hasClass(CLASSES.navDisabled) || $target.hasClass(CLASSES.disabled), 753 754 // * For IE, non-focusable elements can be active elements as well 755 // (http://stackoverflow.com/a/2684561). 756 activeElement = getActiveElement() 757 activeElement = activeElement && ((activeElement.type || activeElement.href) ? activeElement : null); 758 759 // If itâs disabled or nothing inside is actively focused, re-focus the element. 760 if (targetDisabled || activeElement && !$.contains(P.$root[0], activeElement)) { 761 P.$holder.eq(0).focus() 762 } 763 764 // If something is superficially changed, update the `highlight` based on the `nav`. 765 if (!targetDisabled && targetData.nav) { 766 P.set('highlight', P.component.item.highlight, { nav: targetData.nav }) 767 } 768 769 // If something is picked, set `select` then close with focus. 770 else if (!targetDisabled && 'pick' in targetData) { 771 P.set('select', targetData.pick) 772 if (SETTINGS.closeOnSelect) { 773 P.close(true) 774 } 775 } 776 777 // If a âclearâ button is pressed, empty the values and close with focus. 778 else if (targetData.clear) { 779 P.clear() 780 if (SETTINGS.closeOnClear) { 781 P.close(true) 782 } 783 } 784 785 else if (targetData.close) { 786 P.close(true) 787 } 788 789 }) //P.$holder 790 791 } 792 793 794 /** 795 * Prepare the hidden input element along with all bindings. 796 */ 797 function prepareElementHidden() { 798 799 var name 800 801 if (SETTINGS.hiddenName === true) { 802 name = ELEMENT.name 803 ELEMENT.name = '' 804 } 805 else { 806 name = [ 807 typeof SETTINGS.hiddenPrefix == 'string' ? SETTINGS.hiddenPrefix : '', 808 typeof SETTINGS.hiddenSuffix == 'string' ? SETTINGS.hiddenSuffix : '_submit' 809 ] 810 name = name[0] + ELEMENT.name + name[1] 811 } 812 813 P._hidden = $('<input>', { 814 type: 'hidden', 815 name: name, 816 value: $ELEMENT.data('value') || ELEMENT.value ? P.get('select', SETTINGS.formatSubmit) : '' 817 })[0] 818 819 $ELEMENT. 820 821 // If the value changes, update the hidden input with the correct format. 822 on('change.' + STATE.id, function () { 823 P._hidden.value = ELEMENT.value ? 824 P.get('select', SETTINGS.formatSubmit) : 825 '' 826 }) 827 } 828 829 830 // Wait for transitions to end before focusing the holder. Otherwise, while 831 // using the `container` option, the view jumps to the container. 832 function focusPickerOnceOpened() { 833 834 if (IS_DEFAULT_THEME && supportsTransitions) { 835 P.$holder.find('.' + CLASSES.frame).one('transitionend', function () { 836 P.$holder.eq(0).focus() 837 }) 838 } 839 else { 840 setTimeout(function () { 841 P.$holder.eq(0).focus() 842 }, 0) 843 } 844 } 845 846 847 function handleFocusToOpenEvent(event) { 848 849 // Stop the event from propagating to the doc. 850 event.stopPropagation() 851 852 // Add the âtargetâ class. 853 $ELEMENT.addClass(CLASSES.target) 854 855 // Add the âfocusedâ class to the root. 856 P.$root.addClass(CLASSES.focused) 857 858 // And then finally open the picker. 859 P.open() 860 } 861 862 863 // For iOS8. 864 function handleKeydownEvent(event) { 865 866 var keycode = event.keyCode, 867 868 // Check if one of the delete keys was pressed. 869 isKeycodeDelete = /^(8|46)$/.test(keycode) 870 871 // For some reason IE clears the input value on âescapeâ. 872 if (keycode == 27) { 873 P.close(true) 874 return false 875 } 876 877 // Check if `space` or `delete` was pressed or the picker is closed with a key movement. 878 if (keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode]) { 879
880 // Prevent it from moving the page and bubbling to doc. 881 event.preventDefault() 882 event.stopPropagation() 883 884 // If `delete` was pressed, clear the values and close the picker. 885 // Otherwise open the picker. 886 if (isKeycodeDelete) { P.clear().close() } 887 else { P.open() } 888 } 889 } 890 891 892 // Return a new picker instance. 893 return new PickerInstance() 894 } //PickerConstructor 895 896 897 898 /** 899 * The default classes and prefix to use for the HTML classes. 900 */ 901 PickerConstructor.klasses = function (prefix) { 902 prefix = prefix || 'picker' 903 return { 904 905 picker: prefix, 906 opened: prefix + '--opened', 907 focused: prefix + '--focused', 908 909 input: prefix + '__input', 910 active: prefix + '__input--active', 911 target: prefix + '__input--target', 912 913 holder: prefix + '__holder', 914 915 frame: prefix + '__frame', 916 wrap: prefix + '__wrap', 917 918 box: prefix + '__box' 919 } 920 } //PickerConstructor.klasses 921 922 923 924 /** 925 * Check if the default theme is being used. 926 */ 927 function isUsingDefaultTheme(element) { 928 929 var theme, 930 prop = 'position' 931 932 // For IE. 933 if (element.currentStyle) { 934 theme = element.currentStyle[prop] 935 } 936 937 // For normal browsers. 938 else if (window.getComputedStyle) { 939 theme = getComputedStyle(element)[prop] 940 } 941 942 return theme == 'fixed' 943 } 944 945 946 947 /** 948 * Get the width of the browserâs scrollbar. 949 * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js 950 */ 951 function getScrollbarWidth() { 952 953 if ($html.height() <= $window.height()) { 954 return 0 955 } 956 957 var $outer = $('<div style="visibility:hidden;width:100px" />'). 958 appendTo('body') 959 960 // Get the width without scrollbars. 961 var widthWithoutScroll = $outer[0].offsetWidth 962 963 // Force adding scrollbars. 964 $outer.css('overflow', 'scroll') 965 966 // Add the inner div. 967 var $inner = $('<div style="width:100%" />').appendTo($outer) 968 969 // Get the width with scrollbars. 970 var widthWithScroll = $inner[0].offsetWidth 971 972 // Remove the divs. 973 $outer.remove() 974 975 // Return the difference between the widths. 976 return widthWithoutScroll - widthWithScroll 977 } 978 979 980 981 /** 982 * Get the target element from the event. 983 * If ELEMENT is supplied and present in the event path (ELEMENT is ancestor of the target), 984 * returns ELEMENT instead 985 */ 986 function getRealEventTarget(event, ELEMENT) { 987 988 var path = [] 989 990 if (event.path) { 991 path = event.path 992 } 993 994 if (event.originalEvent && event.originalEvent.path) { 995 path = event.originalEvent.path 996 } 997 998 if (path && path.length > 0) { 999 if (ELEMENT && path.indexOf(ELEMENT) >= 0) { 1000 return ELEMENT 1001 } else { 1002 return path[0] 1003 } 1004 } 1005 1006 return event.target 1007 } 1008 1009 /** 1010 * PickerConstructor helper methods. 1011 */ 1012 PickerConstructor._ = { 1013 1014 /** 1015 * Create a group of nodes. Expects: 1016 * ` 1017 { 1018 min: {Integer}, 1019 max: {Integer}, 1020 i: {Integer}, 1021 node: {String}, 1022 item: {Function} 1023 } 1024 * ` 1025 */ 1026 group: function (groupObject) { 1027 1028 var 1029 // Scope for the looped object 1030 loopObjectScope, 1031 1032 // Create the nodes list 1033 nodesList = '', 1034 1035 // The counter starts from the `min` 1036 counter = PickerConstructor._.trigger(groupObject.min, groupObject) 1037 1038 1039 // Loop from the `min` to `max`, incrementing by `i` 1040 for (; counter <= PickerConstructor._.trigger(groupObject.max, groupObject, [counter]); counter += groupObject.i) { 1041 1042 // Trigger the `item` function within scope of the object 1043 loopObjectScope = PickerConstructor._.trigger(groupObject.item, groupObject, [counter]) 1044 1045 // Splice the subgroup and create nodes out of the sub nodes 1046 nodesList += PickerConstructor._.node( 1047 groupObject.node, 1048 loopObjectScope[0], // the node 1049 loopObjectScope[1], // the classes 1050 loopObjectScope[2] // the attributes 1051 ) 1052 } 1053 1054 // Return the list of nodes 1055 return nodesList 1056 }, //group 1057 1058 1059 /** 1060 * Create a dom node string 1061 */ 1062 node: function (wrapper, item, klass, attribute) { 1063 1064 // If the item is false-y, just return an empty string 1065 if (!item) return '' 1066 1067 // If the item is an array, do a join 1068 item = $.isArray(item) ? item.join('') : item 1069 1070 // Check for the class 1071 klass = klass ? ' class="' + klass + '"' : '' 1072 1073 // Check for any attributes 1074 attribute = attribute ? ' ' + attribute : '' 1075 1076 // Return the wrapped item 1077 return '<' + wrapper + klass + attribute + '>' + item + '</' + wrapper + '>' 1078 }, //node 1079 1080 1081 /** 1082 * Lead numbers below 10 with a zero. 1083 */ 1084 lead: function (number) { 1085 return (number < 10 ? '0' : '') + number 1086 }, 1087 1088 1089 /** 1090 * Trigger a function otherwise return the value. 1091 */ 1092 trigger: function (callback, scope, args) { 1093 return typeof callback == 'function' ? callback.apply(scope, args || []) : callback 1094 }, 1095 1096 1097 /** 1098 * If the second character is a digit, length is 2 otherwise 1. 1099 */ 1100 digits: function (string) { 1101 return (/\d/).test(string[1]) ? 2 : 1 1102 }, 1103 1104 1105 /** 1106 * Tell if something is a date object. 1107 */ 1108 isDate: function (value) { 1109 return {}.toString.call(value).indexOf('Date') > -1 && this.isInteger(value.getDate()) 1110 }, 1111 1112 1113 /** 1114 * Tell if something is an integer. 1115 */ 1116 isInteger: function (value) { 1117 return {}.toString.call(value).indexOf('Number') > -1 && value % 1 === 0 1118 }, 1119 1120 1121 /** 1122 * Create ARIA attribute strings. 1123 */ 1124 ariaAttr: ariaAttr 1125 } //PickerConstructor._ 1126 1127 1128 1129 /** 1130 * Extend the picker with a component and defaults. 1131 */ 1132 PickerConstructor.extend = function (name, Component) { 1133 1134 // Extend jQuery. 1135 $.fn[name] = function (options, action) { 1136 1137 // Grab the component data. 1138 var componentData = this.data(name) 1139 1140 // If the picker is requested, return the data object. 1141 if (options == 'picker') { 1142 return componentData 1143 } 1144 1145 // If the component data exists and `options` is a string, carry out the action. 1146 if (componentData && typeof options == 'string') { 1147 return PickerConstructor._.trigger(componentData[options], componentData, [action]) 1148 } 1149 1150 // Otherwise go through each matched element and if the component 1151 // doesnât exist, create a new picker using `this` element 1152 // and merging the defaults and options with a deep copy. 1153 return this.each(function () { 1154 var $this = $(this) 1155 if (!$this.data(name)) { 1156 new PickerConstructor(this, name, Component, options) 1157 } 1158 }) 1159 } 1160 1161 // Set the defaults. 1162 $.fn[name].defaults = Component.defaults 1163 } //PickerConstructor.extend 1164 1165 1166 1167 function aria(element, attribute, value) { 1168 if ($.isPlainObject(attribute)) { 1169 for (var key in attribute) { 1170 ariaSet(element, key, attribute[key]) 1171 } 1172 } 1173 else { 1174 ariaSet(element, attribute, value) 1175 } 1176 } 1177 function ariaSet(element, attribute, value) { 1178 element.setAttribute( 1179 (attribute == 'role' ? '' : 'aria-') + attribute, 1180 value 1181 ) 1182 } 1183 function ariaAttr(attribute, data) { 1184 if (!$.isPlainObject(attribute)) { 1185 attribute = { attribute: data } 1186 } 1187 data = '' 1188 for (var key in attribute) { 1189 var attr = (key == 'role' ? '' : 'aria-') + key, 1190 attrVal = attribute[key] 1191 data += attrVal == null ? '' : attr + '="' + attribute[key] + '"' 1192 } 1193 return data 1194 } 1195 1196 // IE8 bug throws an error for activeElements within iframes. 1197 function getActiveElement() { 1198 try { 1199 return document.activeElement 1200 } catch (err) { } 1201 } 1202 1203 1204 1205 // Expose the picker constructor. 1206 return PickerConstructor 1207 1208 1209}));
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.