PageSourceSearch

https://www.nacacnet.org/wp-content/plugins/my-calendar/js/mcjs.js?ver=3.8.645940

js nacacnet.org collected 2026-09-24 08:36:01 UTC 17,468 bytes, 433 lines download raw bytes

1(() => {
2	const { __, _x, _n, _nx } = wp.i18n;
3
4	'use strict';
5	mc_display_usertime();
6	initjs();
7
8	function initjs( ref = false ) {
9		const calendar = document.querySelectorAll( '.mc-main, .mc-event-list' );
10		if ( calendar ) {
11			calendar.forEach( (el) => {
12				let targetId = ( ref ) ? ref : el.getAttribute( 'id' );
13				mc_build_toggles( targetId );
14				el.classList.remove( 'mcjs' );
15			});
16		}
17	}
18
19	const loadmore = document.querySelectorAll( '.mc-loader' );
20	if ( loadmore ) {
21		loadmore.forEach( (el) => {
22			const parent = el.closest( 'ul' );
23			parent.setAttribute( 'tabindex', '-1' );
24			parent.addEventListener( 'click', function( e ) {
25				let targetParent = e.target.closest( 'button' );
26				if ( targetParent && targetParent.classList.contains( 'mc-loader' ) ) {
27					loadUpcoming( targetParent, parent );
28				}
29			});
30		});
31	}
32
33	function loadUpcoming( el, parent ) {
34		let request = new XMLHttpRequest();
35
36		request.open( 'POST', my_calendar.ajaxurl, true );
37		request.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded;' );
38		request.onload = function () {
39			if ( this.status >= 200 && this.status < 400) {
40				let results = JSON.parse( this.response );
41				// Remove the list items.
42				parent.querySelectorAll( 'li' ).forEach( e => e.remove() );
43				// Append the response.
44				parent.innerHTML += results.response;
45				// Set focus to parent list.
46				parent.focus();
47				wp.a11y.speak( __( 'Upcoming events loaded', 'my-calendar' ) );
48			} else {
49				// Request failed.
50				parent.innerHTML += '<li>' + __( 'Upcoming Events failed to load', 'my-calendar' ) + '</li>';
51				wp.a11y.speak( __( 'Upcoming Events failed to load', 'my-calendar' ) );
52			}
53		};
54		request.onerror = function() {
55			// Connection error
56		};
57		let time = el.value;
58		let args = el.getAttribute( 'data-value' );
59		type = ( 'dates' === time ) ? 'dates' : 'time';
60
61		request.send('action=' + my_calendar.action + '&behavior=loadupcoming&' + type + '=' + time + '&args=' + args );
62	}
63
64	my_calendar_external_links();
65	mc_disclosures();
66	if ( 'true' === my_calendar.ajax ) {
67		//mc_render_buttons();
68		mc_setup_handlers();
69	} else {
70		mc_render_links();
71	}
72
73	function mc_setup_handlers() {
74		// Prevents spacebar from scrolling the page on links with button role.
75		let buttonHandlers = document.querySelectorAll('.my-calendar-header a:not(.mc-print a, .mc-export a), .my-calendar-footer a:not(.mc-print a, .mc-export a), .my-calendar-header input[type=submit], .my-calendar-footer input[type=submit], .my-calendar-header button:not(.mc-export button), .my-calendar-footer button:not(.mc-export button)');
76		buttonHandlers.forEach( (el) => {
77			el.addEventListener( 'click', function(e) {
78				mc_handle_navigation(e, el);
79			});
80			el.addEventListener( 'keyup', function(e) {
81				mc_handle_navigation(e, el);
82			});
83		});
84	}
85
86	function mc_handle_navigation(e, el) {
87		e.preventDefault();
88		if ( 'click' === e.type || ( 'keyup' === e.type && ' ' === e.key ) ) {
89			const calendar = el.closest( '.mc-main' );
90			calendar.classList.remove( 'is-main-view' );
91			let targetId = el.getAttribute( 'id' ), ref = calendar.getAttribute('id'),
92				month, day, year, mcat, loc, access, mcs, link, url, inputForm, searchParams;
93			let queryString = window.location.search;
94			let urlParams   = new URLSearchParams( queryString );
95			month  = ( urlParams.has( 'month' ) ) ? urlParams.get( 'month' ) : '';
96			day    = ( urlParams.has( 'dy' ) ) ? urlParams.get( 'dy' ) : '';
97			year   = ( urlParams.has( 'yr' ) ) ? urlParams.get( 'yr' ) : '';
98			mcat   = ( urlParams.has( 'mcat' ) ) ? urlParams.get( 'mcat' ) : '';
99			loc    = ( urlParams.has( 'loc' ) ) ? urlParams.get( 'loc' ) : '';
100			access = ( urlParams.has( 'access' ) ) ? urlParams.get( 'access' ) : '';
101			mcs    = ( urlParams.has( 'mcs' ) ) ? urlParams.get( 'mcs' ) : '';
102
103			if ( 'INPUT' === el.nodeName || 'BUTTON' === el.nodeName ) {
104				inputForm = el.closest( 'form' );
105				if ( inputForm ) {
106					if ( inputForm.classList.contains( 'mc-date-switcher' ) ) {
107						month = inputForm.querySelector( 'select[name=month]' ).value;
108						let day_input = inputForm.querySelector( 'select[name=dy]' );
109						if ( day_input ) {
110							day = day_input.value;
111						}
112						year  = inputForm.querySelector( 'select[name=yr]' ).value;
113					}
114					if ( inputForm.classList.contains( 'mc-categories-switcher' ) ) {
115						mcat = inputForm.querySelector( 'select[name=mcat]' ).value;
116					}
117					if ( inputForm.classList.contains( 'mc-locations-switcher' ) ) {
118						loc = inputForm.querySelector( 'select[name=loc]' ).value;
119					}
120					if ( inputForm.classList.contains( 'mc-access-switcher' ) ) {
121						access = inputForm.querySelector( 'select[name=access]' ).value;
122					}
123					if ( inputForm.classList.contains( 'mc-search-form' ) ) {
124						mcs = inputForm.querySelector( 'input[name=mcs]' ).value;
125					}
126					link = el.closest( 'form' ).getAttribute( 'action' );
127				} else {
128					link = el.getAttribute('data-href');
129				}
130			}
131			try {
132				url = new URL(link);
133				url.searchParams.delete('embed');
134				url.searchParams.delete('source');
135				if ( 'INPUT' === el.nodeName || 'BUTTON' === el.nodeName ) {
136					inputForm = el.closest( 'form' );
137					if ( inputForm ) {
138						url.searchParams.delete( 'month' );
139						url.searchParams.delete( 'dy' );
140						url.searchParams.delete( 'yr' );
141						if ( '' !== month && 'undefined' !== typeof( month ) ) {
142							url.searchParams.append( 'month', parseInt( month ) );
143							if ( 'undefined' !== typeof( day ) && '' !== day ) {
144								url.searchParams.append( 'dy', parseInt( day ) );
145							}
146							url.searchParams.append( 'yr', parseInt( year ) );
147						}
148						url.searchParams.delete( 'mcat' );
149						if ( '' !== mcat && 'undefined' !== typeof( mcat ) ) {
150							url.searchParams.append( 'mcat', mcat );
151						}
152						url.searchParams.delete( 'loc' );
153						url.searchParams.delete( 'ltype' );
154						if ( '' !== loc && 'undefined' !== typeof( loc ) ) {
155							url.searchParams.append( 'ltype', 'id' );
156							url.searchParams.append( 'loc', loc );
157						}
158						url.searchParams.delete( 'access' );
159						if ( '' !== access && 'undefined' !== typeof( access ) ) {
160							if ( 'all' !== access ) {
161								url.searchParams.append( 'access', parseInt( access ) );
162							}
163						}
164						url.searchParams.delete( 'mcs' );
165						if ( '' !== mcs && 'undefined' !== typeof( mcs ) ) {
166							url.searchParams.append( 'mcs', encodeURIComponent( mcs ) );
167						}
168
169						link = url.toString();
170					}
171				}
172				searchParams = url.searchParams;
173				searchParams.sort();
174
175				window.history.pushState({}, '', url );
176			} catch(_) {
177				url = false;
178			}
179
180			calendar.insertAdjacentHTML( 'afterbegin', '<div class="mc-loading"></div><div class="loading"><span class="screen-reader-text">Loading...</span></div>');
181			wp.a11y.speak( __( 'Loading', 'my-calendar' ) );
182
183			fetch( link )
184				.then( response => {
185					if ( response.ok ) {
186						return response.text();
187					}
188				}).then (html => {
189					const parser = new DOMParser();
190					const doc = parser.parseFromString( html, "text/html" );
191					calendar.replaceWith( doc.querySelector( '#' + ref ) );
192					mc_build_calendar( targetId, ref );
193				}).catch( error => {
194					calendar.insertAdjacentHTML( 'afterbegin', error );
195				});
196		}
197	}
198
199	function mc_build_calendar( targetId, ref ) {
200		initjs( ref );
201		// functions to execute when new view loads.
202		// List view.
203		if ( typeof( my_calendar ) !== "undefined" && my_calendar.list == 'true' ) {
204			let listEvents;
205			if ( 'false' === my_calendar.links ) {
206				listEvents = document.querySelectorAll( 'li.mc-events' );
207				listEvents.forEach( (el) => {
208					let target = el.querySelector( '.mc-events' );
209					if ( ! el.classList.contains( 'current-day' ) && target ) {
210						target.style.display = 'none';
211					}
212				});
213			} else {
214				listEvents =  document.querySelectorAll( 'li.mc-events .single-details' );
215				listEvents.forEach( (el) => {
216					el.style.display = 'none';
217				});
218			}
219		}
220		// Grid view.
221		if ( typeof( my_calendar ) !== "undefined" && my_calendar.grid == 'true' ) {
222			let gridEvents = document.querySelectorAll('.mc-main.calendar .has-events > .calendar-event > *:not(header)');
223			gridEvents.forEach( (el) => {
224				el.style.display = 'none';
225			});
226		}
227		// Mini view.
228		if  ( typeof( my_calendar ) !== "undefined" && my_calendar.mini == 'true' ) {
229			let miniEvents = document.querySelectorAll( '.mc-main.mini .has-events .calendar-events' );
230			miniEvents.forEach( (el) => {
231				el.style.display = 'none';
232			});
233		}
234		my_calendar_external_links();
235		mc_disclosures();
236		let originalFocus = document.getElementById( targetId );
237		if ( null === originalFocus ) {
238			// If the originalFocus doesn't exist on the new screen, set to first button.
239			calendar      = document.getElementById( ref );
240			originalFocus = calendar.querySelectorAll( 'button' )[0];
241		}
242		originalFocus.focus();
243		let refAnnounce = document.getElementById( 'mc_head_' + ref );
244		wp.a11y.speak( refAnnounce.innerText );
245		mc_display_usertime();
246		if ( 'true' === my_calendar.ajax ) {
247			mc_setup_handlers();
248		} else {
249			mc_render_links();
250		}
251		my_calendar_table_aria();
252		// Notify other scripts (e.g. My Tickets) that calendar content was replaced and needs event rebinding.
253		document.dispatchEvent( new CustomEvent( 'mc_calendar_loaded', { detail: { targetId: targetId, ref: ref } } ) );
254	}
255
256	function mc_display_usertime() {
257		const usertime = document.querySelectorAll( '.mc-user-time' );
258		let label = new Intl.DateTimeFormat().resolvedOptions().timeZone, udate, utime;
259		usertime.forEach( (el) => {
260			let time  = el.innerText;
261			let type  = el.getAttribute( 'data-type' );
262			// Handle Internet Explorer's lack of timezone info.
263			if (undefined === label) {
264				label = el.getAttribute( 'data-label' );
265			}
266			if ( 'datetime' === type ) {
267				utime = '<span class="mc-local-time-time">' + new Date( time ).toLocaleTimeString().replace( ':00 ', ' ' ) + '</span>';
268				udate = '<span class="mc-local-time-date">' + new Date( time ).toLocaleDateString() + '</span>';
269				el.innerHTML = '<span class="mc-local-time-label">' + label + ':</span> ' + udate + '<span class="sep">, </span>' + utime;
270			}
271			if ( 'date' === type ) {
272				udate = '<span class="mc-local-time-date">' + new Date( time ).toLocaleDateString() + '</span>';
273				el.innerHTML = '<span class="mc-local-time-label">' + label + ':</span> ' + udate;
274
275			}
276			if ( 'time' === type ) {
277				utime = '<span class="mc-local-time-time">' + new Date( time ).toLocaleTimeString().replace( ':00 ', ' ' ) + '</span>';
278				el.innerHTML = '<span class="mc-local-time-label">' + label + ':</span> ' + utime;
279
280			}
281			el.setAttribute( 'data-time', time );
282		});
283	}
284
285	function mc_render_links() {
286		const buttons = document.querySelectorAll( '.mc-main button.mc-navigation-button' );
287		buttons.forEach( (el) => {
288			let link = document.createElement( 'a' );
289			link.setAttribute( 'id', el.getAttribute( 'id' ) );
290			link.setAttribute( 'href', el.getAttribute( 'data-href' ) );
291			classes = el.getAttribute( 'class' ) ?? '';
292			link.setAttribute( 'class', classes );
293			link.setAttribute( 'rel', 'nofollow' );
294			link.classList.remove( 'mc-navigation-button' );
295			link.classList.add( 'mc-navigation-link' );
296			link.innerHTML = el.innerHTML;
297			el.replaceWith( link );
298		});
299	}
300
301	function mc_disclosures() {
302		const hasPopup = document.querySelectorAll( 'button.has-popup' );
303		if ( hasPopup ) {
304			hasPopup.forEach( (el) => {
305				let controlId = el.getAttribute( 'aria-controls' );
306				let controlled = document.getElementById( controlId );
307				//$( this ).append( '<span class="dashicons dashicons-plus" aria-hidden="true">' );
308				controlled.style.display = 'none';
309				el.addEventListener( 'click', function() {
310					let visible = controlled.checkVisibility();
311					let position = el.offsetWidth + 8;
312					controlled.style.left = position + 'px';
313					if ( visible ) {
314						controlled.style.display = 'none';
315						el.setAttribute( 'aria-expanded', 'false' );
316					} else {
317						controlled.style.display = 'block';
318						el.setAttribute( 'aria-expanded', 'true' );
319					}
320				});
321			});
322		}
323	}
324
325	function mc_build_toggles( targetId ) {
326		let exportButton, subscribeButton;
327		if ( targetId ) {
328			const subscribe = document.querySelector( '#' + targetId + ' .mc-subscribe' );
329			const exports   = document.querySelector( '#' + targetId + ' .mc-download' );
330			if ( null !== subscribe ) {
331				subscribeButton = subscribe.querySelector( 'button' );
332				if ( null === subscribeButton ) {
333					let controls_id = 'mc_control_' + Math.floor(Math.random() * 1000 ).toString();
334					const toggle = document.createElement( 'button' );
335					toggle.setAttribute( 'type', 'button' );
336					toggle.setAttribute( 'aria-controls', controls_id );
337					toggle.setAttribute( 'aria-expanded', false );
338					toggle.innerHTML = my_calendar.subscribe + ' <span class="dashicons dashicons-arrow-right" aria-hidden="true"></span>';
339					subscribe.querySelector( 'ul' ).setAttribute( 'id', controls_id );
340					subscribe.querySelector( 'ul' ).style.display = 'none';
341					subscribe.insertAdjacentElement( 'afterbegin', toggle );
342				}
343			}
344			if ( null !== exports ) {
345				exportButton = exports.querySelector( 'button' );
346				if ( null === exportButton ) {
347					let controls_id = 'mc_control_' + Math.floor(Math.random() * 1000 ).toString();
348					const toggle = document.createElement( 'button' );
349					toggle.setAttribute( 'type', 'button' );
350					toggle.setAttribute( 'aria-controls', controls_id );
351					toggle.setAttribute( 'aria-expanded', false );
352					toggle.innerHTML = my_calendar.export + ' <span class="dashicons dashicons-arrow-right" aria-hidden="true"></span>';
353					exports.querySelector( 'ul' ).setAttribute( 'id', controls_id );
354					exports.querySelector( 'ul' ).style.display = 'none';
355					exports.insertAdjacentElement( 'afterbegin', toggle );
356				}
357			}
358			if ( null === exportButton || null === subscribeButton ) {
359				const toggles = document.querySelectorAll( '#' + targetId + ' .mc-export button' );
360				let icon;
361				toggles.forEach( (el) => {
362					el.addEventListener( 'click', function() {
363						let controlled = el.getAttribute( 'aria-controls' );
364						let target     = document.getElementById( controlled );
365						if ( target ) {
366							if ( target.checkVisibility() ) {
367								target.style.display = 'none';
368								el.setAttribute( 'aria-expanded', 'false' );
369								icon = el.querySelector( '.dashicons' );
370								icon.classList.remove( 'dashicons-arrow-down' );
371								icon.classList.add( 'dashicons-arrow-right' );
372							} else {
373								target.style.display = 'block';
374								el.setAttribute( 'aria-expanded', 'true' );
375								icon = el.querySelector( '.dashicons' );
376								icon.classList.remove( 'dashicons-arrow-right' )
377								icon.classList.add( 'dashicons-arrow-down' );
378							}
379						}
380					});
381				});
382			}
383		}
384	}
385
386	function my_calendar_external_links() {
387		let external_links = document.querySelectorAll('.mc-main a[target=_blank]');
388		external_links.forEach( (el) => {
389			el.classList.add( 'mc-opens-in-new-tab' );
390			el.insertAdjacentHTML( 'beforeend', ' <span class="dashicons dashicons-external" aria-hidden="true"></span><span class="screen-reader-text"> ' + my_calendar.newWindow + '</span>' );
391		});
392	}
393
394	/**
395	 * Map ARIA attributes to My Calendar table so responsive view doesn't break table relationships.
396	 */
397	function my_calendar_table_aria() {
398		try {
399			const allTables = document.querySelectorAll('.mc-main.calendar table.my-calendar-table');
400			const allRowGroups = document.querySelectorAll('.mc-main.calendar table.my-calendar-table thead, .mc-main.calendar table.my-calendar-table tbody, .mc-main.calendar table.my-calendar-table tfoot');
401			const allRows = document.querySelectorAll('.mc-main.calendar table.my-calendar-table tr');
402			const allCells = document.querySelectorAll('.mc-main.calendar table.my-calendar-table td');
403			const allHeaders = document.querySelectorAll('.mc-main.calendar table.my-calendar-table th');
404			const allRowHeaders = document.querySelectorAll('.mc-main.calendar table.my-calendar-table th[scope=row]');
405
406			for (let i = 0; i < allTables.length; i++) {
407				allTables[i].setAttribute('role','table');
408			}
409			for (let i = 0; i < allRowGroups.length; i++) {
410				allRowGroups[i].setAttribute('role','rowgroup');
411			}
412			for (let i = 0; i < allRows.length; i++) {
413				allRows[i].setAttribute('role','row');
414			}
415			for (let i = 0; i < allCells.length; i++) {
416				allCells[i].setAttribute('role','cell');
417			}
418			for (let i = 0; i < allHeaders.length; i++) {
419				allHeaders[i].setAttribute('role','columnheader');
420			}
421			// this accounts for scoped row headers
422			for (let i = 0; i < allRowHeaders.length; i++) {
423				allRowHeaders[i].setAttribute('role','rowheader');
424			}
425			// caption role not needed as it is not a real role and
426			// browsers do not dump their own role with display block
427		} catch (e) {
428			console.log( "my_calendar_table_aria(): " + e );
429		}
430	}
431	my_calendar_table_aria();
432
433})();

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.