1/** 2 * Makes sure we have all the required levels on the Tribe Object 3 * 4 * @since 4.9.5 5 * 6 * @type {Object} 7 */ 8tribe.events = tribe.events || {}; 9tribe.events.views = tribe.events.views || {}; 10 11/** 12 * Configures Datepicker Object in the Global Tribe variable 13 * 14 * @since 4.9.5 15 * 16 * @type {Object} 17 */ 18tribe.events.views.datepicker = {}; 19 20/** 21 * Initializes in a Strict env the code that manages the Event Views 22 * 23 * @since 4.9.5 24 * 25 * @param {Object} $ jQuery 26 * @param {Object} obj tribe.events.views.datepicker 27 * 28 * @return {void} 29 */ 30( function( $, obj ) { 31 'use strict'; 32 var $document = $( document ); 33 34 /** 35 * Selectors used for configuration and setup 36 * 37 * @since 4.9.5 38 * 39 * @type {Object} 40 */ 41 obj.selectors = { 42 datepickerFormClass: '.tribe-events-c-top-bar__datepicker-form', 43 datepickerContainer: '[data-js="tribe-events-top-bar-datepicker-container"]', 44 datepickerDaysBody: '.datepicker-days tbody', 45 input: '[data-js="tribe-events-top-bar-date"]', 46 button: '[data-js="tribe-events-top-bar-datepicker-button"]', 47 buttonOpenClass: '.tribe-events-c-top-bar__datepicker-button--open', 48 dateInput: '[name="tribe-events-views[tribe-bar-date]"]', 49 prevIconTemplate: '.tribe-events-c-top-bar__datepicker-template-prev-icon', 50 nextIconTemplate: '.tribe-events-c-top-bar__datepicker-template-next-icon', 51 }; 52 53 /** 54 * Object of state 55 * 56 * @since 4.9.5 57 * 58 * @type {Object} 59 */ 60 obj.state = { 61 initialized: false, 62 }; 63 64 /** 65 * Object of datepicker options 66 * 67 * @since 4.9.10 68 * 69 * @type {Object} 70 */ 71 obj.options = { 72 container: null, 73 daysOfWeekDisabled: [], 74 maxViewMode: 'decade', 75 minViewMode: 'month', 76 orientation: 'bottom left', 77 showOnFocus: false, 78 templates: { 79 leftArrow: '', 80 rightArrow: '', 81 }, 82 }; 83 84 /** 85 * Object of key codes 86 * 87 * @since 5.0.0 88 * 89 * @type {Object} 90 */ 91 obj.keyCode = { 92 ENTER: 13, 93 }; 94 95 /** 96 * Date object representing today 97 * 98 * @since 4.9.13 99 * 100 * @type {Date|null} 101 */ 102 obj.today = null; 103 104 /** 105 * Object of date format map. 106 * Date formats are mapped from PHP to Bootstrap Datepicker format. 107 * 108 * @since 4.9.11 109 * 110 * @type {Object} 111 * 112 * @see https://bootstrap-datepicker.readthedocs.io/en/latest/options.html#format 113 */ 114 obj.dateFormatMap = { 115 d: 'dd', 116 j: 'd', 117 m: 'mm', 118 n: 'm', 119 Y: 'yyyy', 120 }; 121 122 /** 123 * Mutation observer to watch for mutations 124 * 125 * @since 4.9.10 126 * 127 * @type {MutationObserver} 128 */ 129 obj.observer = null; 130 131 /** 132 * Pads number with extra 0 if needed to make it double digit 133 * 134 * @since 4.9.5 135 * 136 * @param {integer} number number to pad with extra 0 137 * 138 * @return {string} string representation of padded number 139 */ 140 obj.padNumber = function( number ) { 141 var numStr = number + ''; 142 var padding = numStr.length > 1 ? '' : '0'; 143 return padding + numStr; 144 }; 145 146 /** 147 * Performs an AJAX request using manager.js request method 148 * 149 * @since 4.9.5 150 * 151 * @param {object} viewData object of view data 152 * @param {jQuery} $container jQuery object of view container 153 * 154 * @return {void} 155 */ 156 obj.request = function( viewData, $container ) { 157 var data = { 158 view_data: viewData, 159 _wpnonce: $container.data( 'view-rest-nonce' ), 160 }; 161 162 tribe.events.views.manager.request( data, $container ); 163 }; 164 165 /** 166 * Create the Date input that will be preprended on the form created. 167 * 168 * @since 4.9.11 169 * 170 * @param {string} value string representation of the date value 171 * 172 * @return {jQuery} 173 */ 174 obj.createDateInputObj = function( value ) { 175 var $input = $( '<input>' ); 176 $input.attr( { 177 type: 'hidden', 178 name: 'tribe-events-views[tribe-bar-date]', 179 value: value, 180 } ); 181 182 return $input; 183 }; 184 185 /** 186 * Submits request after date change from datepicker based on live refresh setting. 187 * 188 * @since 4.9.11 189 * 190 * @param {jQuery} $container jQuery object of view container 191 * @param {string} value string representation of the date value 192 * 193 * @return {void} 194 */ 195 obj.submitRequest = function( $container, value ) { 196 var viewData = {}; 197 viewData[ 'tribe-bar-date' ] = value, 198 199 obj.request( viewData, $container ); 200 }; 201 202 /** 203 * Handle datepicker changeDate event 204 * 205 * @since 4.9.5 206 * 207 * @param {Event} event event object for 'changeDate' event 208 * 209 * @return {void} 210 */ 211 obj.handleChangeDate = function( event ) { 212 var $container = event.data.container; 213 var date = event.date.getDate();
214 var month = event.date.getMonth() + 1; 215 var year = event.date.getFullYear(); 216 217 var paddedDate = obj.padNumber( date ); 218 var paddedMonth = obj.padNumber( month ); 219 220 var dateValue = [ year, paddedMonth, paddedDate ].join( '-' ); 221 222 obj.submitRequest( $container, dateValue ); 223 }; 224 225 /** 226 * Handle datepicker changeMonth event 227 * 228 * @since 4.9.5 229 * 230 * @param {Event} event event object for 'changeMonth' event 231 * 232 * @return {void} 233 */ 234 obj.handleChangeMonth = function( event ) { 235 var $container = event.data.container; 236 var month, year; 237 238 if ( event.date ) { 239 month = event.date.getMonth() + 1; 240 year = event.date.getFullYear(); 241 } else { 242 var date = $container 243 .find( obj.selectors.input ) 244 .bootstrapDatepicker( 'getDate' ); 245 month = date.getMonth() + 1; 246 year = date.getFullYear(); 247 } 248 249 var paddedMonth = obj.padNumber( month ); 250 251 var dateValue = [ year, paddedMonth ].join( '-' ); 252 253 obj.submitRequest( $container, dateValue ); 254 }; 255 256 /** 257 * Handle datepicker keydown event 258 * 259 * @since 5.0.0 260 * 261 * @param {Event} event event object for 'keydown' event 262 * 263 * @return {void} 264 */ 265 obj.handleKeyDown = function(event) { 266 if ( event.keyCode !== obj.keyCode.ENTER ) { 267 return; 268 } 269 270 event.data.input.bootstrapDatepicker().trigger( 'changeMonth' ); 271 } 272 273 /** 274 * Handle datepicker show event 275 * 276 * @since 4.9.13 277 * 278 * @param {Event} event event object for 'show' event 279 * 280 * @return {void} 281 */ 282 obj.handleShow = function( event ) { 283 event.data.datepickerButton.addClass( obj.selectors.buttonOpenClass.className() ); 284 }; 285 286 /** 287 * Handle datepicker hide event 288 * 289 * @since 4.9.8 290 * 291 * @param {Event} event event object for 'hide' event 292 * 293 * @return {void} 294 */ 295 obj.handleHide = function( event ) { 296 var $datepickerButton = event.data.datepickerButton; 297 var state = $datepickerButton.data( 'tribeEventsState' ); 298 299 event.data.observer.disconnect(); 300 301 if ( state.isTarget ) { 302 event.data.input.bootstrapDatepicker( 'show' ); 303 return; 304 } 305 306 $datepickerButton 307 .removeClass( obj.selectors.buttonOpenClass.className() ) 308 .trigger( 'focus' ); 309 }; 310 311 /** 312 * Handle datepicker button mousedown 313 * 314 * @since 4.9.8 315 * 316 * @param {Event} event event object for 'mousedown' event 317 * 318 * @return {void} 319 */ 320 obj.handleMousedown = function( event ) { 321 var $datepickerButton = event.data.target; 322 var state = $datepickerButton.data( 'tribeEventsState' ); 323 324 if ( 'touchstart' === event.type ) { 325 var method = $datepickerButton.hasClass( obj.selectors.buttonOpenClass.className() ) 326 ? 'hide' 327 : 'show'; 328 var tapHide = 'hide' === method; 329 state.isTarget = false;
330 331 $datepickerButton 332 .data( 'tribeTapHide', tapHide ) 333 .data( 'tribeEventsState', state ) 334 .off( 'mousedown', obj.handleMousedown ); 335 336 return; 337 } 338 339 state.isTarget = true; 340 $datepickerButton.data( 'tribeEventsState', state ); 341 }; 342 343 /** 344 * Handle datepicker button click 345 * 346 * @since 4.9.8 347 * 348 * @param {Event} event event object for 'click' event 349 * 350 * @return {void} 351 */ 352 obj.handleClick = function( event ) { 353 var $input = event.data.input; 354 var $datepickerButton = event.data.target; 355 var state = $datepickerButton.data( 'tribeEventsState' ); 356 var method = $datepickerButton.hasClass( obj.selectors.buttonOpenClass.className() ) 357 ? 'hide' 358 : 'show'; 359 var tapHide = $datepickerButton.data( 'tribeTapHide' ); 360 361 if ( tapHide ) { 362 return; 363 } 364 365 state.isTarget = false; 366 367 $datepickerButton.data( 'tribeEventsState', state ); 368 $input.bootstrapDatepicker( method ); 369 370 if ( 'show' === method ) { 371 $input.trigger( 'focus' ); 372 } 373 }; 374 375 /** 376 * Curry function to handle mutations 377 * Used to pass in `data` 378 * 379 * @since 4.9.7 380 * 381 * @param {Object} data data object to be passed for use in handler 382 * 383 * @return {function} 384 */ 385 obj.handleMutation = function( data ) { 386 var $container = data.container; 387 388 /** 389 * Handle mutations from mutation observer 390 * 391 * @since 4.9.7 392 * 393 * @param {array} mutationsList list of mutations that have occurred 394 * @param {MutationObserver} observer mutation observer instance 395 * 396 * @return {void} 397 */ 398 return function( mutationsList, observer ) { // eslint-disable-line no-unused-vars 399 mutationsList.forEach( function( mutation ) { 400 // if datepicker switches months via prev/next arrows or by selecting a month on month picker 401 if ( 402 'childList' === mutation.type && 403 $container.find( obj.selectors.datepickerDaysBody ).is( mutation.target ) && 404 mutation.addedNodes.length 405 ) { 406 $container.trigger( 'handleMutationMonthChange.tribeEvents' ); 407 } 408 } ); 409 }; 410 }; 411 412 /** 413 * Set today to date object representing today 414 * 415 * @since 4.9.13 416 * 417 * @param {string} today string representation of today's date according to website time 418 * 419 * @return {void} 420 */ 421 obj.setToday = function( today ) { 422 var date = today; 423 if ( today.indexOf( ' ' ) >= 0 ) { 424 date = today.split( ' ' )[0]; 425 } 426 427 obj.today = new Date( date ); 428 }; 429 430 /** 431 * Determine whether or not date is the same as today. 432 * The function uses UTC values to maintain consistency with website date. 433 * Function will return false if proper unit is not provided. 434 * 435 * @since 4.9.13 436 * 437 * @param {Date} date Date object representing the date being compared 438 * @param {string} unit Unit to compare dates to 439 * 440 * @return {bool} 441 */ 442 obj.isSameAsToday = function( date, unit ) { 443 switch ( unit ) { 444 case 'year': 445 return date.getFullYear() === obj.today.getUTCFullYear(); 446 case 'month': 447 return obj.isSameAsToday( date, 'year' ) && date.getMonth() === obj.today.getUTCMonth(); 448 case 'day': 449 return obj.isSameAsToday( date, 'month' ) && date.getDate() === obj.today.getUTCDate(); 450 default: 451 return false; 452 } 453 } 454 455 /** 456 * Determine whether or not date is before today. 457 * The function uses UTC values to maintain consistency with website date. 458 * Function will return false if proper unit is not provided. 459 * 460 * @since 4.9.13 461 * 462 * @param {Date} date Date object representing the date being compared 463 * @param {string} unit Unit to compare dates to 464 * 465 * @return {bool} 466 */ 467 obj.isBeforeToday = function( date, unit ) { 468 switch ( unit ) { 469 case 'year': 470 return date.getFullYear() < obj.today.getUTCFullYear(); 471 case 'month': 472 return obj.isBeforeToday( date, 'year' ) 473 || ( obj.isSameAsToday( date, 'year' ) && date.getMonth() < obj.today.getUTCMonth() ); 474 case 'day': 475 return obj.isBeforeToday( date, 'month' ) 476 || ( obj.isSameAsToday( date, 'month' ) && date.getDate() < obj.today.getUTCDate() ); 477 default: 478 return false; 479 } 480 }; 481 482 /** 483 * Filter datepicker day cells 484 * 485 * @since 4.9.13 486 * 487 * @return {string|void} 488 */ 489 obj.filterDayCells = function( date ) { 490 if ( obj.isBeforeToday( date, 'day' ) ) { 491 return 'past'; 492 } else if ( obj.isSameAsToday( date, 'day' ) ) { 493 return 'current'; 494 } 495 }; 496 497 /** 498 * Filter datepicker month cells 499 * 500 * @since 4.9.13 501 * 502 * @return {string|void} 503 */ 504 obj.filterMonthCells = function( date ) { 505 if ( obj.isBeforeToday( date, 'month' ) ) { 506 return 'past'; 507 } else if ( obj.isSameAsToday( date, 'month' ) ) { 508 return 'current'; 509 } 510 }; 511 512 /** 513 * Filter datepicker year cells 514 * 515 * @since 4.9.13 516 * 517 * @return {string|void} 518 */ 519 obj.filterYearCells = function( date ) { 520 if ( obj.isBeforeToday( date, 'year' ) ) { 521 return 'past'; 522 } else if ( obj.isSameAsToday( date, 'year' ) ) { 523 return 'current'; 524 } 525 }; 526 527 /** 528 * Convert date format from PHP to Bootstrap datepicker format. 529 * 530 * @since 4.9.11 531 * 532 * @param {string} dateFormat datepicker date format in PHP format. 533 * 534 * @return {string} 535 */ 536 obj.convertDateFormat = function( dateFormat ) { 537 var convertedDateFormat = dateFormat; 538 Object.keys( obj.dateFormatMap ).forEach( function( key ) { 539 convertedDateFormat = convertedDateFormat.replace( key, obj.dateFormatMap[ key ] ); 540 } ); 541 542 return convertedDateFormat; 543 }; 544 545 /** 546 * Initialize datepicker date format. 547 * 548 * @since 4.9.11 549 * 550 * @param {object} data data object passed from 'afterSetup.tribeEvents' event 551 * 552 * @return {void} 553 */ 554 obj.initDateFormat = function( data ) { 555 var dateFormats = data.date_formats || {}; 556 var dateFormat = dateFormats.compact; 557 var convertedDateFormat = obj.convertDateFormat( dateFormat ); 558 obj.options.format = convertedDateFormat; 559 }; 560 561 /** 562 * Deinitialize datepicker JS 563 * 564 * @since 4.9.5 565 * 566 * @param {Event} event event object for 'beforeAjaxSuccess.tribeEvents' event 567 * @param {jqXHR} jqXHR Request object 568 * @param {Object} settings Settings that this request was made with 569 * 570 * @return {void} 571 */ 572 obj.deinit = function( event, jqXHR, settings ) { 573 var $container = event.data.container; 574 575 $container.trigger( 'beforeDatepickerDeinit.tribeEvents', [ jqXHR, settings ] ); 576 577 var $input = $container.find( obj.selectors.input ); 578 var $datepickerButton = $container.find( obj.selectors.button ); 579 580 $input.bootstrapDatepicker( 'destroy' ).off(); 581 $datepickerButton.off(); 582 $container.off( 'beforeAjaxSuccess.tribeEvents', obj.deinit ); 583 584 $container.trigger( 'afterDatepickerDeinit.tribeEvents', [ jqXHR, settings ] ); 585 }; 586 587 /** 588 * Initialize datepicker JS 589 * 590 * @since 4.9.8 591 * 592 * @param {Event} event event object for 'afterSetup.tribeEvents' event 593 * @param {integer} index jQuery.each index param from 'afterSetup.tribeEvents' event 594 * @param {jQuery} $container jQuery object of view container 595 * @param {object} data data object passed from 'afterSetup.tribeEvents' event 596 * 597 * @return {void} 598 */ 599 obj.init = function( event, index, $container, data ) { 600 $container.trigger( 'beforeDatepickerInit.tribeEvents', [ index, $container, data ] ); 601 602 var $input = $container.find( obj.selectors.input ); 603 var $datepickerButton = $container.find( obj.selectors.button ); 604 var $prevIcon = $container.find( obj.selectors.prevIconTemplate ).html(); 605 var $nextIcon = $container.find( obj.selectors.nextIconTemplate ).html(); 606 var viewSlug = data.slug; 607 var isMonthView = 'month' === viewSlug; 608 609 // set up datepicker change event and handler 610 var changeEvent = isMonthView ? 'changeMonth' : 'changeDate'; 611 var changeHandler = isMonthView ? obj.handleChangeMonth : obj.handleChangeDate; 612 613 // set up datepicker button state 614 var state = { 615 isTarget: false, 616 }; 617 618 // set up mutation observer 619 obj.observer = new MutationObserver( obj.handleMutation( { container: $container } ) ); 620 621 // set up today's date 622 obj.setToday( data.today ); 623 624 // set options for datepicker 625 obj.initDateFormat( data ); 626 obj.options.weekStart = data.start_of_week; 627 obj.options.container = $container.find( obj.selectors.datepickerContainer ); 628 obj.options.minViewMode = isMonthView ? 'year' : 'month'; 629 var tribeL10nDatatables = window.tribe_l10n_datatables || {}; 630 var datepickerI18n = tribeL10nDatatables.datepicker || {}; 631 var nextText = datepickerI18n.nextText || 'Next'; 632 var prevText = datepickerI18n.prevText || 'Prev'; 633 obj.options.templates.leftArrow = $prevIcon 634 + '<span class="tribe-common-a11y-visual-hide">' 635 + prevText 636 + '</span>'; 637 obj.options.templates.rightArrow = $nextIcon 638 + '<span class="tribe-common-a11y-visual-hide">' 639 + nextText 640 + '</span>'; 641 obj.options.beforeShowDay = obj.filterDayCells; 642 obj.options.beforeShowMonth = obj.filterMonthCells; 643 obj.options.beforeShowYear = obj.filterYearCells; 644 645 $input 646 .bootstrapDatepicker( obj.options ) 647 .on( changeEvent, { container: $container }, changeHandler ) 648 .on( 'show', { datepickerButton: $datepickerButton }, obj.handleShow ) 649 .on( 650 'hide',
651 { datepickerButton: $datepickerButton, input: $input, observer: obj.observer }, 652 obj.handleHide 653 ); 654 655 if ( isMonthView ) { 656 $input 657 .bootstrapDatepicker() 658 .on( 'keydown', { input: $input }, obj.handleKeyDown ); 659 } 660 661 $datepickerButton 662 .on( 'touchstart mousedown', { target: $datepickerButton }, obj.handleMousedown ) 663 .on( 'click', { target: $datepickerButton, input: $input }, obj.handleClick ) 664 .data( 'tribeEventsState', state ); 665 666 // deinit datepicker and event handlers before success 667 $container.on( 668 'beforeAjaxSuccess.tribeEvents', 669 { container: $container, viewSlug: viewSlug }, 670 obj.deinit 671 ); 672 673 $container.trigger( 'afterDatepickerInit.tribeEvents', [ index, $container, data ] ); 674 }; 675 676 /** 677 * Initialize datepicker i18n 678 * 679 * @since 4.9.5 680 * 681 * @return {void} 682 */ 683 obj.initDatepickerI18n = function() { 684 var tribeL10nDatatables = window.tribe_l10n_datatables || {}; 685 var datepickerI18n = tribeL10nDatatables.datepicker || {}; 686 687 datepickerI18n.dayNames && 688 ( $.fn.bootstrapDatepicker.dates.en.days = datepickerI18n.dayNames ); 689 datepickerI18n.dayNamesShort && 690 ( $.fn.bootstrapDatepicker.dates.en.daysShort = datepickerI18n.dayNamesShort ); 691 datepickerI18n.dayNamesMin && 692 ( $.fn.bootstrapDatepicker.dates.en.daysMin = datepickerI18n.dayNamesMin ); 693 datepickerI18n.monthNames && 694 ( $.fn.bootstrapDatepicker.dates.en.months = datepickerI18n.monthNames ); 695 datepickerI18n.monthNamesMin && 696 ( $.fn.bootstrapDatepicker.dates.en.monthsShort = datepickerI18n.monthNamesMin ); 697 datepickerI18n.today && 698 ( $.fn.bootstrapDatepicker.dates.en.today = datepickerI18n.today ); 699 datepickerI18n.clear && 700 ( $.fn.bootstrapDatepicker.dates.en.clear = datepickerI18n.clear ); 701 }; 702 703 /** 704 * Initialize datepicker to jQuery object 705 * 706 * @since 4.9.5 707 * 708 * @return {void} 709 */ 710 obj.initDatepicker = function() { 711 obj.initDatepickerI18n(); 712 obj.state.initialized = true; 713 }; 714 715 /** 716 * Handles the initialization of the Datepicker when Document is ready 717 * 718 * @since 4.9.5 719 * 720 * @return {void} 721 */ 722 obj.ready = function() { 723 obj.initDatepicker(); 724 725 if ( obj.state.initialized ) { 726 $document.on( 727 'afterSetup.tribeEvents', 728 tribe.events.views.manager.selectors.container, 729 obj.init 730 ); 731 } 732 }; 733 734 // Configure on document ready 735 $( obj.ready ); 736} )( jQuery, tribe.events.views.datepicker );
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.