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.