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
		
			
				
	
	
		
			320 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			320 lines
		
	
	
	
		
			7.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* global wpforms_settings */
 | |
| 
 | |
| ( function() {
 | |
| 	/**
 | |
| 	 * Predefine hint text to display.
 | |
| 	 *
 | |
| 	 * @since 1.5.6
 | |
| 	 * @since 1.6.4 Added a new macros - {remaining}.
 | |
| 	 *
 | |
| 	 * @param {string} hintText Hint text.
 | |
| 	 * @param {number} count    Current count.
 | |
| 	 * @param {number} limit    Limit to.
 | |
| 	 *
 | |
| 	 * @return {string} Predefined hint text.
 | |
| 	 */
 | |
| 	function renderHint( hintText, count, limit ) {
 | |
| 		return hintText.replace( '{count}', count ).replace( '{limit}', limit ).replace( '{remaining}', limit - count );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Create HTMLElement hint element with text.
 | |
| 	 *
 | |
| 	 * @since 1.5.6
 | |
| 	 *
 | |
| 	 * @param {number|string} formId  Form id.
 | |
| 	 * @param {number|string} fieldId Form field id.
 | |
| 	 * @param {string}        text    Hint text.
 | |
| 	 *
 | |
| 	 * @return {Object} HTMLElement hint element with text.
 | |
| 	 */
 | |
| 	function createHint( formId, fieldId, text ) {
 | |
| 		const hint = document.createElement( 'div' );
 | |
| 
 | |
| 		formId = typeof formId === 'object' ? '' : formId;
 | |
| 		fieldId = typeof fieldId === 'object' ? '' : fieldId;
 | |
| 
 | |
| 		hint.classList.add( 'wpforms-field-limit-text' );
 | |
| 		hint.id = 'wpforms-field-limit-text-' + formId + '-' + fieldId;
 | |
| 		hint.setAttribute( 'aria-live', 'polite' );
 | |
| 		hint.textContent = text;
 | |
| 
 | |
| 		return hint;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Keyup/Keydown event higher order function for characters limit.
 | |
| 	 *
 | |
| 	 * @since 1.5.6
 | |
| 	 *
 | |
| 	 * @param {Object} hint  HTMLElement hint element.
 | |
| 	 * @param {number} limit Max allowed number of characters.
 | |
| 	 *
 | |
| 	 * @return {Function} Handler function.
 | |
| 	 */
 | |
| 	function checkCharacters( hint, limit ) {
 | |
| 		// noinspection JSUnusedLocalSymbols
 | |
| 		return function( e ) { // eslint-disable-line no-unused-vars
 | |
| 			hint.textContent = renderHint(
 | |
| 				window.wpforms_settings.val_limit_characters,
 | |
| 				this.value.length,
 | |
| 				limit
 | |
| 			);
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Count words in the string.
 | |
| 	 *
 | |
| 	 * @since 1.6.2
 | |
| 	 *
 | |
| 	 * @param {string} string String value.
 | |
| 	 *
 | |
| 	 * @return {number} Words count.
 | |
| 	 */
 | |
| 	function countWords( string ) {
 | |
| 		if ( typeof string !== 'string' ) {
 | |
| 			return 0;
 | |
| 		}
 | |
| 
 | |
| 		if ( ! string.length ) {
 | |
| 			return 0;
 | |
| 		}
 | |
| 
 | |
| 		[
 | |
| 			/([A-Z]+),([A-Z]+)/gi,
 | |
| 			/([0-9]+),([A-Z]+)/gi,
 | |
| 			/([A-Z]+),([0-9]+)/gi,
 | |
| 		].forEach( function( pattern ) {
 | |
| 			string = string.replace( pattern, '$1, $2' );
 | |
| 		} );
 | |
| 
 | |
| 		return string.split( /\s+/ ).length;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Keyup/Keydown event higher order function for words limit.
 | |
| 	 *
 | |
| 	 * @since 1.5.6
 | |
| 	 *
 | |
| 	 * @param {Object} hint  HTMLElement hint element.
 | |
| 	 * @param {number} limit Max allowed number of characters.
 | |
| 	 *
 | |
| 	 * @return {Function} Handler function.
 | |
| 	 */
 | |
| 	function checkWords( hint, limit ) {
 | |
| 		return function( e ) {
 | |
| 			const value = this.value.trim(),
 | |
| 				words = countWords( value );
 | |
| 
 | |
| 			hint.textContent = renderHint(
 | |
| 				window.wpforms_settings.val_limit_words,
 | |
| 				words,
 | |
| 				limit
 | |
| 			);
 | |
| 
 | |
| 			// We should prevent the keys: Enter, Space, Comma.
 | |
| 			if ( [ 13, 32, 188 ].indexOf( e.keyCode ) > -1 && words >= limit ) {
 | |
| 				e.preventDefault();
 | |
| 			}
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get passed text from the clipboard.
 | |
| 	 *
 | |
| 	 * @since 1.5.6
 | |
| 	 *
 | |
| 	 * @param {ClipboardEvent} e Clipboard event.
 | |
| 	 *
 | |
| 	 * @return {string} Text from clipboard.
 | |
| 	 */
 | |
| 	function getPastedText( e ) {
 | |
| 		if ( window.clipboardData && window.clipboardData.getData ) { // IE
 | |
| 			return window.clipboardData.getData( 'Text' );
 | |
| 		} else if ( e.clipboardData && e.clipboardData.getData ) {
 | |
| 			return e.clipboardData.getData( 'text/plain' );
 | |
| 		}
 | |
| 
 | |
| 		return '';
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Paste event higher order function for character limit.
 | |
| 	 *
 | |
| 	 * @since 1.6.7.1
 | |
| 	 *
 | |
| 	 * @param {number} limit Max allowed number of characters.
 | |
| 	 *
 | |
| 	 * @return {Function} Event handler.
 | |
| 	 */
 | |
| 	function pasteText( limit ) {
 | |
| 		return function( e ) {
 | |
| 			e.preventDefault();
 | |
| 
 | |
| 			const pastedText = getPastedText( e ),
 | |
| 				newPosition = this.selectionStart + pastedText.length,
 | |
| 				newText = this.value.substring( 0, this.selectionStart ) + pastedText + this.value.substring( this.selectionStart );
 | |
| 
 | |
| 			this.value = newText.substring( 0, limit );
 | |
| 			this.setSelectionRange( newPosition, newPosition );
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Limit string length to a certain number of words, preserving line breaks.
 | |
| 	 *
 | |
| 	 * @since 1.6.8
 | |
| 	 *
 | |
| 	 * @param {string} text  Text.
 | |
| 	 * @param {number} limit Max allowed number of words.
 | |
| 	 *
 | |
| 	 * @return {string} Text with the limited number of words.
 | |
| 	 */
 | |
| 	function limitWords( text, limit ) {
 | |
| 		let result = '';
 | |
| 
 | |
| 		// Regular expression pattern: match any space character.
 | |
| 		const regEx = /\s+/g;
 | |
| 
 | |
| 		// Store separators for further join.
 | |
| 		const separators = text.trim().match( regEx ) || [];
 | |
| 
 | |
| 		// Split the new text by regular expression.
 | |
| 		const newTextArray = text.split( regEx );
 | |
| 
 | |
| 		// Limit the number of words.
 | |
| 		newTextArray.splice( limit, newTextArray.length );
 | |
| 
 | |
| 		// Join the words together using stored separators.
 | |
| 		for ( let i = 0; i < newTextArray.length; i++ ) {
 | |
| 			result += newTextArray[ i ] + ( separators[ i ] || '' );
 | |
| 		}
 | |
| 
 | |
| 		return result.trim();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Paste event higher order function for words limit.
 | |
| 	 *
 | |
| 	 * @since 1.5.6
 | |
| 	 *
 | |
| 	 * @param {number} limit Max allowed number of words.
 | |
| 	 *
 | |
| 	 * @return {Function} Event handler.
 | |
| 	 */
 | |
| 	function pasteWords( limit ) {
 | |
| 		return function( e ) {
 | |
| 			e.preventDefault();
 | |
| 
 | |
| 			const pastedText = getPastedText( e ),
 | |
| 				newPosition = this.selectionStart + pastedText.length,
 | |
| 				newText = this.value.substring( 0, this.selectionStart ) + pastedText + this.value.substring( this.selectionStart );
 | |
| 
 | |
| 			this.value = limitWords( newText, limit );
 | |
| 			this.setSelectionRange( newPosition, newPosition );
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Array.from polyfill.
 | |
| 	 *
 | |
| 	 * @since 1.5.6
 | |
| 	 *
 | |
| 	 * @param {Object} el Iterator.
 | |
| 	 *
 | |
| 	 * @return {Object} Array.
 | |
| 	 */
 | |
| 	function arrFrom( el ) {
 | |
| 		return [].slice.call( el );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Public functions and properties.
 | |
| 	 *
 | |
| 	 * @since 1.8.9
 | |
| 	 *
 | |
| 	 * @type {Object}
 | |
| 	 */
 | |
| 	const app = {
 | |
| 		/**
 | |
| 		 * Init text limit hint.
 | |
| 		 *
 | |
| 		 * @since 1.8.9
 | |
| 		 *
 | |
| 		 * @param {string} context Context selector.
 | |
| 		 */
 | |
| 		initHint( context ) {
 | |
| 			arrFrom( document.querySelectorAll( context + ' .wpforms-limit-characters-enabled' ) )
 | |
| 				.map(
 | |
| 					function( e ) { // eslint-disable-line array-callback-return
 | |
| 						const limit = parseInt( e.dataset.textLimit, 10 ) || 0;
 | |
| 
 | |
| 						e.value = e.value.slice( 0, limit );
 | |
| 
 | |
| 						const hint = createHint(
 | |
| 							e.dataset.formId,
 | |
| 							e.dataset.fieldId,
 | |
| 							renderHint(
 | |
| 								wpforms_settings.val_limit_characters,
 | |
| 								e.value.length,
 | |
| 								limit
 | |
| 							)
 | |
| 						);
 | |
| 
 | |
| 						const fn = checkCharacters( hint, limit );
 | |
| 
 | |
| 						e.parentNode.appendChild( hint );
 | |
| 						e.addEventListener( 'keydown', fn );
 | |
| 						e.addEventListener( 'keyup', fn );
 | |
| 						e.addEventListener( 'paste', pasteText( limit ) );
 | |
| 					}
 | |
| 				);
 | |
| 
 | |
| 			arrFrom( document.querySelectorAll( context + ' .wpforms-limit-words-enabled' ) )
 | |
| 				.map(
 | |
| 					function( e ) { // eslint-disable-line array-callback-return
 | |
| 						const limit = parseInt( e.dataset.textLimit, 10 ) || 0;
 | |
| 
 | |
| 						e.value = limitWords( e.value, limit );
 | |
| 
 | |
| 						const hint = createHint(
 | |
| 							e.dataset.formId,
 | |
| 							e.dataset.fieldId,
 | |
| 							renderHint(
 | |
| 								wpforms_settings.val_limit_words,
 | |
| 								countWords( e.value.trim() ),
 | |
| 								limit
 | |
| 							)
 | |
| 						);
 | |
| 
 | |
| 						const fn = checkWords( hint, limit );
 | |
| 
 | |
| 						e.parentNode.appendChild( hint );
 | |
| 
 | |
| 						e.addEventListener( 'keydown', fn );
 | |
| 						e.addEventListener( 'keyup', fn );
 | |
| 						e.addEventListener( 'paste', pasteWords( limit ) );
 | |
| 					}
 | |
| 				);
 | |
| 		},
 | |
| 	};
 | |
| 
 | |
| 	/**
 | |
| 	 * DOMContentLoaded handler.
 | |
| 	 *
 | |
| 	 * @since 1.5.6
 | |
| 	 */
 | |
| 	function ready() {
 | |
| 		// Expose to the world.
 | |
| 		window.WPFormsTextLimit = app;
 | |
| 
 | |
| 		app.initHint( 'body' );
 | |
| 	}
 | |
| 
 | |
| 	if ( document.readyState === 'loading' ) {
 | |
| 		document.addEventListener( 'DOMContentLoaded', ready );
 | |
| 	} else {
 | |
| 		ready();
 | |
| 	}
 | |
| }() );
 |