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 26var $window = $( window ) 27var $document = $( document ) 28var $html = $( document.documentElement ) 29var supportsTransitions = document.documentElement.style.transition != null 30 31 32/** 33 * The picker constructor that creates a blank picker. 34 */ 35function 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 = $( 814 '<input ' + 815 'type=hidden ' + 816 817 // Create the name using the original inputâs with a prefix and suffix. 818 'name="' + name + '"' + 819 820 // If the element has a value, set the hidden value as well. 821 ( 822 $ELEMENT.data('value') || ELEMENT.value ? 823 ' value="' + P.get('select', SETTINGS.formatSubmit) + '"' : 824 '' 825 ) + 826 '>' 827 )[0] 828 829 $ELEMENT. 830 831 // If the value changes, update the hidden input with the correct format. 832 on('change.' + STATE.id, function() { 833 P._hidden.value = ELEMENT.value ? 834 P.get('select', SETTINGS.formatSubmit) : 835 '' 836 }) 837 } 838 839 840 // Wait for transitions to end before focusing the holder. Otherwise, while 841 // using the `container` option, the view jumps to the container. 842 function focusPickerOnceOpened() { 843 844 if (IS_DEFAULT_THEME && supportsTransitions) { 845 P.$holder.find('.' + CLASSES.frame).one('transitionend', function() { 846 P.$holder.eq(0).focus() 847 }) 848 } 849 else { 850 setTimeout(function() { 851 P.$holder.eq(0).focus() 852 }, 0) 853 } 854 } 855 856 857 function handleFocusToOpenEvent(event) { 858 859 // Stop the event from propagating to the doc. 860 event.stopPropagation() 861 862 // Add the âtargetâ class. 863 $ELEMENT.addClass( CLASSES.target ) 864 865 // Add the âfocusedâ class to the root. 866 P.$root.addClass( CLASSES.focused ) 867 868 // And then finally open the picker. 869 P.open() 870 } 871 872 873 // For iOS8. 874 function handleKeydownEvent( event ) { 875 876 var keycode = event.keyCode, 877 878 // Check if one of the delete keys was pressed. 879 isKeycodeDelete = /^(8|46)$/.test(keycode) 880 881 // For some reason IE clears the input value on âescapeâ. 882 if ( keycode == 27 ) { 883 P.close( true ) 884 return false 885 } 886 887 // Check if `space` or `delete` was pressed or the picker is closed with a key movement. 888 if ( keycode == 32 || isKeycodeDelete || !STATE.open && P.component.key[keycode] ) { 889
890 // Prevent it from moving the page and bubbling to doc. 891 event.preventDefault() 892 event.stopPropagation() 893 894 // If `delete` was pressed, clear the values and close the picker. 895 // Otherwise open the picker. 896 if ( isKeycodeDelete ) { P.clear().close() } 897 else { P.open() } 898 } 899 } 900 901 902 // Return a new picker instance. 903 return new PickerInstance() 904} //PickerConstructor 905 906 907 908/** 909 * The default classes and prefix to use for the HTML classes. 910 */ 911PickerConstructor.klasses = function( prefix ) { 912 prefix = prefix || 'picker' 913 return { 914 915 picker: prefix, 916 opened: prefix + '--opened', 917 focused: prefix + '--focused', 918 919 input: prefix + '__input', 920 active: prefix + '__input--active', 921 target: prefix + '__input--target', 922 923 holder: prefix + '__holder', 924 925 frame: prefix + '__frame', 926 wrap: prefix + '__wrap', 927 928 box: prefix + '__box' 929 } 930} //PickerConstructor.klasses 931 932 933 934/** 935 * Check if the default theme is being used. 936 */ 937function isUsingDefaultTheme( element ) { 938 939 var theme, 940 prop = 'position' 941 942 // For IE. 943 if ( element.currentStyle ) { 944 theme = element.currentStyle[prop] 945 } 946 947 // For normal browsers. 948 else if ( window.getComputedStyle ) { 949 theme = getComputedStyle( element )[prop] 950 } 951 952 return theme == 'fixed' 953} 954 955 956 957/** 958 * Get the width of the browserâs scrollbar. 959 * Taken from: https://github.com/VodkaBears/Remodal/blob/master/src/jquery.remodal.js 960 */ 961function getScrollbarWidth() { 962 963 if ( $html.height() <= $window.height() ) { 964 return 0 965 } 966 967 var $outer = $( '<div style="visibility:hidden;width:100px" />' ). 968 appendTo( 'body' ) 969 970 // Get the width without scrollbars. 971 var widthWithoutScroll = $outer[0].offsetWidth 972 973 // Force adding scrollbars. 974 $outer.css( 'overflow', 'scroll' ) 975 976 // Add the inner div. 977 var $inner = $( '<div style="width:100%" />' ).appendTo( $outer ) 978 979 // Get the width with scrollbars. 980 var widthWithScroll = $inner[0].offsetWidth 981 982 // Remove the divs. 983 $outer.remove() 984 985 // Return the difference between the widths. 986 return widthWithoutScroll - widthWithScroll 987} 988 989 990 991/** 992 * Get the target element from the event. 993 * If ELEMENT is supplied and present in the event path (ELEMENT is ancestor of the target), 994 * returns ELEMENT instead 995 */ 996function getRealEventTarget( event, ELEMENT ) { 997 998 var path = [] 999 1000 if ( event.path ) { 1001 path = event.path 1002 } 1003 1004 if ( event.originalEvent && event.originalEvent.path ) { 1005 path = event.originalEvent.path 1006 } 1007 1008 if ( path && path.length > 0 ) { 1009 if ( ELEMENT && path.indexOf( ELEMENT ) >= 0 ) { 1010 return ELEMENT 1011 } else { 1012 return path[0] 1013 } 1014 } 1015 1016 return event.target 1017} 1018 1019/** 1020 * PickerConstructor helper methods. 1021 */ 1022PickerConstructor._ = { 1023 1024 /** 1025 * Create a group of nodes. Expects: 1026 * ` 1027 { 1028 min: {Integer}, 1029 max: {Integer}, 1030 i: {Integer}, 1031 node: {String}, 1032 item: {Function} 1033 } 1034 * ` 1035 */ 1036 group: function( groupObject ) { 1037 1038 var 1039 // Scope for the looped object 1040 loopObjectScope, 1041 1042 // Create the nodes list 1043 nodesList = '', 1044 1045 // The counter starts from the `min` 1046 counter = PickerConstructor._.trigger( groupObject.min, groupObject ) 1047 1048 1049 // Loop from the `min` to `max`, incrementing by `i` 1050 for ( ; counter <= PickerConstructor._.trigger( groupObject.max, groupObject, [ counter ] ); counter += groupObject.i ) { 1051 1052 // Trigger the `item` function within scope of the object 1053 loopObjectScope = PickerConstructor._.trigger( groupObject.item, groupObject, [ counter ] ) 1054 1055 // Splice the subgroup and create nodes out of the sub nodes 1056 nodesList += PickerConstructor._.node( 1057 groupObject.node, 1058 loopObjectScope[ 0 ], // the node 1059 loopObjectScope[ 1 ], // the classes 1060 loopObjectScope[ 2 ] // the attributes 1061 ) 1062 } 1063 1064 // Return the list of nodes 1065 return nodesList 1066 }, //group 1067 1068 1069 /** 1070 * Create a dom node string 1071 */ 1072 node: function( wrapper, item, klass, attribute ) { 1073 1074 // If the item is false-y, just return an empty string 1075 if ( !item ) return '' 1076 1077 // If the item is an array, do a join 1078 item = $.isArray( item ) ? item.join( '' ) : item 1079 1080 // Check for the class 1081 klass = klass ? ' class="' + klass + '"' : '' 1082 1083 // Check for any attributes 1084 attribute = attribute ? ' ' + attribute : '' 1085 1086 // Return the wrapped item 1087 return '<' + wrapper + klass + attribute + '>' + item + '</' + wrapper + '>' 1088 }, //node 1089 1090 1091 /** 1092 * Lead numbers below 10 with a zero. 1093 */ 1094 lead: function( number ) { 1095 return ( number < 10 ? '0': '' ) + number 1096 }, 1097 1098 1099 /** 1100 * Trigger a function otherwise return the value. 1101 */ 1102 trigger: function( callback, scope, args ) { 1103 return typeof callback == 'function' ? callback.apply( scope, args || [] ) : callback 1104 }, 1105 1106 1107 /** 1108 * If the second character is a digit, length is 2 otherwise 1. 1109 */ 1110 digits: function( string ) { 1111 return ( /\d/ ).test( string[ 1 ] ) ? 2 : 1 1112 }, 1113 1114 1115 /** 1116 * Tell if something is a date object. 1117 */ 1118 isDate: function( value ) { 1119 return {}.toString.call( value ).indexOf( 'Date' ) > -1 && this.isInteger( value.getDate() ) 1120 }, 1121 1122 1123 /** 1124 * Tell if something is an integer. 1125 */ 1126 isInteger: function( value ) { 1127 return {}.toString.call( value ).indexOf( 'Number' ) > -1 && value % 1 === 0 1128 }, 1129 1130 1131 /** 1132 * Create ARIA attribute strings. 1133 */ 1134 ariaAttr: ariaAttr 1135} //PickerConstructor._ 1136 1137 1138 1139/** 1140 * Extend the picker with a component and defaults. 1141 */ 1142PickerConstructor.extend = function( name, Component ) { 1143 1144 // Extend jQuery. 1145 $.fn[ name ] = function( options, action ) { 1146 1147 // Grab the component data. 1148 var componentData = this.data( name ) 1149 1150 // If the picker is requested, return the data object. 1151 if ( options == 'picker' ) { 1152 return componentData 1153 } 1154 1155 // If the component data exists and `options` is a string, carry out the action. 1156 if ( componentData && typeof options == 'string' ) { 1157 return PickerConstructor._.trigger( componentData[ options ], componentData, [ action ] ) 1158 } 1159 1160 // Otherwise go through each matched element and if the component 1161 // doesnât exist, create a new picker using `this` element 1162 // and merging the defaults and options with a deep copy. 1163 return this.each( function() { 1164 var $this = $( this ) 1165 if ( !$this.data( name ) ) { 1166 new PickerConstructor( this, name, Component, options ) 1167 } 1168 }) 1169 } 1170 1171 // Set the defaults. 1172 $.fn[ name ].defaults = Component.defaults 1173} //PickerConstructor.extend 1174 1175 1176 1177function aria(element, attribute, value) { 1178 if ( $.isPlainObject(attribute) ) { 1179 for ( var key in attribute ) { 1180 ariaSet(element, key, attribute[key]) 1181 } 1182 } 1183 else { 1184 ariaSet(element, attribute, value) 1185 } 1186} 1187function ariaSet(element, attribute, value) { 1188 element.setAttribute( 1189 (attribute == 'role' ? '' : 'aria-') + attribute, 1190 value 1191 ) 1192} 1193function ariaAttr(attribute, data) { 1194 if ( !$.isPlainObject(attribute) ) { 1195 attribute = { attribute: data } 1196 } 1197 data = '' 1198 for ( var key in attribute ) { 1199 var attr = (key == 'role' ? '' : 'aria-') + key, 1200 attrVal = attribute[key] 1201 data += attrVal == null ? '' : attr + '="' + attribute[key] + '"' 1202 } 1203 return data 1204} 1205 1206// IE8 bug throws an error for activeElements within iframes. 1207function getActiveElement() { 1208 try { 1209 return document.activeElement 1210 } catch ( err ) { } 1211} 1212 1213 1214 1215// Expose the picker constructor. 1216return PickerConstructor 1217 1218 1219}));
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.