form-functionality-library
Version:
A modular, flexible form functionality library for Webflow forms supporting single-step, multi-step, and branching forms
330 lines • 12.8 kB
JavaScript
/**
* Form Functionality Library - Main Entry Point
*
* A modular, flexible form functionality library for Webflow forms
* supporting single-step, multi-step, and branching forms.
*
* Version: CACHE_BUST_2025_01_28_22_20_INPUT_ONLY_BORDERS
*/
import { SELECTORS } from './config.js';
import { logVerbose, initFieldCoordinator, resetFieldCoordinator } from './modules/utils.js';
import { clearQueryCache } from './modules/utils.js';
import { FormState } from './modules/formState.js';
// Add version logging to verify which script is loading
console.log('🚀 [FormLib] === SCRIPT VERSION CHECK ===');
console.log('📦 [FormLib] Script Version: v1.7.3 ROBUST ELEMENT LOOKUP');
console.log('🔗 [FormLib] Expected URL: @9705259 or newer');
console.log('⏰ [FormLib] Load Time:', new Date().toISOString());
// Import all modules
import { initMultiStep, goToStep, goToStepById, debugStepSystem, getNavigatedSteps } from './modules/multiStep.js';
import { initMultiStepClean, goToStepByIdClean, getCleanState } from './modules/multiStep-clean.js';
// import { initMultiStepDiagnostic, goToStepByIdDiagnostic, getDiagnosticState } from './modules/multiStep-diagnostic.js';
import { initValidation, validateField, validateStep, validateAllVisibleFields, getValidationState } from './modules/validation.js';
import { initErrors, showError, clearError, clearAllErrors, showErrors, hasError, getFieldsWithErrors, getErrorState } from './modules/errors.js';
import { initializeWebflowErrorHandling, showFieldError, clearFieldError, validateCurrentStep, clearAllErrors as clearAllWebflowErrors, hasFieldError, getFieldsWithErrors as getWebflowFieldsWithErrors } from './modules/webflowNativeErrors.js';
import { initializeCustomErrorSystem, showCustomError, clearCustomError, clearAllCustomErrors, getFieldsWithCustomErrors } from './modules/webflowListenerErrors.js';
import { initBrowserValidationFix } from './modules/browserValidationFix.js';
import { initWebflowIntegration, getWebflowIntegrationStatus } from './modules/webflowIntegration.js';
import { initSummary, updateSummary, clearSummary, getSummaryState } from './modules/summary.js';
// Skip functionality now integrated into multiStep.js
/**
* Main FormLib class - singleton instance
*/
class FormLibrary {
constructor() {
this.initialized = false;
this.rootElement = document;
logVerbose('FormLibrary instance created');
}
/**
* Get singleton instance
*/
static getInstance() {
if (!FormLibrary.instance) {
FormLibrary.instance = new FormLibrary();
}
return FormLibrary.instance;
}
/**
* Initialize the form library
*/
init(root = document) {
if (this.initialized) {
logVerbose('FormLibrary already initialized, reinitializing...');
this.destroy();
}
this.rootElement = root;
logVerbose('Initializing FormLibrary', {
root: root === document ? 'document' : 'custom element'
});
// Check if we have any forms to work with
const multistepForms = root.querySelectorAll(SELECTORS.MULTISTEP);
const logicForms = root.querySelectorAll(SELECTORS.LOGIC);
const stepElements = root.querySelectorAll(SELECTORS.STEP);
logVerbose('Form detection results', {
multistepForms: multistepForms.length,
logicForms: logicForms.length,
stepElements: stepElements.length
});
if (multistepForms.length === 0 && stepElements.length === 0) {
logVerbose('No compatible forms found, library will not initialize');
return;
}
// Initialize modules in dependency order
try {
// 1. Initialize centralized field coordinator (used by all modules)
initFieldCoordinator(root);
// 2. Fix browser validation conflicts (must happen before validation)
initBrowserValidationFix(root);
// 3. Initialize error handling (used by validation)
initErrors(root);
// 3.1. Initialize Webflow-native error handling (v1.9.0)
initializeWebflowErrorHandling();
// 3.2. Initialize custom error system that listens to Webflow (v1.9.5)
initializeCustomErrorSystem();
// 4. Initialize validation (used by multi-step navigation)
initValidation(root);
// 5. Initialize multi-step navigation (linear navigation only)
if (multistepForms.length > 0 || stepElements.length > 0) {
initMultiStep(root); // Includes integrated skip functionality
}
// 6. Initialize Webflow integration (hooks into Webflow's validation system)
initWebflowIntegration();
// 7. Initialize summary functionality (listens to field changes)
initSummary(root);
this.initialized = true;
logVerbose('FormLibrary initialization complete');
// Log initial state
this.logCurrentState();
}
catch (error) {
logVerbose('FormLibrary initialization failed', error);
throw error;
}
}
/**
* Destroy and cleanup the form library
*/
destroy() {
if (!this.initialized) {
logVerbose('FormLibrary not initialized, nothing to destroy');
return;
}
logVerbose('Destroying FormLibrary');
// Reset all modules (they handle their own cleanup)
try {
// Reset centralized field coordinator
resetFieldCoordinator();
// Skip functionality integrated into multiStep
// Note: Other modules will be reset when re-initialized
}
catch (error) {
logVerbose('Error during FormLibrary destruction', error);
}
// Clear FormState
FormState.clear();
// Clear query cache to prevent memory leaks
clearQueryCache();
this.initialized = false;
logVerbose('FormLibrary destruction complete');
}
/**
* Check if library is initialized
*/
isInitialized() {
return this.initialized;
}
/**
* Get current form state for debugging
*/
getState() {
return {
initialized: this.initialized,
formState: FormState.getDebugInfo(),
multiStep: { note: "Simplified linear navigation - debug info removed" },
validation: getValidationState(),
errors: getErrorState(),
webflowIntegration: getWebflowIntegrationStatus(),
summary: getSummaryState(),
// skip functionality integrated into multiStep
};
}
/**
* Log current state to console
*/
logCurrentState() {
const state = this.getState();
logVerbose('Current FormLibrary State', state);
}
/**
* Validate entire form
*/
validateForm() {
if (!this.initialized) {
logVerbose('Cannot validate form - library not initialized');
return false;
}
logVerbose('Validating entire form');
// Use both validation systems
const legacyIsValid = validateAllVisibleFields();
const webflowValidation = validateCurrentStep();
const isValid = legacyIsValid && webflowValidation.isValid;
logVerbose('Form validation result', {
legacyValidation: legacyIsValid,
webflowValidation: webflowValidation.isValid,
overallValid: isValid,
webflowErrors: webflowValidation.errors
});
return isValid;
}
/**
* Reset form to initial state
*/
resetForm() {
if (!this.initialized) {
logVerbose('Cannot reset form - library not initialized');
return;
}
logVerbose('Resetting form to initial state');
// Clear all errors
clearAllErrors();
// Clear form state
FormState.clear();
// Clear summaries
clearSummary();
// Go to first step if multi-step
try {
goToStep(0);
}
catch (error) {
logVerbose('Could not go to first step during reset', error);
}
logVerbose('Form reset complete');
}
/**
* Get form data
*/
getFormData() {
return FormState.getAll();
}
/**
* Set form data
*/
setFormData(data) {
Object.entries(data).forEach(([key, value]) => {
FormState.setField(key, value);
});
// Update summaries after setting data
updateSummary();
logVerbose('Form data set', data);
}
// ADDED: Debug and utility functions for troubleshooting
debugStepSystem() {
debugStepSystem();
}
getNavigatedSteps() {
return getNavigatedSteps();
}
// Error handling methods for testing
showError(fieldName, message) {
showError(fieldName, message);
}
clearError(fieldName) {
clearError(fieldName);
}
clearAllErrors() {
clearAllErrors();
}
hasError(fieldName) {
return hasError(fieldName);
}
getFieldsWithErrors() {
return getFieldsWithErrors();
}
}
// Create and export singleton instance
const FormLib = FormLibrary.getInstance();
// Export the main interface
export default FormLib;
// Export individual modules for advanced usage
export {
// Core
FormState,
// Multi-step (simplified linear navigation)
initMultiStep, goToStep, goToStepById,
// Ultra-minimal clean version (zero legacy code)
initMultiStepClean, goToStepByIdClean, getCleanState,
// Ultra-verbose diagnostic version for debugging
// initMultiStepDiagnostic,
// goToStepByIdDiagnostic,
// getDiagnosticState,
// Validation
initValidation, validateField, validateStep, validateAllVisibleFields,
// Errors
initErrors, showError, clearError, clearAllErrors, showErrors, hasError, getFieldsWithErrors,
// Webflow Native Errors (v1.9.0)
initializeWebflowErrorHandling, showFieldError, clearFieldError, validateCurrentStep, clearAllWebflowErrors, hasFieldError, getWebflowFieldsWithErrors,
// Custom Error System - Webflow Listener (v1.9.5)
initializeCustomErrorSystem, showCustomError, clearCustomError, clearAllCustomErrors, getFieldsWithCustomErrors,
// Browser Validation Fix
initBrowserValidationFix,
// Summary
initSummary, updateSummary, clearSummary };
// Auto-initialize using Webflow's push system for proper timing
if (typeof window !== 'undefined') {
const autoInit = () => {
const multistepForms = document.querySelectorAll(SELECTORS.MULTISTEP);
const stepElements = document.querySelectorAll(SELECTORS.STEP);
console.log('🔍 [FormLib] Auto-init check:', {
multistepForms: multistepForms.length,
stepElements: stepElements.length,
readyState: document.readyState
});
if (multistepForms.length > 0 || stepElements.length > 0) {
console.log('🚀 [FormLib] Auto-initializing FormLibrary');
try {
FormLib.init();
console.log('✅ [FormLib] Auto-initialization complete');
}
catch (error) {
console.error('❌ [FormLib] Auto-initialization failed:', error);
}
}
else {
console.log('⏭️ [FormLib] No compatible forms found, skipping auto-init');
}
};
// Enhanced timing for Webflow compatibility
const webflowWindow = window;
// Try multiple initialization strategies for maximum compatibility
if (webflowWindow.Webflow?.push) {
console.log('🌐 [FormLib] Using Webflow.push for initialization');
webflowWindow.Webflow.push(autoInit);
}
else {
console.log('🔄 [FormLib] Webflow not available, using DOM events');
}
// Always add DOM ready fallback
if (document.readyState === 'loading') {
console.log('⏳ [FormLib] DOM loading, waiting for ready');
document.addEventListener('DOMContentLoaded', autoInit);
}
else {
console.log('✅ [FormLib] DOM already ready, initializing now');
// Add slight delay to ensure all elements are rendered
setTimeout(autoInit, 100);
}
// Additional fallback for dynamic content
setTimeout(() => {
if (!FormLib.isInitialized()) {
console.log('🔁 [FormLib] Fallback initialization attempt');
autoInit();
}
}, 1000);
}
// Make FormLib available globally for testing
if (typeof window !== 'undefined') {
window.FormLib = FormLib;
logVerbose('FormLib attached to window for debugging');
}
//# sourceMappingURL=index.js.map