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();
|
|
}
|
|
}() );
|