1/** 2 * Request Swatch Modal: open/close, form submit, "more fields below" indicator. 3 * Wrapper uses data-swatch-modal-id; config via requestSwatchModal (ajaxUrl, submitAction, toast_duration_ms). 4 */ 5(function () { 6 'use strict'; 7 8 var config = typeof requestSwatchModal !== 'undefined' ? requestSwatchModal : {}; 9 var toast_duration_ms = config.toast_duration_ms || 3000; 10 11 function showToast(message, type) { 12 if (typeof GlobalScripts !== 'undefined' && GlobalScripts.showPopUp) { 13 GlobalScripts.showPopUp(message, type || 'success', toast_duration_ms); 14 } 15 } 16 17 function parseJsonAttr(element, attribute_name, fallback_value) { 18 try { 19 var raw_attribute_value = element.getAttribute(attribute_name); 20 return raw_attribute_value ? JSON.parse(raw_attribute_value) : (fallback_value || {}); 21 } catch (parse_error) { 22 return fallback_value || {}; 23 } 24 } 25 26 function resolveProductDetailsId(form_element) { 27 var product_id = ''; 28 if (typeof window !== 'undefined' && window.__productDetailsData) { 29 product_id = window.__productDetailsData.id || window.__productDetailsData.product_id || ''; 30 } 31 if (!product_id && typeof product_details_data !== 'undefined' && product_details_data) { 32 product_id = product_details_data.id || product_details_data.product_id || ''; 33 } 34 if (!product_id && form_element) { 35 product_id = form_element.getAttribute('data-product-details') || ''; 36 } 37 product_id = product_id == null ? '' : String(product_id).trim(); 38 return product_id; 39 } 40 41 function getAdditionalDataFromForm(form_element) { 42 var additional_data = {}; 43 try { 44 var raw = form_element.getAttribute('data-additional-data'); 45 if (raw) { 46 additional_data = JSON.parse(raw); 47 } 48 } catch (e) {} 49 if (typeof additional_data !== 'object' || additional_data === null) { 50 additional_data = {}; 51 } 52 var product_id = resolveProductDetailsId(form_element); 53 if (product_id) { 54 additional_data.product_details = product_id; 55 } 56 return additional_data; 57 } 58 59 function getFieldType(form_element, field_id) { 60 if (!form_element) return null; 61 var wrapper = form_element.querySelector('.form-builder-with-rule[data-name="' + field_id + '"]'); 62 if (!wrapper) return null; 63 var attr = parseJsonAttr(wrapper, 'data-attribute', {}); 64 return (attr && attr.type) ? attr.type : null; 65 } 66 67 function normalizeValueForPayload(field_id, value, form_element) { 68 var type = getFieldType(form_element, field_id); 69 var arr; 70 if (type === 'select' || type === 'single_select' || type === 'country_single_select' || type === 'state_single_select') { 71 arr = Array.isArray(value) ? value : (value != null && value !== '' ? [value] : []); 72 return { value: arr }; 73 } 74 if (type === 'multi_select' || type === 'multiselect') { 75 if (Array.isArray(value)) arr = value; 76 else if (typeof value === 'string') arr = value ? value.split(',').map(function (s) { return s.trim(); }).filter(Boolean) : []; 77 else arr = []; 78 return { value: arr }; 79 } 80 return { value: value }; 81 } 82 83 function buildRequestSwatchPayload(form_element, form_name) { 84 var additional_data = getAdditionalDataFromForm(form_element); 85 var submitted_values = {}; 86 var form_data = typeof window[form_name] !== 'undefined' && window[form_name].data ? window[form_name].data : {}; 87 for (var field_id in form_data) { 88 if (form_data.hasOwnProperty(field_id)) { 89 submitted_values[field_id] = normalizeValueForPayload(field_id, form_data[field_id], form_element); 90 } 91 } 92 return { additional_data: additional_data, submitted_values: submitted_values }; 93 } 94 if (typeof window !== 'undefined') window.buildRequestSwatchPayload = buildRequestSwatchPayload; 95 96 function clearRequestSwatchForm(formElement, formName) { 97 if (!formElement) return; 98 formName = formName || formElement.getAttribute('data-form-name') || 'request_swatch_modal'; 99 window[formName] = window[formName] || { data: {}, errors: {} }; 100 window[formName].data = {}; 101 window[formName].errors = {}; 102 var wrappers = formElement.querySelectorAll('.form-builder
102-with-rule'); 103 for (var w = 0; w < wrappers.length; w++) { 104 var fieldId = wrappers[w].getAttribute('data-name'); 105 if (!fieldId) continue; 106 var attr = parseJsonAttr(wrappers[w], 'data-attribute', {}); 107 var type = (attr && attr.type) ? attr.type : 'text'; 108 var emptyVal = (type === 'single_file' || type === 'multi_file') ? [] : ''; 109 window[formName].data[fieldId] = emptyVal; 110 try { document.dispatchEvent(new CustomEvent(formName + '_' + fieldId + '_set_value', { detail: { value: emptyVal } })); } catch (e) {} 111 } 112 } 113 if (typeof window !== 'undefined') { 114 window.clearRequestSwatchForm = clearRequestSwatchForm; 115 window.resetRequestSwatchForm = clearRequestSwatchForm; 116 } 117 118 function initRequestSwatchModals() { 119 var button_wrapper_selector = '.request-swatch-button-wrapper[data-swatch-modal-id]'; 120 var button_wrapper_elements = document.querySelectorAll(button_wrapper_selector); 121 122 button_wrapper_elements.forEach(function (button_wrapper_element) { 123 var modal_id = button_wrapper_element.getAttribute('data-swatch-modal-id'); 124 if (!modal_id) return; 125 126 var open_modal_trigger_button = button_wrapper_element.querySelector('.request-swatch-button'); 127 var modal_element = document.getElementById(modal_id); 128 var modal_overlay_element = document.getElementById(modal_id + '-overlay'); 129 130 if (!open_modal_trigger_button || !modal_element || !modal_overlay_element) return; 131 if (button_wrapper_element.dataset.requestSwatchInitialized === '1') return; 132 button_wrapper_element.dataset.requestSwatchInitialized = '1'; 133 134 function updateMoreFieldsBelowIndicator() { 135 var modal_form_element = modal_element.querySelector('.request-swatch-modal-form'); 136 var form_fields_container = modal_form_element ? modal_form_element.querySelector('.request-swatch-modal-form-fields') : null; 137 if (!modal_form_element || !form_fields_container) return; 138 var fields_have_overflow = form_fields_container.scrollHeight > form_fields_container.clientHeight; 139 modal_form_element.classList.toggle('has-scrollable-fields', fields_have_overflow); 140 var scroll_threshold = 8; 141 var at_end = fields_have_overflow && (form_fields_container.scrollTop + form_fields_container.clientHeight >= form_fields_container.scrollHeight - scroll_threshold); 142 modal_form_element.classList.toggle('at-end-of-form', at_end); 143 } 144 145 function openModal() { 146 modal_element.classList.add('open'); 147 modal_overlay_element.classList.add('open'); 148 document.body.classList.add('request-swatch-modal-open'); 149 document.body.style.overflow = 'hidden'; 150 setTimeout(updateMoreFieldsBelowIndicator, 100); 151 } 152 153 function closeModal() { 154 var modal_form = modal_element.querySelector('.request-swatch-modal-form'); 155 var form_name = modal_form ? (modal_form.getAttribute('data-form-name') || 'request_swatch_modal') : ''; 156 if (modal_form && form_name) clearRequestSwatchForm(modal_form, form_name); 157 modal_element.classList.remove('open'); 158 modal_overlay_element.classList.remove('open'); 159 document.body.classList.remove('request-swatch-modal-open'); 160 document.body.style.overflow = ''; 161 } 162 163 open_modal_trigger_button.addEventListener('click', openModal); 164 modal_overlay_element.addEventListener('click', function (overlay_click_event) { 165 if (overlay_click_event.target === modal_overlay_element) closeModal(); 166 }); 167 168 var modal_header_close_button = modal_element.querySelector('.request-swatch-modal-close'); 169 if (modal_header_close_button) modal_header_close_button.addEventListener('click', closeModal); 170 171 var modal_footer_cancel_button = modal_element.querySelector('.request-swatch-modal-cancel'); 172 if (modal_footer_cancel_button) modal_footer_cancel_button.addEventListener('click', closeModal); 173 174 var submit_spinner_svg = '<span class="request-swatch-modal-submit-spinner" aria-hidden="true"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2" stroke-opacity="0.3"/><path d="M12 2a10 10 0 0 1 10 10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg></span>'; 175 176 function setSubmitLoading(loading) { 177 var submit_btn = modal_element.querySelector('.request-swatch-modal-submit');
178 var cancel_btn = modal_element.querySelector('.request-swatch-modal-cancel'); 179 if (submit_btn) { 180 submit_btn.disabled = loading; 181 if (loading) { 182 submit_btn.classList.add('request-swatch-modal-submit-loading'); 183 if (!submit_btn.querySelector('.request-swatch-modal-submit-spinner')) { 184 submit_btn.insertAdjacentHTML('afterbegin', submit_spinner_svg); 185 } 186 } else { 187 submit_btn.classList.remove('request-swatch-modal-submit-loading'); 188 var sp = submit_btn.querySelector('.request-swatch-modal-submit-spinner'); 189 if (sp) sp.remove(); 190 } 191 } 192 if (cancel_btn) cancel_btn.disabled = loading; 193 } 194 195 var modal_form_element = modal_element.querySelector('.request-swatch-modal-form'); 196 if (modal_form_element) { 197 modal_form_element.addEventListener('submit', function (submit_event) { 198 submit_event.preventDefault(); 199 var form_name = modal_form_element.getAttribute('data-form-name') || 'request_swatch_modal'; 200 var form_type = modal_form_element.getAttribute('data-form-type') || 'email_form'; 201 var ajax_submit_url = config.ajaxUrl || null; 202 var ajax_action_name = config.submitAction || 'request_swatch_form_submit'; 203 if (!ajax_submit_url) { 204 showToast('Unable to submit request. Please try again.', 'error'); 205 return; 206 } 207 if (typeof window.submitFormBuilderNew === 'function') { 208 window.submitFormBuilderNew(function (fields) { 209 var additional_data = getAdditionalDataFromForm(modal_form_element); 210 var submitted_values = {}; 211 for (var field_id in fields) { 212 if (fields.hasOwnProperty(field_id)) { 213 submitted_values[field_id] = normalizeValueForPayload(field_id, fields[field_id], modal_form_element); 214 } 215 } 216 var submission_payload = { additional_data: additional_data, submitted_values: submitted_values }; 217 setSubmitLoading(true); 218 var form_data_for_submit = new FormData(); 219 form_data_for_submit.append('action', ajax_action_name); 220 form_data_for_submit.append('form_type', form_type); 221 form_data_for_submit.append('payload', JSON.stringify(submission_payload)); 222 fetch(ajax_submit_url, { method: 'POST', body: form_data_for_submit }) 223 .then(function (res) { 224 return res.json().catch(function () { return null; }).then(function (json) { 225 if (res.ok && json && json.success) { 226 showToast('Swatch request submitted successfully.', 'success'); 227 clearRequestSwatchForm(modal_form_element, form_name); 228 closeModal(); 229 } else { 230 var msg = (json && json.data && json.data.message) ? json.data.message : 'Unable to submit request. Please try again.'; 231 showToast(msg, 'error'); 232 } 233 }); 234 }) 235 .catch(function () { 236 showToast('Something went wrong. Please try again.', 'error'); 237 }) 238 .finally(function () { 239 setSubmitLoading(false); 240 }); 241 }, form_name).then(function (didSubmit) { 242 if (!didSubmit) showToast('Please fill in all required fields.', 'error'); 243 }); 244 } else { 245 var submission_payload = buildRequestSwatchPayload(modal_form_element, form_name); 246 setSubmitLoading(true); 247 var form_data_for_submit = new FormData(); 248 form_data_for_submit.append('action', ajax_action_name); 249 form_data_for_submit.append('form_type', modal_form_element.getAttribute('data-form-type') || 'email_form'); 250 form_data_for_submit.append('payload', JSON.stringify(submission_payload)); 251 fetch(ajax_submit_url, { method: 'POST', body: form_data_for_submit }) 252 .then(function (res) { 253 return res.json().catch(function () { return null; }).then(function (json) { 254 if (res.ok && json && json.success) { 255 showToast('Swatch request submitted successfully.', 'success'); 256 clearRequestSwatchForm(modal_form_element, form_name); 257 closeModal(); 258 } else { 259 var msg = (json && json.data && json.data.message) ? json.data.message : 'Unable to submit request. Please try again.'; 260 showToast(msg, 'error'); 261 } 262 }); 263 }) 264 .catch(function () { 265 showToast('Something went wrong. Please try again.', 'error'); 266 }) 267 .finally(function () { 268 setSubmitLoading(false); 269 }); 270 } 271 }); 272 var form_fields_container = modal_form_element.querySelector('.request-swatch-modal-form-fields'); 273 if (form_fields_container) form_fields_container.addEventListener('scroll', updateMoreFieldsBelowIndicator); 274 } 275 276 updateMoreFieldsBelowIndicator(); 277 document.addEventListener('keydown', function (keyboard_event) { 278 if (keyboard_event.key === 'Escape' && modal_element.classList.contains('open')) closeModal(); 279 }); 280 }); 281 } 282 283 if (document.readyState === 'loading') { 284 document.addEventListener('DOMContentLoaded', initRequestSwatchModals); 285 } else { 286 initRequestSwatchModals(); 287 } 288})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.