1 // Function to scroll to the div element with the query ID 2 function scrollToQueryId( queryId ) { 3 const targetElement = document.getElementById( `uagb-block-queryid-${queryId}` ); 4 5 if ( targetElement ) { 6 const rect = targetElement.getBoundingClientRect(); 7 const adminBar = document.querySelector( '#wpadminbar' ); 8 const adminBarOffSetHeight = adminBar?.offsetHeight || 0; 9 const scrollTop = window?.pageYOffset || document?.documentElement?.scrollTop; 10 const targetOffset = ( rect?.top + scrollTop ) - adminBarOffSetHeight; 11 12 window.scrollTo( { 13 top: targetOffset, 14 behavior: 'smooth' 15 } ); 16 } 17 } 18 19 /** 20 * Function to find the ancestor with the given class name. 21 * 22 * @param {Element} element The element. 23 * @param {string} className The class name. 24 * @return {Element} The element. 25 * @since 1.2.0 26 */ 27 function findAncestorWithClass( element, className ) { 28 while ( element && ! element.classList.contains( className ) ) { 29 element = element.parentNode; 30 } 31 return element; 32 } 33 34 document.addEventListener( 'DOMContentLoaded', function () { 35 // Debounce function to limit the rate of execution 36 function debounce( func, wait ) { 37 let timeout; 38 39 return function executedFunction( ...args ) { 40 const context = this; 41 const later = () => { 42 timeout = null; 43 func.apply( context, args ); 44 }; 45 46 clearTimeout( timeout ); 47 timeout = setTimeout( later, wait ); 48 }; 49 }; 50 51 // Add functions to store and get active filters 52 function storeActiveFilter( loopBuilder, filterData, filterType ) { 53 if ( loopBuilder && filterData ) { 54 loopBuilder.setAttribute( `data-active-filter-${filterType}`, filterData ); 55 } 56 } 57 58 function getActiveFilter( loopBuilder, filterType ) { 59 return loopBuilder?.getAttribute( `data-active-filter-${filterType}` ) || null; 60 } 61 62 /** 63 * Function to update the loop wrapper content 64 * as per data in filters. 65 * 66 * @param {Event} event The event. 67 * @param {string} paged The paged parameter for displaying a particular page on click of pagination links. 68 * @param {string} buttonFilter The array of selected button value. 69 * @param {string} loopParentContainer The loop parent container. 70 * @return {Promise} The Promise. 71 * @throws {Error} The error. 72 * @since 1.2.0 73 */ 74 async function updateContent( event, paged = null, buttonFilter = null, loopParentContainer ) { 75 try { 76 const loopBuilder = loopParentContainer; 77 const formData = new FormData(); 78 79 // Get all form data 80 const search = loopBuilder?.querySelector( '.uagb-loop-search' )?.value || ''; 81 const sorting = loopBuilder?.querySelector( '.uagb-loop-sort' )?.value || ''; 82 83 // Get category select value 84 const categorySelect = loopBuilder?.querySelector( '.uagb-loop-category' ); 85 if ( categorySelect?.value ) { 86 formData.append( 'category', categorySelect.value ); 87 storeActiveFilter( loopBuilder, categorySelect.value, 'select' ); 88 } else { 89 // Try to get stored select filter 90 const storedSelectFilter = getActiveFilter( loopBuilder, 'select' ); 91 if ( storedSelectFilter ) { 92 formData.append( 'category', storedSelectFilter ); 93 } 94 } 95 96 // Handle checkboxes 97 const checkBoxValues = loopBuilder?.querySelectorAll( '.uagb-cat-checkbox' ); 98 const checkedValues = []; 99 checkBoxValues?.forEach( checkBox => { 100 if ( checkBox.checked && checkBox.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ) { 101 checkedValues.push( checkBox.value ); 102 } 103 } ); 104 105 // Handle button filter 106 let activeButtonData = getActiveFilter( loopBuilder, 'button' ); 107 if ( ! activeButtonData && buttonFilter?.type ) { 108 activeButtonData = buttonFilter.type; 109 storeActiveFilter( loopBuilder, activeButtonData, 'button' ); 110 } 111 112 // Clear all filters first 113 formData.delete( 'buttonFilter' ); 114 formData.delete( 'checkbox' ); 115 formData.delete( 'category' ); 116 loopBuilder.removeAttribute( 'data-active-filter-checkbox' ); 117 loopBuilder.removeAttribute( 'data-active-filter-select' ); 118 loopBuilder.removeAttribute( 'data-active-filter-button' ); 119 120 // Handle filters based on the event target 121 if ( event.target.classList.contains( 'uagb-cat-checkbox' ) ) { 122 // Checkbox was clicked - clear select and apply checkbox 123 if ( categorySelect ) categorySelect.value = ''; 124 formData.append( 'checkbox', checkedValues ); 125 storeActiveFilter( loopBuilder, JSON.stringify( checkedValues ), 'checkbox' ); 126 } else if ( event.target.classList.contains( 'uagb-loop-category' ) ) { 127 // Select was changed - clear checkboxes and apply select 128 checkBoxValues?.forEach( checkBox => { 129 if ( checkBox.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ) { 130 checkBox.checked = false;
131 } 132 } ); 133 formData.append( 'category', categorySelect.value ); 134 storeActiveFilter( loopBuilder, categorySelect.value, 'select' ); 135 } else if ( buttonFilter?.type ) { 136 // Button was clicked - clear select and checkboxes 137 if ( categorySelect ) categorySelect.value = ''; 138 checkBoxValues?.forEach( checkBox => { 139 if ( checkBox.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ) { 140 checkBox.checked = false; 141 } 142 } ); 143 formData.append( 'buttonFilter', buttonFilter.type ); 144 storeActiveFilter( loopBuilder, buttonFilter.type, 'button' ); 145 } 146 147 // Add other form data 148 if ( search ) { 149 formData.append( 'search', search ); 150 } 151 if ( sorting ) { 152 formData.append( 'sorting', sorting ); 153 } 154 if ( paged ) { 155 formData.append( 'paged', paged ); 156 } 157 158 let queryId = null; 159 if ( buttonFilter?.type === 'all' ) { 160 const el = document.querySelector( '[data-query-id]' ); 161 if ( el ) { 162 queryId = el.getAttribute( 'data-query-id' ); 163 } else { 164 queryId = 0; // fallback to default 165 } 166 167 } else { 168 // Get query ID 169 queryId = event.target?.dataset?.uagbBlockQueryId || 170 event.target?.parentElement?.dataset?.uagbBlockQueryId || 171 event?.dataset?.uagbBlockQueryId || 172 event.target.closest( 'a' )?.getAttribute( 'data-uagb-block-query-id' ) || 0; 173 } 174 175 // Scroll to the query ID 176 scrollToQueryId( queryId ); 177 178 formData.append( 'queryId', queryId ); 179 formData.append( 'block_id', loopBuilder?.getAttribute( 'data-block_id' ) ); 180 formData.append( 'action', 'uagb_update_loop_builder_content' ); 181 formData.append( 'postId', uagb_loop_builder.post_id ); 182 formData.append( 'postType', uagb_loop_builder.post_type ); 183 formData.append( 'security', uagb_loop_builder.nonce ); 184 185 // Log the complete form data 186 const formDataObj = {}; 187 formData.forEach( ( value, key ) => { 188 formDataObj[key] = value; 189 } ); 190 191 const output = await getUpdatedLoopWrapperContent( formData ); 192 193 // Update content 194 if ( output?.content?.wrapper ) { 195 const loopElement = loopBuilder?.querySelector( '#uagb-block-queryid-' + queryId ); 196 if ( loopElement ) { 197 loopElement.innerHTML = output.content.wrapper; 198 } 199 } 200 201 // Update pagination 202 if ( output?.content?.pagination ) { 203 const paginationElements = loopBuilder?.querySelectorAll( '#uagb-block-pagination-queryid-' + queryId ); 204 paginationElements?.forEach( element => { 205 element.innerHTML = output.content.pagination; 206 } ); 207 } 208 209 } catch ( error ) { 210 throw error; 211 } 212 } 213 214 /** 215 * Handles the input event for the search functionality within the UAGB Loop Builder block. 216 * Synchronizes input values across all search inputs within the same loop builder container 217 * and triggers a content update. 218 * 219 * @param {Event} event - The input event triggered by the user. 220 * @since 1.2.0 221 */ 222 function handleInput( event ) { 223 const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' ); 224 const searchInputs = loopParentContainer.querySelectorAll( '.uagb-loop-search' );
225 searchInputs.forEach( searchInput => { 226 if( searchInput.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ){ 227 searchInput.value = event.target.value; 228 } 229 } ); 230 updateContent( event, null, null, loopParentContainer ); 231 } 232 233 /** 234 * Handles the checkbox selection within the UAGB Loop Builder block. 235 * Collects the values of all checked checkboxes that match the block query ID 236 * and triggers a content update. 237 * 238 * @param {Event} event - The change event triggered by the user when interacting with a checkbox. 239 * @since 1.2.0 240 */ 241 function handleCheckBoxVal( event ) { 242 const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' ); 243 const checkBoxValues = loopParentContainer.querySelectorAll( '.uagb-cat-checkbox' ); 244 // Initialize an array to store checked checkbox values. 245 const checkedValues = []; 246 checkBoxValues.forEach( checkBoxVal => { 247 // Check if the checkbox is checked. 248 const isChecked = checkBoxVal.checked; 249 if ( isChecked && checkBoxVal.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ) { 250 // Add the value to the array. 251 checkedValues.push( checkBoxVal.value ); 252 } 253 } ); 254 255 // Always update content when checkbox state changes, even if no checkboxes are checked 256 updateContent( event, null, null, loopParentContainer ); 257 } 258 259 /** 260 * Handles the selection event on the search filter. 261 * Updates the value of all relevant search filter elements with the same query ID and triggers content update. 262 * 263 * @param {Event} event - The select event triggered by the user interaction. 264 * @since 1.2.0 265 */ 266 function handleSelect( event ) { 267 const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' ); 268 const sortSelects = loopParentContainer.querySelectorAll( '.uagb-loop-sort' ); 269 sortSelects.forEach( sortSelect => { 270 if( sortSelect.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ){ 271 sortSelect.value = event.target.value; 272 } 273 } ); 274 updateContent( event, null, null, loopParentContainer ); 275 } 276 277 /** 278 * Handles the category selection event on a dropdown filter. 279 * Updates the value of all relevant category select elements with the same query ID and triggers content update. 280 * 281 * @param {Event} event - The select event triggered by the user interaction. 282 * @since 1.2.0 283 */ 284 function handleCatSelect( event ) { 285 const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' ); 286 const categorySelects = loopParentContainer.querySelectorAll( '.uagb-loop-category' ); 287 categorySelects.forEach( categorySelect => { 288 if ( categorySelect.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ) { 289 categorySelect.value = event.target.value; 290 } 291 } ); 292 293 // If "all" or empty value is selected, clear the stored filter 294 if ( !event.target.value || event.target.value === '' || event.target.value === 'all' ) { 295 loopParentContainer.removeAttribute( 'data-active-filter-select' ); 296 } 297 298 updateContent( event, null, null, loopParentContainer ); 299 } 300 301 /** 302 * Resets the values of elements within a container based on their query ID. 303 * 304 * @param {HTMLElement} container - The container element to search within. 305 * @param {string} selector - The CSS selector for the elements to reset. 306 * @param {string} queryId - The query ID to match. 307 * @param {Function} resetCallback - A callback function to apply the reset logic to each element. 308 * @since 1.2.0 309 */ 310 function resetValues( container, selector, queryId, resetCallback ) { 311 const elements = container.querySelectorAll( selector );
312 elements.forEach( element => { 313 const elementQueryId = element.dataset.uagbBlockQueryId; 314 if ( elementQueryId === queryId ) { 315 resetCallback( element ); 316 } 317 } ); 318 } 319 320 /** 321 * Handles the reset event for all filters within the loop builder block. 322 * Resets the values of search inputs, sort selects, category selects, and checkboxes to their default state. 323 * 324 * @param {Event} event - The reset event triggered by the user interaction. 325 * @since 1.2.0 326 */ 327 function handleReset( event ) { 328 const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' ); 329 // Get the query ID from the event target 330 let queryId = event.target.parentElement.dataset.uagbBlockQueryId; 331 if ( event.target.tagName.toLowerCase() === 'a' ) { 332 queryId = event.target.dataset.uagbBlockQueryId; 333 } else if ( event.target.tagName.toLowerCase() === 'svg' || event.target.tagName.toLowerCase() === 'path' ) { 334 queryId = event.target.closest( 'a' )?.getAttribute( 'data-uagb-block-query-id' ); 335 } 336 337 // Reset the value of the filter inputs 338 const loopBuilder = findAncestorWithClass( event.target.parentNode, 'wp-block-uagb-loop-builder' ); 339 340 resetValues( loopBuilder, '.uagb-loop-search', queryId, element => { 341 element.value = ''; // Reset search input value 342 } ); 343 344 resetValues( loopBuilder, '.uagb-loop-sort', queryId, element => { 345 element.value = ''; // Reset sort select value 346 } ); 347 348 resetValues( loopBuilder, '.uagb-loop-category', queryId, element => { 349 element.value = ''; // Reset category select value 350 } ); 351 352 resetValues( loopBuilder, '.uagb-cat-checkbox', queryId, element => { 353 element.checked = false; // Uncheck category checkbox 354 } ); 355 356 // Clear all stored filter data attributes 357 if ( loopBuilder ) { 358 loopBuilder.removeAttribute( 'data-active-filter-select' ); 359 loopBuilder.removeAttribute( 'data-active-filter-checkbox' ); 360 loopBuilder.removeAttribute( 'data-active-filter-button' ); 361 } 362 363 // Trigger the updateContent function to reflect the changes 364 updateContent( event, null, null, loopParentContainer ); 365 } 366 367 const resetButtons = document.querySelectorAll( '.uagb-loop-reset' ); 368 369 const searchInputs = document.querySelectorAll( '.uagb-loop-search' ); 370 371 searchInputs.forEach( searchInput => { 372 const debouncedHandleInput = debounce( handleInput, 250 ); 373 searchInput.addEventListener( 'input', debouncedHandleInput ); 374 } ); 375 376 const sortSelects = document.querySelectorAll( '.uagb-loop-sort' ); 377 378 sortSelects.forEach( sortSelect => { 379 const debouncedHandleInput = debounce( handleSelect, 250 ); 380 sortSelect.addEventListener( 'change', debouncedHandleInput ); 381 } ); 382 383 const categorySelects = document.querySelectorAll( '.uagb-loop-category' ); 384 385 categorySelects.forEach( categorySelect => { 386 const debouncedHandleInput = debounce( handleCatSelect, 250 ); 387 categorySelect.addEventListener( 'change', debouncedHandleInput ); 388 } ); 389 390 // Get a reference to the checkbox element. 391 const checkBoxValues = document.querySelectorAll( '.uagb-cat-checkbox' ); 392 checkBoxValues.forEach( checkBoxVal => { 393 const debouncedHandleInput = debounce( handleCheckBoxVal, 250 ); 394 checkBoxVal.addEventListener( 'click', debouncedHandleInput ); 395 } ); 396 397 resetButtons.forEach( resetButton => { 398 const debouncedHandleReset = debounce( handleReset, 250 ); 399 resetButton.addEventListener( 'click', debouncedHandleReset ); 400 } ); 401 402 const oldPaginations = document.querySelectorAll( '.wp-block-uagb-loop-builder >
402 :not(.uagb-loop-pagination).wp-block-uagb-buttons' ); 403 404 oldPaginations?.forEach( function( container ) { 405 // Create a new div with class "parent-container" 406 const parentContainer = document.createElement( 'div' ); 407 parentContainer.classList.add( 'uagb-loop-pagination' ); 408 const queryIdPAginationLink = container.querySelector( 'a' ).getAttribute( 'data-uagb-block-query-id' ); 409 parentContainer.id = 'uagb-block-pagination-queryid-'+queryIdPAginationLink; 410 411 // Append the container content to the new div 412 parentContainer.innerHTML = container.outerHTML; 413 414 // Append the new div after the original container 415 container.parentNode.insertBefore( parentContainer, container.nextSibling ); 416 417 // Remove the original container 418 container.parentNode.removeChild( container ); 419 } ); 420 421 const paginationContainer = document.querySelectorAll( '.uagb-loop-pagination' ); 422 423 paginationContainer.forEach( pagination => { 424 pagination.addEventListener( 'click', function( event ) { 425 event.preventDefault(); 426 const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' ); 427 428 const paged = event.target.dataset.uagbBlockQueryPaged || 429 event.target.parentElement.dataset.uagbBlockQueryPaged || 430 event?.target?.closest( 'a' )?.getAttribute( 'data-uagb-block-query-paged' ); 431 432 // Get all active filter data 433 const activeButtonData = getActiveFilter( loopParentContainer, 'button' ); 434 const activeSelectData = getActiveFilter( loopParentContainer, 'select' ); 435 const activeCheckboxData = getActiveFilter( loopParentContainer, 'checkbox' ); 436 437 // Create form data based on active filter 438 const formData = new FormData(); 439 440 // Add pagination 441 if ( paged ) { 442 formData.append( 'paged', paged ); 443 } 444 445 // Add active filter based on type 446 if ( activeButtonData ) { 447 formData.append( 'buttonFilter', activeButtonData ); 448 } else if ( activeSelectData ) { 449 formData.append( 'category', activeSelectData ); 450 } else if ( activeCheckboxData ) { 451 formData.append( 'checkbox', activeCheckboxData ); 452 } 453 454 // Add other required data 455 formData.append( 'queryId', event.target.dataset.uagbBlockQueryId || 456 event.target.parentElement.dataset.uagbBlockQueryId || 457 event?.target?.closest( 'a' )?.getAttribute( 'data-uagb-block-query-id' ) || 0 ); 458 formData.append( 'block_id', loopParentContainer?.getAttribute( 'data-block_id' ) ); 459 formData.append( 'action', 'uagb_update_loop_builder_content' ); 460 formData.append( 'postId', uagb_loop_builder.post_id ); 461 formData.append( 'postType', uagb_loop_builder.post_type ); 462 formData.append( 'security', uagb_loop_builder.nonce ); 463
464 // Get search and sorting values if they exist 465 const search = loopParentContainer?.querySelector( '.uagb-loop-search' )?.value || ''; 466 const sorting = loopParentContainer?.querySelector( '.uagb-loop-sort' )?.value || ''; 467 468 if ( search ) { 469 formData.append( 'search', search ); 470 } 471 if ( sorting ) { 472 formData.append( 'sorting', sorting ); 473 } 474 475 // Make the AJAX request 476 getUpdatedLoopWrapperContent( formData ) 477 .then( output => { 478 if ( output?.content?.wrapper ) { 479 const loopElement = loopParentContainer?.querySelector( '#uagb-block-queryid-' + formData.get( 'queryId' ) ); 480 if ( loopElement ) { 481 loopElement.innerHTML = output.content.wrapper; 482 } 483 } 484 if ( output?.content?.pagination ) { 485 const paginationElements = loopParentContainer?.querySelectorAll( '#uagb-block-pagination-queryid-' + formData.get( 'queryId' ) ); 486 paginationElements?.forEach( element => { 487 element.innerHTML = output.content.pagination; 488 } ); 489 } 490 } ) 491 .catch( error => { 492 throw error; // Propagate the error 493 } ); 494 } ); 495 } ); 496 497 const categoryButtonFilterContainer = document.querySelectorAll( '.uagb-loop-category-inner a' ); 498 499 categoryButtonFilterContainer.forEach( ( buttons ) => { 500 buttons.addEventListener( 'click', function ( event ) { 501 event.preventDefault(); 502 const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' ); 503 let buttonData = null; 504 505 if ( event.target.tagName.toLowerCase() === 'a' ) { 506 buttonData = event.target.children[0].dataset.type; 507 } else if ( event.target.tagName.toLowerCase() === 'div' && event.target.parentElement.tagName.toLowerCase() === 'a' ) { 508 buttonData = event.target.dataset.type; 509 } 510 511 // Uncheck all checkboxes when a button is clicked 512 checkBoxValues?.forEach( checkBox => { 513 checkBox.checked = false; 514 } ); 515 516 // Check if "all" button was clicked. 517 if ( buttonData === 'all' || buttonData === undefined ) { 518 // Clear stored button filter. 519 loopParentContainer.removeAttribute( 'data-active-filter-button' ); 520 // Update content with all type. 521 updateContent( event, null, { type: 'all' }, loopParentContainer ); 522 } else if ( buttonData ) { 523 storeActiveFilter( loopParentContainer, buttonData, 'button' ); 524 updateContent( event, null, { type: buttonData }, loopParentContainer ); 525 } 526 } ); 527 } ); 528 } ); 529 530 /** 531 * Function to get the updated loop wrapper content. 532 * as per data in filters. 533 * 534 * @param {FormData} data The form data. 535 * @since 1.2.0 536 * @return {Promise} The Promise. 537 */ 538 function getUpdatedLoopWrapperContent( data ) { 539 // Create a new FormData object 540 data.append( 'action', 'uagb_update_loop_builder_content' ); 541 data.append( 'postId', uagb_loop_builder?.post_id ); 542 data.append( 'postType', uagb_loop_builder?.what_post_type ); 543 data.append( 'security', uagb_loop_builder?.nonce ) 544 545 // The function now returns a Promise 546 return fetch( uagb_loop_builder?.ajax_url, { 547 method: 'POST', 548 credentials: 'same-origin', 549 body: data, 550 } ) 551 .then( response => { 552 if ( ! response.ok ) { 553 throw new Error( 'Network response was not ok' ); 554 } 555 return response.json(); 556 } ) 557 .then( output => { 558 if ( output.success ) { 559 // Return the actual output. 560 return output.data; 561 } 562 throw new Error( output.data.message ); 563 564 } ) 565 .catch( error => { 566 throw error; // Propagate the error 567 } ); 568 }; 569/** 570 * navigation.js 571 * 572 * Handles toggling the navigation menu for small screens. 573 */ 574( function() { 575 var container, button, menu; 576 577 container = document.getElementById( 'site-navigation' ); 578 if ( ! container ) 579 return; 580 581 button = container.getElementsByClassName( 'menu-toggle' )[0]; 582 if ( 'undefined' === typeof button ) 583 return; 584 585 menu = container.getElementsByTagName( 'ul' )[0]; 586 587 // Hide menu toggle button if menu is empty and return early. 588 if ( 'undefined' === typeof menu ) { 589 button.style.display = 'none'; 590 return; 591 } 592 593 if ( -1 === menu.className.indexOf( 'nav-menu' ) ) 594 menu.className += 'nav-menu'; 595 596 button.onclick = function() { 597 if ( -1 !== container.className.indexOf( 'main-small-navigation' ) ) 598 container.className = container.className.replace( 'main-small-navigation', 'main-navigation' ); 599 else 600 container.className = container.className.replace( 'main-navigation', 'main-small-navigation' ); 601 }; 602 603 /** 604 * Toggles `focus` class to allow submenu access on tablets. 605 */ 606 ( function( container ) { 607 var touchStartFn, i, 608 parentLink = container.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' ); 609 610 if ( 'ontouchstart' in window ) { 611 touchStartFn = function( e ) { 612 var menuItem = this.parentNode, i; 613 614 if ( ! menuItem.classList.contains( 'focus' ) ) { 615 e.preventDefault(); 616 for ( i = 0; i < menuItem.parentNode.children.length; ++i ) { 617 if ( menuItem === menuItem.parentNode.children[i] ) { 618 continue; 619 } 620 menuItem.parentNode.children[i].classList.remove( 'focus' ); 621 } 622 menuItem.classList.add( 'focus' ); 623 } else { 624 menuItem.classList.remove( 'focus' ); 625 } 626 }; 627 628 for ( i = 0; i < parentLink.length; ++i ) { 629 parentLink[i].addEventListener( 'touchstart', touchStartFn, false ); 630 } 631 } 632 }( container ) ); 633} )(); 634; 635( function() { 636 var is_webkit = navigator.userAgent.toLowerCase().indexOf( 'webkit' ) > -1, 637 is_opera = navigator.userAgent.toLowerCase().indexOf( 'opera' ) > -1, 638 is_ie = navigator.userAgent.toLowerCase().indexOf( 'msie' ) > -1; 639 640 if ( ( is_webkit || is_opera || is_ie ) && 'undefined' !== typeof( document.getElementById ) ) { 641 var eventMethod = ( window.addEventListener ) ? 'addEventListener' : 'attachEvent';
642 window[ eventMethod ]( 'hashchange', function() { 643 var element = document.getElementById( location.hash.substring( 1 ) ); 644 645 if ( element ) { 646 if ( ! /^(?:a|select|input|button|textarea)$/i.test( element.tagName ) ) 647 element.tabIndex = -1; 648 649 element.focus(); 650 } 651 }, false ); 652 } 653})(); 654; 655// For compatibility with optimizers 656if (document.readyState !== 'loading') { 657 //console.log('Newsletter loaded (late)'); 658 tnp_ajax_init(); 659} else { 660 document.addEventListener("DOMContentLoaded", function () { 661 //console.log('Newsletter loaded'); 662 tnp_ajax_init(); 663 }); 664} 665 666function tnp_ajax_init() { 667 document.querySelectorAll('form.tnp-ajax').forEach(el => { 668 el.addEventListener('submit', async function(ev) { 669 ev.preventDefault(); 670 ev.stopPropagation(); 671 const response = await fetch(newsletter_data.action_url + '?action=tnp&na=sa', { 672 method: "POST", 673 body: new FormData(this) 674 }); 675 this.innerHTML = await response.text(); 676 }); 677 }); 678} 679 680 681 682; 683(()=>{var e=[],t=!1,n=2e3,i=[],o=new Promise(e=>{"loading"!==document.readyState?e():window.addEventListener("DOMContentLoaded",()=>e())});function s(e,t){if("string"==typeof e)try{e=JSON.parse(e)}catch{return}if(t&&"function"==typeof t.postMessage)try{t.postMessage(JSON.stringify({type:"likesMessage",data:e}),"*")}catch{}}function r(){const t=[];document.querySelectorAll("div.jetpack-likes-widget-unloaded").forEach(n=>{if(!(e.indexOf(n.id)>-1)&&d(n)){e.push(n.id);var i,o=/like-(post|comment)-wrapper-(\d+)-(\d+)-(\w+)/.exec(n.id);o&&5===o.length&&(i={blog_id:o[2],width:n.width},"post"===o[1]?i.post_id=o[3]:"comment"===o[1]&&(i.comment_id=o[3]),i.obj_id=o[4],t.push(i))}}),t.length>0&&s({event:"initialBatch",requests:t},window.frames["likes-master"])}function a(){const e=document.querySelector("#likes-other-gravatars");if(e){e.style.display="none",e.setAttribute("aria-hidden","true");const t=e.__resizeHandler;t&&(window.removeEventListener("resize",t),delete e.__resizeHandler)}}function l(){var e;if(!t)return s({event:"queryMasterReady"},window.frames["likes-master"]),void setTimeout(l,500);!function(){for(let e=i.length-1;e>=0;e--){const t=i[e];if(!d(t)){const n=t&&t.parentElement&&t.parentElement.parentElement;n.classList.remove("jetpack-likes-widget-loaded"),n.classList.remove("jetpack-likes-widget-loading"),n.classList.add("jetpack-likes-widget-unloaded");const o=n.querySelector(".likes-widget-placeholder");o&&(o.style.display=""),i.splice(e,1),t.remove()}}}(),function(){if(!g)return;document.querySelectorAll("div.jetpack-likes-widget-unloaded").forEach(e=>g.observe(e))}();var n=[...document.querySelectorAll("div.jetpack-likes-widget-unloaded")].filter(e=>d(e));n.length>0&&r();for(var o=0,a=n.length;o<=a-1;o++)(e=n[o].id)&&c(e)}function c(e){if(void 0===e)return;const t=document.querySelector("#"+e);t.querySelectorAll("iframe").forEach(e=>e.remove());const n=t.querySelector(".likes-widget-placeholder");if(n&&n.classList.contains("post-likes-widget-placeholder")){const e=document.createElement("iframe");e.classList.add("post-likes-widget","jetpack-likes-widget"),e.name=t.dataset.name,e.src=t.dataset.src,e.height="55px",e.width="100%",e.frameBorder="0",e.scrolling="no",e.title=t.dataset.title,n.after(e)}if(n.classList.contains("comment-likes-widget-placeholder")){const e=document.createElement("iframe");e.class="comment-likes-widget-frame jetpack-likes-widget-frame",e.name=t.dataset.name,e.src=t.dataset.src,e.height="18px",e.width="100%",e.frameBorder="0",e.scrolling="no",t.querySelector(".comment-like-feedback").after(e),i.push(e)}t.classList.remove("jetpack-likes-widget-unloaded"),t.classList.add("jetpack-likes-widget-loading"),t.querySelector("iframe").addEventListener("load",e=>{t.contains(e.target)&&(s({event:"loadLikeWidget",name:e.target.name,width:e.target.width},window.frames["likes-master"]),n&&(n.style.display="none"),t.classList.remove("jetpack-likes-widget-loading"),t.classList.add("jetpack-likes-widget-loaded"))})}function d(e){const t=e.getBoundingClientRect().top,i=e.getBoundingClientRect().bottom;return t+n>=0&&i<=window.innerHeight+n}window.addEventListener("message",function(e){let n=e&&e.data;if("string"==typeof n)try{n=JSON.parse(n)}catch{return}const i=n&&n.type,l=n&&n.data;if("likesMessage"!==i||void 0===l.event)return;if("https://widgets.wp.com"===e.origin)switch(l.event){case"masterReady":o.then(()=>{t=!0;const e={event:"injectStyles"},n=document.querySelector(".sd-text-color"),i=document.querySelector(".sd-link-color"),o=n&&getComputedStyle(n)||{},a=i&&getComputedStyle(i)||{};document.body.classList.contains("single")&&s({event:"reblogsEnabled"},window.frames["likes-master"]),e.textStyles={color:o.color,fontFamily:o["font-family"],fontSize:o["font-size"],direction:o.direction,fontWeight:o["font-weight"],fontStyle:o["font-style"],textDecoration:o["text-decoration"]},e.linkStyles={color:a.color,fontFamily:a["font-family"],fontSize:a["font-size"],textDecoration:a["text-decoration"],fontWeight:a["font-weight"],fontStyle:a["font-style"]},s(e,window.frames["likes-master"]),r()});break;case"showLikeWidget":case"showCommentLikeWidget":break;case"killCommentLikes":document.querySelectorAll(".jetpack-comment-likes-widget-wrapper").forEach(e
683=>e.remove());break;case"clickReblogFlair":wpcom_reblog&&"function"==typeof wpcom_reblog.toggle_reblog_box_flair&&wpcom_reblog.toggle_reblog_box_flair(l.obj_id);break;case"hideOtherGravatars":a();break;case"showOtherGravatars":{const e=document.querySelector("#likes-other-gravatars");if(!e)break;const t=e.querySelector("ul");e.style.display="none",t.innerHTML="",e.querySelectorAll(".likes-text span").forEach(e=>e.textContent=l.totalLikesLabel),(l.likers||[]).forEach(async(e,n)=>{if("http"!==e.profile_URL.substr(0,4))return;const i=document.createElement("li");t.append(i);const o=encodeURI(e.profile_URL),r=encodeURI(e.avatar_URL);i.innerHTML=`<a href="${o}" rel="nofollow" target="_parent" class="wpl-liker">\n\t\t\t\t\t\t<img src="${r}"\n\t\t\t\t\t\t\talt=""\n\t\t\t\t\t\t\tstyle="width: 28px; height: 28px;" />\n\t\t\t\t\t\t<span></span>\n\t\t\t\t\t</a>`,i.classList.add(e.css_class),i.querySelector("img").alt=l.avatarAltTitle.replace("%s",e.name),i.querySelector("span").innerText=e.name,n===l.likers.length-1&&i.addEventListener("keydown",e=>{"Tab"!==e.key||e.shiftKey||(e.preventDefault(),a(),s({event:"focusLikesCount",parent:l.parent},window.frames["likes-master"]))})});const n=function(){const t="rtl"===getComputedStyle(e).direction,n=document.querySelector(`*[name='${l.parent}']`),i=n.getBoundingClientRect(),o=n.ownerDocument.defaultView,s=i.top+o.pageYOffset,r=i.left+o.pageXOffset;let a;if(e.style.top=s+l.position.top-1+"px",t){const t=l&&l.likers?Math.min(l.likers.length,5):0;a=r+l.position.left+24*t+4,e.style.transform="translateX(-100%)"}else a=r+l.position.left;e.style.left=a+"px",e.style.left="-9999px",e.style.display="block";const c=e.offsetWidth;a+c>o.innerWidth&&(a=i.right-c),e.style.left=a+"px",e.setAttribute("aria-hidden","false")};n(),e.focus();const i=function(e,t){var n;return function(){var i=this,o=arguments;clearTimeout(n),n=setTimeout(function(){e.apply(i,o)},t)}},o=i(n,100);e.__resizeHandler=o,window.addEventListener("resize",o),e.focus()}}}),document.addEventListener("click",a);var f,m,u,p=(f=250,m=l,function(){clearTimeout(u),u=setTimeout(m,f)}),g="function"==typeof IntersectionObserver?new IntersectionObserver(p,{rootMargin:"2000px",threshold:[0,1]}):null;l(),window.addEventListener("scroll",p,!0)})();;
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.