Add massive collection of CSS, JavaScript and theme assets that were previously excluded: **CSS Files (681 total):** - HVAC plugin-specific styles (hvac-*.css): 34 files including dashboard, certificates, registration, mobile nav, accessibility fixes, animations, and welcome popup - Theme framework files (Astra, builder systems, layouts): 200+ files - Plugin compatibility styles (WooCommerce, WPForms, Elementor, Contact Form 7): 150+ files - WordPress core and editor styles: 50+ files - Responsive and RTL language support: 200+ files **JavaScript Files (400+ total):** - HVAC plugin functionality (hvac-*.js): 27 files including menu systems, dashboard enhancements, profile sharing, mobile responsive features, accessibility, and animations - Framework and library files: jQuery plugins, GSAP, AOS, Swiper, Chart.js, Lottie, Isotope - Plugin compatibility scripts: WPForms, WooCommerce, Elementor, Contact Form 7, LifterLMS - WordPress core functionality: customizer, admin, block editor compatibility - Third-party integrations: Stripe, SMTP, analytics, search functionality **Assets:** - Certificate background images and logos - Comprehensive theme styling infrastructure - Mobile-responsive design systems - Cross-browser compatibility assets - Performance-optimized minified versions **Updated .gitignore:** - Fixed asset directory whitelisting patterns to properly include CSS/JS/images - Added proper directory structure recognition (!/assets/css/, !/assets/js/, etc.) - Maintains security by excluding sensitive files while including essential assets This commit provides the complete frontend infrastructure needed for: - Full theme functionality and styling - Plugin feature implementations - Mobile responsiveness and accessibility - Cross-browser compatibility - Performance optimization - Developer workflow support
385 lines
No EOL
15 KiB
JavaScript
385 lines
No EOL
15 KiB
JavaScript
// Function to scroll to the div element with the query ID
|
|
function scrollToQueryId( queryId ) {
|
|
const targetElement = document.getElementById( `uagb-block-queryid-${queryId}` );
|
|
|
|
if ( targetElement ) {
|
|
const rect = targetElement.getBoundingClientRect();
|
|
const adminBar = document.querySelector( '#wpadminbar' );
|
|
const adminBarOffSetHeight = adminBar?.offsetHeight || 0;
|
|
const scrollTop = window?.pageYOffset || document?.documentElement?.scrollTop;
|
|
const targetOffset = ( rect?.top + scrollTop ) - adminBarOffSetHeight;
|
|
|
|
window.scrollTo( {
|
|
top: targetOffset,
|
|
behavior: 'smooth'
|
|
} );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Function to find the ancestor with the given class name.
|
|
*
|
|
* @param {Element} element The element.
|
|
* @param {string} className The class name.
|
|
* @return {Element} The element.
|
|
* @since 1.2.0
|
|
*/
|
|
function findAncestorWithClass( element, className ) {
|
|
while ( element && ! element.classList.contains( className ) ) {
|
|
element = element.parentNode;
|
|
}
|
|
return element;
|
|
}
|
|
|
|
document.addEventListener( 'DOMContentLoaded', function () {
|
|
// Debounce function to limit the rate of execution
|
|
function debounce( func, wait ) {
|
|
let timeout;
|
|
|
|
return function executedFunction( ...args ) {
|
|
const context = this;
|
|
const later = () => {
|
|
timeout = null;
|
|
func.apply( context, args );
|
|
};
|
|
|
|
clearTimeout( timeout );
|
|
timeout = setTimeout( later, wait );
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Function to update the loop wrapper content
|
|
* as per data in filters.
|
|
*
|
|
* @param {Event} event The event.
|
|
* @param {string} paged The paged parameter for displaying a particular page on click of pagination links.
|
|
* @param {string} buttonFilter The array of selected button value.
|
|
* @param {string} current The current selected element value.
|
|
* @param {string} loopParentContainer The loop parent container.
|
|
* @return {Promise} The Promise.
|
|
* @throws {Error} The error.
|
|
* @since 1.2.0
|
|
*/
|
|
async function updateContent( event, paged = null, buttonFilter = null, current = null, loopParentContainer ) {
|
|
try{
|
|
const loopBuilder = loopParentContainer;
|
|
const search = loopBuilder?.querySelector( '.uagb-loop-search' )?.value;
|
|
const sorting = loopBuilder?.querySelector( '.uagb-loop-sort' )?.value;
|
|
const category = current?.value;
|
|
const categoryButtonFilterContainer = loopBuilder?.querySelector( '.uagb-loop-category-inner' );
|
|
const formData = new FormData();
|
|
if( search ){
|
|
formData.append( 'search', search );
|
|
}
|
|
if( sorting ){
|
|
formData.append( 'sorting', sorting );
|
|
}
|
|
if ( category ) {
|
|
formData.append( 'category', category );
|
|
}
|
|
const checkBoxValues = loopParentContainer?.querySelectorAll( '.uagb-cat-checkbox' );
|
|
// Initialize an array to store checked checkbox values.
|
|
const checkedValues = [];
|
|
checkBoxValues?.forEach( checkBoxVal => {
|
|
// Check if the checkbox is checked.
|
|
const isChecked = checkBoxVal.checked;
|
|
if ( isChecked && checkBoxVal.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ) {
|
|
// Add the value to the array.
|
|
checkedValues.push( checkBoxVal.value );
|
|
}
|
|
} );
|
|
if ( checkedValues ) {
|
|
formData.append( 'checkbox', checkedValues );
|
|
}
|
|
if( paged ){
|
|
formData.append( 'paged', paged );
|
|
}
|
|
if ( buttonFilter ){
|
|
formData.append( 'buttonFilter', JSON.stringify( buttonFilter.type ) );
|
|
}
|
|
const queryId = event.target?.dataset?.uagbBlockQueryId || event.target?.parentElement?.dataset?.uagbBlockQueryId || categoryButtonFilterContainer?.dataset?.uagbBlockQueryId || event?.dataset?.uagbBlockQueryId || event.target.closest( 'a' )?.getAttribute( 'data-uagb-block-query-id' );
|
|
scrollToQueryId( queryId ); // Scroll to top when ajax based pagination.
|
|
formData.append( 'queryId', queryId );
|
|
formData.append( 'block_id', loopBuilder?.getAttribute( 'data-block_id' ) );
|
|
const output = await getUpdatedLoopWrapperContent( formData );
|
|
const loopElement = loopBuilder?.querySelector( '#uagb-block-queryid-' + queryId );
|
|
if ( loopElement && output?.content?.wrapper ) {
|
|
loopElement.innerHTML = output.content.wrapper;
|
|
}
|
|
const loopPaginationContainers = loopBuilder?.querySelectorAll( '#uagb-block-pagination-queryid-'+queryId );
|
|
if ( loopPaginationContainers && output?.content?.pagination ) {
|
|
loopPaginationContainers.innerHTML = output?.content?.pagination;
|
|
}
|
|
loopPaginationContainers?.forEach( loopPaginationContainer => {
|
|
loopPaginationContainer.innerHTML = output.content.pagination;
|
|
} );
|
|
} catch( error ){
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handles the input event for the search functionality within the UAGB Loop Builder block.
|
|
* Synchronizes input values across all search inputs within the same loop builder container
|
|
* and triggers a content update.
|
|
*
|
|
* @param {Event} event - The input event triggered by the user.
|
|
* @since 1.2.0
|
|
*/
|
|
function handleInput( event ) {
|
|
const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' );
|
|
const searchInputs = loopParentContainer.querySelectorAll( '.uagb-loop-search' );
|
|
searchInputs.forEach( searchInput => {
|
|
if( searchInput.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ){
|
|
searchInput.value = event.target.value;
|
|
}
|
|
} );
|
|
updateContent( event, null, null, null, loopParentContainer );
|
|
}
|
|
|
|
/**
|
|
* Handles the checkbox selection within the UAGB Loop Builder block.
|
|
* Collects the values of all checked checkboxes that match the block query ID
|
|
* and triggers a content update.
|
|
*
|
|
* @param {Event} event - The change event triggered by the user when interacting with a checkbox.
|
|
* @since 1.2.0
|
|
*/
|
|
function handleCheckBoxVal( event ) {
|
|
const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' );
|
|
const checkBoxValues = loopParentContainer.querySelectorAll( '.uagb-cat-checkbox' );
|
|
// Initialize an array to store checked checkbox values.
|
|
const checkedValues = [];
|
|
checkBoxValues.forEach( checkBoxVal => {
|
|
// Check if the checkbox is checked.
|
|
const isChecked = checkBoxVal.checked;
|
|
if ( isChecked && checkBoxVal.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ) {
|
|
// Add the value to the array.
|
|
checkedValues.push( checkBoxVal.value );
|
|
}
|
|
} );
|
|
updateContent( event, null, null, null, loopParentContainer );
|
|
}
|
|
|
|
/**
|
|
* Handles the selection event on the search filter.
|
|
* Updates the value of all relevant search filter elements with the same query ID and triggers content update.
|
|
*
|
|
* @param {Event} event - The select event triggered by the user interaction.
|
|
* @since 1.2.0
|
|
*/
|
|
function handleSelect( event ) {
|
|
const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' );
|
|
const sortSelects = loopParentContainer.querySelectorAll( '.uagb-loop-sort' );
|
|
sortSelects.forEach( sortSelect => {
|
|
if( sortSelect.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ){
|
|
sortSelect.value = event.target.value;
|
|
}
|
|
} );
|
|
updateContent( event, null, null, null, loopParentContainer );
|
|
}
|
|
|
|
/**
|
|
* Handles the category selection event on a dropdown filter.
|
|
* Updates the value of all relevant category select elements with the same query ID and triggers content update.
|
|
*
|
|
* @param {Event} event - The select event triggered by the user interaction.
|
|
* @since 1.2.0
|
|
*/
|
|
function handleCatSelect( event ) {
|
|
const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' );
|
|
const categorySelects = loopParentContainer.querySelectorAll( '.uagb-loop-category' );
|
|
categorySelects.forEach( categorySelect => {
|
|
if ( categorySelect.getAttribute( 'data-uagb-block-query-id' ) === event.target.dataset.uagbBlockQueryId ) {
|
|
categorySelect.value = event.target.value;
|
|
}
|
|
} );
|
|
updateContent( event, null, null, this, loopParentContainer );
|
|
}
|
|
|
|
/**
|
|
* Resets the values of elements within a container based on their query ID.
|
|
*
|
|
* @param {HTMLElement} container - The container element to search within.
|
|
* @param {string} selector - The CSS selector for the elements to reset.
|
|
* @param {string} queryId - The query ID to match.
|
|
* @param {Function} resetCallback - A callback function to apply the reset logic to each element.
|
|
* @since 1.2.0
|
|
*/
|
|
function resetValues( container, selector, queryId, resetCallback ) {
|
|
const elements = container.querySelectorAll( selector );
|
|
elements.forEach( element => {
|
|
const elementQueryId = element.dataset.uagbBlockQueryId;
|
|
if ( elementQueryId === queryId ) {
|
|
resetCallback( element );
|
|
}
|
|
} );
|
|
}
|
|
|
|
/**
|
|
* Handles the reset event for all filters within the loop builder block.
|
|
* Resets the values of search inputs, sort selects, category selects, and checkboxes to their default state.
|
|
*
|
|
* @param {Event} event - The reset event triggered by the user interaction.
|
|
* @since 1.2.0
|
|
*/
|
|
function handleReset( event ) {
|
|
const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' );
|
|
// Get the query ID from the event target
|
|
let queryId = event.target.parentElement.dataset.uagbBlockQueryId;
|
|
if ( event.target.tagName.toLowerCase() === 'a' ) {
|
|
queryId = event.target.dataset.uagbBlockQueryId;
|
|
} else if ( event.target.tagName.toLowerCase() === 'svg' || event.target.tagName.toLowerCase() === 'path' ) {
|
|
queryId = event.target.closest( 'a' )?.getAttribute( 'data-uagb-block-query-id' );
|
|
}
|
|
|
|
// Reset the value of the filter inputs
|
|
const loopBuilder = findAncestorWithClass( event.target.parentNode, 'wp-block-uagb-loop-builder' );
|
|
|
|
resetValues( loopBuilder, '.uagb-loop-search', queryId, element => {
|
|
element.value = ''; // Reset search input value
|
|
} );
|
|
|
|
resetValues( loopBuilder, '.uagb-loop-sort', queryId, element => {
|
|
element.value = ''; // Reset sort select value
|
|
} );
|
|
|
|
resetValues( loopBuilder, '.uagb-loop-category', queryId, element => {
|
|
element.value = ''; // Reset category select value
|
|
} );
|
|
|
|
resetValues( loopBuilder, '.uagb-cat-checkbox', queryId, element => {
|
|
element.checked = false; // Uncheck category checkbox
|
|
} );
|
|
// Trigger the updateContent function to reflect the changes
|
|
updateContent( event, null, null, null, loopParentContainer );
|
|
}
|
|
|
|
const resetButtons = document.querySelectorAll( '.uagb-loop-reset' );
|
|
|
|
const searchInputs = document.querySelectorAll( '.uagb-loop-search' );
|
|
|
|
searchInputs.forEach( searchInput => {
|
|
const debouncedHandleInput = debounce( handleInput, 250 );
|
|
searchInput.addEventListener( 'input', debouncedHandleInput );
|
|
} );
|
|
|
|
const sortSelects = document.querySelectorAll( '.uagb-loop-sort' );
|
|
|
|
sortSelects.forEach( sortSelect => {
|
|
const debouncedHandleInput = debounce( handleSelect, 250 );
|
|
sortSelect.addEventListener( 'change', debouncedHandleInput );
|
|
} );
|
|
|
|
const categorySelects = document.querySelectorAll( '.uagb-loop-category' );
|
|
|
|
categorySelects.forEach( categorySelect => {
|
|
const debouncedHandleInput = debounce( handleCatSelect, 250 );
|
|
categorySelect.addEventListener( 'change', debouncedHandleInput );
|
|
} );
|
|
|
|
// Get a reference to the checkbox element.
|
|
const checkBoxValues = document.querySelectorAll( '.uagb-cat-checkbox' );
|
|
checkBoxValues.forEach( checkBoxVal => {
|
|
const debouncedHandleInput = debounce( handleCheckBoxVal, 250 );
|
|
checkBoxVal.addEventListener( 'click', debouncedHandleInput );
|
|
} );
|
|
|
|
resetButtons.forEach( resetButton => {
|
|
const debouncedHandleReset = debounce( handleReset, 250 );
|
|
resetButton.addEventListener( 'click', debouncedHandleReset );
|
|
} );
|
|
|
|
const oldPaginations = document.querySelectorAll( '.wp-block-uagb-loop-builder > :not(.uagb-loop-pagination).wp-block-uagb-buttons' );
|
|
|
|
oldPaginations?.forEach( function( container ) {
|
|
// Create a new div with class "parent-container"
|
|
const parentContainer = document.createElement( 'div' );
|
|
parentContainer.classList.add( 'uagb-loop-pagination' );
|
|
const queryIdPAginationLink = container.querySelector( 'a' ).getAttribute( 'data-uagb-block-query-id' );
|
|
parentContainer.id = 'uagb-block-pagination-queryid-'+queryIdPAginationLink;
|
|
|
|
// Append the container content to the new div
|
|
parentContainer.innerHTML = container.outerHTML;
|
|
|
|
// Append the new div after the original container
|
|
container.parentNode.insertBefore( parentContainer, container.nextSibling );
|
|
|
|
// Remove the original container
|
|
container.parentNode.removeChild( container );
|
|
} );
|
|
|
|
const paginationContainer = document.querySelectorAll( '.uagb-loop-pagination' );
|
|
|
|
paginationContainer.forEach( pagination => {
|
|
pagination.addEventListener( 'click', function( event ) {
|
|
event.preventDefault();
|
|
const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' );
|
|
if ( event.target.tagName.toLowerCase() === 'a' ){
|
|
updateContent( event, event.target.dataset.uagbBlockQueryPaged, null, null, loopParentContainer );
|
|
}
|
|
if ( ( event.target.tagName.toLowerCase() === 'div' && event.target.parentElement.tagName.toLowerCase() === 'a' ) ) {
|
|
updateContent( event, event.target.parentElement.dataset.uagbBlockQueryPaged, null, null, loopParentContainer );
|
|
}
|
|
if ( event.target.tagName.toLowerCase() === 'svg' && event.target.tagName.toLowerCase() === 'path' ) {
|
|
updateContent( event.target.parentElement.parentElement, event?.target?.closest( 'a' )?.getAttribute( 'data-uagb-block-query-paged' ), null, null, loopParentContainer );
|
|
}
|
|
} );
|
|
} );
|
|
|
|
const categoryButtonFilterContainer = document.querySelectorAll( '.uagb-loop-category-inner ' );
|
|
|
|
categoryButtonFilterContainer.forEach( buttons => {
|
|
buttons.addEventListener( 'click', function ( event ) {
|
|
event.preventDefault();
|
|
const loopParentContainer = this.closest( '.wp-block-uagb-loop-builder' );
|
|
if ( event.target.tagName.toLowerCase() === 'a' ) {
|
|
updateContent( event, null, event.target.children[0].dataset, null, loopParentContainer );
|
|
}
|
|
if ( ( event.target.tagName.toLowerCase() === 'div' && event.target.parentElement.tagName.toLowerCase() === 'a' ) ) {
|
|
updateContent( event, null, event.target.dataset, null, loopParentContainer );
|
|
}
|
|
} );
|
|
} );
|
|
} );
|
|
|
|
/**
|
|
* Function to get the updated loop wrapper content.
|
|
* as per data in filters.
|
|
*
|
|
* @param {FormData} data The form data.
|
|
* @since 1.2.0
|
|
* @return {Promise} The Promise.
|
|
*/
|
|
function getUpdatedLoopWrapperContent( data ) {
|
|
// Create a new FormData object
|
|
data.append( 'action', 'uagb_update_loop_builder_content' );
|
|
data.append( 'postId', uagb_loop_builder?.post_id );
|
|
data.append( 'postType', uagb_loop_builder?.what_post_type );
|
|
data.append( 'security', uagb_loop_builder?.nonce )
|
|
|
|
// The function now returns a Promise
|
|
return fetch( uagb_loop_builder?.ajax_url, {
|
|
method: 'POST',
|
|
credentials: 'same-origin',
|
|
body: data,
|
|
} )
|
|
.then( response => {
|
|
if ( ! response.ok ) {
|
|
throw new Error( 'Network response was not ok' );
|
|
}
|
|
return response.json();
|
|
} )
|
|
.then( output => {
|
|
if ( output.success ) {
|
|
// Return the actual output
|
|
return output.data;
|
|
}
|
|
throw new Error( output.data.message );
|
|
|
|
} )
|
|
.catch( error => {
|
|
throw error; // Propagate the error
|
|
} );
|
|
} |