PageSourceSearch

https://lifesmarts.org/wp-content/plugins/the-events-calendar/src/resources/js/views/datepicker.js?ver=6.0.0.1

js lifesmarts.org collected 2026-10-02 02:12:08 UTC 18,384 bytes, 736 lines download raw bytes

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.