UNPKG

form-functionality-library

Version:

A modular, flexible form functionality library for Webflow forms supporting single-step, multi-step, and branching forms

292 lines 9.33 kB
/** * Summary module for collecting and displaying form field values */ import { SELECTORS, DEFAULTS } from '../config.js'; import { logVerbose, queryAllByAttr, getAttrValue } from './utils.js'; import { FormState } from './formState.js'; import { formEvents } from './events.js'; let initialized = false; let eventCleanupFunctions = []; let summaryFields = []; /** * Initialize summary functionality */ export function initSummary(root = document) { if (initialized) { logVerbose('Summary already initialized, cleaning up first'); resetSummary(); } logVerbose('Initializing summary functionality'); // Find all summary display elements const summaryElements = queryAllByAttr(SELECTORS.SUMMARY_FIELD, root); logVerbose(`Found ${summaryElements.length} summary fields`); // Set up summary field configurations setupSummaryFields(summaryElements); // Set up event listeners for field changes via centralized coordinator setupSummaryEventListeners(); // Initial summary update updateAllSummaries(); initialized = true; formEvents.registerModule('summary'); logVerbose('Summary initialization complete'); } /** * Set up summary field configurations */ function setupSummaryFields(summaryElements) { summaryElements.forEach(element => { const summaryFieldAttr = getAttrValue(element, 'data-summary-field'); if (!summaryFieldAttr) return; // Parse field names (pipe-separated) const fieldNames = summaryFieldAttr.split('|').map(name => name.trim()); // Get join type const joinAttr = getAttrValue(element, 'data-join'); const joinType = joinAttr && joinAttr in DEFAULTS.JOIN_SEPARATOR ? joinAttr : 'space'; // Get categorization attributes const type = getAttrValue(element, 'data-summary-type') || undefined; const subtype = getAttrValue(element, 'data-summary-subtype') || undefined; const number = getAttrValue(element, 'data-summary-number') || undefined; const summaryField = { element: element, fieldNames, joinType, type, subtype, number }; summaryFields.push(summaryField); logVerbose('Summary field configured', { fieldNames, joinType, type, subtype, number }); }); } /** * Set up event listeners for field changes via centralized coordinator */ function setupSummaryEventListeners() { // Listen to centralized field events instead of direct DOM events const cleanup1 = formEvents.on('field:change', handleFieldChangeEvent); const cleanup2 = formEvents.on('field:input', handleFieldChangeEvent); eventCleanupFunctions.push(cleanup1, cleanup2); logVerbose('Summary module subscribed to centralized field events'); } /** * Handle field change events from centralized coordinator */ function handleFieldChangeEvent(data) { const { fieldName, value, eventType } = data; logVerbose(`Summary received field ${eventType}: ${fieldName}`, { value }); // Note: FormState already updated by centralized coordinator // Update summaries that include this field updateSummariesForField(fieldName); } /** * Update summaries that include a specific field */ function updateSummariesForField(fieldName) { summaryFields.forEach(summaryField => { if (summaryField.fieldNames.includes(fieldName)) { updateSummaryField(summaryField); } }); } /** * Update all summary fields */ export function updateSummary() { logVerbose('Updating all summaries'); updateAllSummaries(); } /** * Update all summary fields (internal) */ function updateAllSummaries() { summaryFields.forEach(summaryField => { updateSummaryField(summaryField); }); } /** * Update a specific summary field */ function updateSummaryField(summaryField) { const values = []; // Collect values for all field names summaryField.fieldNames.forEach(fieldName => { const value = FormState.getField(fieldName); if (value !== null && value !== undefined && value !== '') { // Handle different value types if (Array.isArray(value)) { values.push(...value.filter(v => v !== '')); } else { values.push(String(value)); } } }); // Join values according to join type const joinedValue = joinValues(values, summaryField.joinType); // Update the summary element updateSummaryElement(summaryField.element, joinedValue); logVerbose(`Summary field updated`, { fieldNames: summaryField.fieldNames, values, joinType: summaryField.joinType, result: joinedValue }); } /** * Join values according to join type */ function joinValues(values, joinType) { if (values.length === 0) return ''; const separator = DEFAULTS.JOIN_SEPARATOR[joinType]; return values.join(separator); } /** * Update summary element content */ function updateSummaryElement(element, value) { // Update text content element.textContent = value; // Add/remove empty class for styling if (value === '') { element.classList.add('summary-empty'); element.classList.remove('summary-filled'); } else { element.classList.remove('summary-empty'); element.classList.add('summary-filled'); } } /** * Get summary by type/subtype/number */ export function getSummaryByCategory(type, subtype, number) { const matchingSummaries = []; summaryFields.forEach(summaryField => { const matches = ((!type || summaryField.type === type) && (!subtype || summaryField.subtype === subtype) && (!number || summaryField.number === number)); if (matches) { const currentValue = summaryField.element.textContent || ''; if (currentValue) { matchingSummaries.push(currentValue); } } }); logVerbose('Retrieved summaries by category', { type, subtype, number, results: matchingSummaries }); return matchingSummaries; } /** * Clear summary for specific fields */ export function clearSummary(fieldNames) { if (fieldNames) { logVerbose('Clearing specific summary fields', fieldNames); // Clear specific fields from FormState FormState.clearFields(fieldNames); // Update affected summaries fieldNames.forEach(fieldName => { updateSummariesForField(fieldName); }); } else { logVerbose('Clearing all summaries'); // Clear all field values from FormState FormState.clear(); // Update all summaries updateAllSummaries(); } } /** * Get all summary values as an object */ export function getAllSummaryValues() { const summaryValues = {}; summaryFields.forEach(summaryField => { const values = []; summaryField.fieldNames.forEach(fieldName => { const value = FormState.getField(fieldName); if (value !== null && value !== undefined && value !== '') { values.push(String(value)); } }); const joinedValue = joinValues(values, summaryField.joinType); const elementId = summaryField.element.id || `summary-${summaryField.fieldNames.join('-')}`; summaryValues[elementId] = joinedValue; }); return summaryValues; } /** * Force refresh all summaries from current FormState */ export function refreshSummaries() { logVerbose('Refreshing all summaries from FormState'); updateAllSummaries(); } /** * Add custom summary field programmatically */ export function addCustomSummary(element, fieldNames, joinType = 'space', type, subtype, number) { const summaryField = { element, fieldNames, joinType, type, subtype, number }; summaryFields.push(summaryField); updateSummaryField(summaryField); logVerbose('Custom summary field added', { fieldNames, joinType, type, subtype, number }); } /** * Get current summary state for debugging */ export function getSummaryState() { const state = {}; summaryFields.forEach((summaryField, index) => { const key = summaryField.type && summaryField.subtype && summaryField.number ? `${summaryField.type}-${summaryField.subtype}-${summaryField.number}` : `summary-${index}`; state[key] = { hasContent: (summaryField.element.textContent || '').trim().length > 0 }; }); return state; } /** * Reset summary functionality */ function resetSummary() { logVerbose('Resetting summary functionality'); // Clean up event listeners eventCleanupFunctions.forEach(cleanup => cleanup()); eventCleanupFunctions = []; // Clear all summary fields summaryFields.forEach(summaryField => { updateSummaryElement(summaryField.element, ''); }); // Reset summary fields array summaryFields = []; initialized = false; logVerbose('Summary reset complete'); } //# sourceMappingURL=summary.js.map