1/** 2 * Contact Form 7 確èªç»é¢ã¢ã¼ãã« 3 * 4 * éä¿¡åã«ç¢ºèªã¢ã¼ãã«ã表示ãã 5 */ 6 7class ContactFormConfirm { 8 /** 9 * @param {HTMLFormElement} form - 対象ã®CF7ãã©ã¼ã è¦ç´ 10 */ 11 constructor(form) { 12 this.form = form; 13 this.modal = null; 14 this.isConfirming = false; 15 this.formId = null; 16 this.settings = {}; 17 this.submitButton = null; 18 this.init(); 19 } 20 21 init() { 22 // Contact Form 7ãåæåããã¦ãããç¢ºèª 23 if (!this.form.wpcf7) { 24 // ã¾ã åæåããã¦ããªãå ´åã¯å°ãå¾ ã¤ 25 setTimeout(() => this.init(), 100); 26 return; 27 } 28 29 // ãã©ã¼ã IDãåå¾ 30 this.formId = this.form.wpcf7.id; 31 32 // è¨å®ãèªã¿è¾¼ã 33 this.loadSettings(); 34 35 // ãã®ãã©ã¼ã ã§ç¢ºèªã¢ã¼ãã«ãç¡å¹åããã¦ããå ´åã¯ä½ãããªã 36 if (!this.settings.enabled) { 37 return; 38 } 39 40 this.createModal(); 41 this.attachEventListeners(); 42 this.attachCF7EventListeners(); 43 } 44 45 /** 46 * è¨å®ãèªã¿è¾¼ã 47 */ 48 loadSettings() { 49 const defaultSettings = window.cf7ConfirmDefaultSettings || { 50 enabled: false, 51 modal_title: 'å ¥åå 容ã®ç¢ºèª', 52 back_button_text: 'æ»ã', 53 submit_button_text: 'éä¿¡ãã', 54 primary_color: '#0d6efd', 55 empty_text: 'ï¼æªå ¥åï¼', 56 show_empty_fields: false 57 }; 58 59 const formSettings = window.cf7ConfirmFormSettings || {}; 60 const currentFormSettings = formSettings[this.formId] || {}; 61 62 // è¨å®ããã¼ã¸ï¼ãã©ã¼ã è¨å®ãåªå ã空ã®å ´åã¯ããã©ã«ãå¤ã使ç¨ï¼ 63 this.settings = { 64 enabled: currentFormSettings.enabled !== undefined ? currentFormSettings.enabled : defaultSettings.enabled, 65 modal_title: currentFormSettings.modal_title || defaultSettings.modal_title, 66 back_button_text: currentFormSettings.back_button_text || defaultSettings.back_button_text, 67 submit_button_text: currentFormSettings.submit_button_text || defaultSettings.submit_button_text, 68 primary_color: currentFormSettings.primary_color || defaultSettings.primary_color, 69 empty_text: currentFormSettings.empty_text || defaultSettings.empty_text, 70 show_empty_fields: currentFormSettings.show_empty_fields !== undefined ? currentFormSettings.show_empty_fields : defaultSettings.show_empty_fields 71 }; 72 } 73 74 /** 75 * 確èªã¢ã¼ãã«ã®HTMLã使 76 * 77 * åä¸ãã¼ã¸ã«è¤æ°ã®CF7ãã©ã¼ã ãåå¨ããå ´åã«ãããããç¬ç«ããã¢ã¼ãã«ã 78 * æã¦ããããIDã¯ä½¿ç¨ããã¯ã©ã¹ãã¼ã¹ã§è¦ç´ ã使ããåç §ãç´æ¥ä¿æãã¾ãã 79 */ 80 createModal() { 81 const modalHTML = ` 82 <div class="cf7-confirm-modal"> 83 <div class="cf7-confirm-modal__overlay"></div> 84 <div class="cf7-confirm-modal__content"> 85 <div class="cf7-confirm-modal__header"> 86 <h2 class="cf7-confirm-modal__title">${this.escapeHtml(this.settings.modal_title)}</h2> 87 <button type="button" class="cf7-confirm-modal__close" aria-label="éãã"> 88 <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> 89 <path d="M18 6L6 18M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 90 </svg> 91 </button> 92 </div> 93 <div class="cf7-confirm-modal__body"> 94 <div class="cf7-confirm-modal__data"></div> 95 </div> 96 <div class="cf7-confirm-modal__footer"> 97 <button type="button" class="cf7-confirm-modal__button cf7-confirm-modal__button--back">${this.escapeHtml(this.settings.back_button_text)}</button> 98 <button type="button" class="cf7-confirm-modal__button cf7-confirm-modal__button--submit">${this.escapeHtml(this.settings.submit_button_text)}</button> 99 </div> 100 </div> 101 </div> 102 `; 103 104 const template = document.createElement('template'); 105 template.innerHTML = modalHTML.trim(); 106 this.modal = template.content.firstElementChild; 107 document.body.appendChild(this.modal); 108 109 // ãã©ã¤ããªã«ã©ã¼ãCSS夿°ã¨ãã¦è¨å® 110 this.modal.style.setProperty('--cf7-confirm-modal-primary-color', this.settings.primary_color); 111 } 112 113 /** 114 * ã¤ãã³ããªã¹ãã¼ãè¨å® 115 */ 116 attachEventListeners() { 117 // ãã©ã¼ã ã®submitã¤ãã³ãããªãã¹ã³ 118 this.form.addEventListener('submit', (e) => { 119 if (!this.isConfirming) { 120 // 確èªåã®éä¿¡ã¯ä¸æ 121 e.preventDefault(); 122 e.stopPropagation(); 123 e.stopImmediatePropagation(); 124 125 // CF7å¿ é ãã£ã¼ã«ãã®ããªãã¼ã·ã§ã³ 126 if (!this.validateRequiredFields()) { 127 // ããªãã¼ã·ã§ã³ã¨ã©ã¼ã®å ´åã¯CF7ã«å¦çãå§ãã 128 this.isConfirming = true; 129 wpcf7.submit(this.form); 130 setTimeout(() => { this.isConfirming = false; }, 2000); 131 return false;
132 } 133 134 // ããªãã¼ã·ã§ã³æåæã¯ã¢ã¼ãã«ã表示 135 this.displayConfirmData(); 136 this.openModal(); 137 138 return false; 139 } 140 }, true); 141 142 // ã¢ã¼ãã«ãéãã 143 const closeBtn = this.modal.querySelector('.cf7-confirm-modal__close'); 144 const backBtn = this.modal.querySelector('.cf7-confirm-modal__button--back'); 145 const overlay = this.modal.querySelector('.cf7-confirm-modal__overlay'); 146 147 closeBtn.addEventListener('click', () => this.closeModal()); 148 backBtn.addEventListener('click', () => this.closeModal()); 149 overlay.addEventListener('click', () => this.closeModal()); 150 151 // 確èªã¢ã¼ãã«ããéä¿¡ 152 const submitBtn = this.modal.querySelector('.cf7-confirm-modal__button--submit'); 153 submitBtn.addEventListener('click', () => this.confirmSubmit()); 154 155 // ESCãã¼ã§ã¢ã¼ãã«ãéãã 156 document.addEventListener('keydown', (e) => { 157 if (e.key === 'Escape' && this.modal.classList.contains('is-open')) { 158 this.closeModal(); 159 } 160 }); 161 162 // éä¿¡ãã¿ã³ã®éæ´»æ§å¶å¾¡ 163 this.submitButton = this.form.querySelector('[type="submit"]'); 164 if (this.submitButton) { 165 this.updateSubmitButtonState(); 166 this.form.addEventListener('input', () => this.updateSubmitButtonState()); 167 this.form.addEventListener('change', () => this.updateSubmitButtonState()); 168 169 // CF7 Conditional Fieldsã®ã°ã«ã¼ãè¡¨ç¤ºåæ¿ãç£è¦ 170 this.observeConditionalGroups(); 171 } 172 } 173 174 /** 175 * CF7 Conditional Fieldsã®ã°ã«ã¼ãè¡¨ç¤ºåæ¿ãç£è¦ 176 * wpcf7cf-hiddenã¯ã©ã¹ã®è¿½å ã»åé¤ãæ¤ç¥ãã¦éä¿¡ãã¿ã³ã®ç¶æ ãæ´æ° 177 */ 178 observeConditionalGroups() { 179 const observer = new MutationObserver(() => this.updateSubmitButtonState()); 180 observer.observe(this.form, { subtree: true, attributes: true, attributeFilter: ['class'] }); 181 } 182 183 /** 184 * éä¿¡ãã¿ã³ã®æ´»æ§/éæ´»æ§ãæ´æ° 185 */ 186 updateSubmitButtonState() { 187 const isValid = this.validateRequiredFields(); 188 this.submitButton.disabled = !isValid; 189 } 190 191 /** 192 * ãã©ã¼ã ãã¼ã¿ã確èªã¢ã¼ãã«ã«è¡¨ç¤ºãã 193 * 194 * ãã®ã¡ã½ããã¯ãContact Form 7ãã©ã¼ã ã®å ¥åå¤ã 195 * 確èªã¢ã¼ãã«ã®ãã¼ãã«å½¢å¼ã§è¡¨ç¤ºãã¾ãã 196 * 197 * @returns {void} 198 * 199 * @description 200 * - ãã©ã¼ã å ã®ãã¹ã¦ã®å ¥åãã£ã¼ã«ããå¦çãã¾ã 201 * - ãã§ãã¯ããã¯ã¹ãã©ã¸ãªãã¿ã³ãã»ã¬ã¯ãããã¯ã¹ãããã¹ãã¨ãªã¢ãé©åã«å¦çãã¾ã 202 * - 空ã®ãã£ã¼ã«ãã¯è¨å®ã«å¾ã£ã¦è¡¨ç¤º/éè¡¨ç¤ºãæ±ºå®ãã¾ã 203 * - åãã£ã¼ã«ãã®ã©ãã«ã¯ getFieldLabel ã¡ã½ããã§åå¾ããã¾ãï¼ã¨ã¹ã±ã¼ãæ¸ã¿HTMLï¼ 204 * - å ¥åå¤ã¯ HTML ã¨ã¹ã±ã¼ããã¦ã»ãã¥ãªãã£ã確ä¿ãã¾ã 205 * - ãã¼ãã«å½¢å¼ã§ãã¼ã¿ã表示ãããã¶ã¤ã³ç¨ã®CSSã¯ã©ã¹ãé©åã«é©ç¨ãã¾ã 206 * 207 * @example 208 * // 確èªã¢ã¼ãã«ã®ãã¼ã¿ãæ´æ°ããå ´å 209 * this.displayConfirmData(); 210 */ 211 displayConfirmData() { 212 const dataContainer = this.modal.querySelector('.cf7-confirm-modal__data'); 213 const formData = new FormData(this.form); 214 let html = '<table class="cf7-confirm-table">'; 215 216 // ãã©ã¼ã ã®åãã£ã¼ã«ããåå¾ 217 const fields = this.form.querySelectorAll('input, select, textarea'); 218 219 fields.forEach((field) => { 220 // é表示ãã£ã¼ã«ãããã¿ã³ãCF7 Conditional Fieldsã§é表示ã®ã°ã«ã¼ãå ã®ãã£ã¼ã«ãã¯ã¹ããã 221 if ( 222 field.type === 'hidden' || 223 field.type === 'submit' || 224 field.name.startsWith('_wpcf7') || 225 !field.name || 226 this.isFieldInHiddenGroup(field) 227 ) { 228 return; 229 } 230 231 // getFieldLabel() ã¯ã¨ã¹ã±ã¼ãæ¸ã¿ã®HTMLæååãè¿ãï¼data-label-suffix ãå«ãï¼ 232 const labelHtml = this.getFieldLabel(field); 233 let value = ''; 234 235 // ãã§ãã¯ããã¯ã¹ 236 if (field.type === 'checkbox') { 237 // acceptanceç³»ã®ãã§ãã¯ããã¯ã¹ã¯è¡¨ç¤ºããªã 238 if (field.closest('.wpcf7-acceptance')) { 239 return; 240 } 241 value = field.checked ? 'ãã§ãã¯æ¸ã¿' : ''; 242 } 243 // ã©ã¸ãªãã¿ã³ 244 else if (field.type === 'radio') { 245 if (field.checked) { 246 value = field.nextElementSibling ? field.nextElementSibling.textContent : field.value; 247 } else { 248 return; // 鏿ããã¦ããªãã©ã¸ãªãã¿ã³ã¯ã¹ããã 249 } 250 } 251 // ã»ã¬ã¯ãããã¯ã¹ 252 else if (field.tagName === 'SELECT') { 253 const selectedOption = field.options[field.selectedIndex]; 254 if (selectedOption) { 255 value = selectedOption.value; // ã¾ãvalueãåå¾ 256 // valueã空ã®å ´åã¯ã¹ããã 257 if (!value || value === '') { 258 return; 259 } 260 // 表示ç¨ã«textãä½¿ç¨ 261 value = selectedOption.text; 262 } 263 } 264 // ããã¹ãã¨ãªã¢ã»ããã¹ãããã¯ã¹ 265 else { 266 value = field.value; 267 } 268 269 // 空ã®å¤ã®å¦ç 270 if (!value || value.trim() === '') { 271 // ãã©ã¼ã ãã¨ã®è¨å®ã«åºã¥ãã¦ç©ºã®å¤ã表示ãããã©ããæ±ºå®
272 if (!this.settings.show_empty_fields) { 273 return; // 空ã®å¤ã¯è¡¨ç¤ºããªã 274 } 275 276 // 空ã®å¤ã表示ããå ´åã®ããã¹ãï¼ãã©ã¼ã ãã¨ã®è¨å®ã使ç¨ï¼ 277 value = this.settings.empty_text; 278 } 279 280 // ããã¹ãã¨ãªã¢ã®å ´åã¯æ¹è¡ãä¿æ 281 const isTextarea = field.tagName === 'TEXTAREA'; 282 const displayValue = this.escapeHtml(value); 283 284 html += ` 285 <tr> 286 <th>${labelHtml}</th> 287 <td${isTextarea ? ' class="cf7-confirm-textarea"' : ''}>${displayValue}</td> 288 </tr> 289 `; 290 }); 291 292 html += '</table>'; 293 dataContainer.innerHTML = html; 294 } 295 296 /** 297 * ãã£ã¼ã«ãã®ã©ãã«ï¼HTMLæååï¼ãåå¾ 298 * 299 * findLabelText() ã§ãã¼ã¹ã®ã©ãã«ããã¹ããåå¾ããå¾ã 300 * HTMLã¨ã¹ã±ã¼ããè¡ããdata-label-suffixï¼HTMLå¯ï¼ãæ«å°¾ã«çµåãã¦è¿ãã¾ãã 301 * 302 * @param {HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} field - ã©ãã«ãåå¾ãããã©ã¼ã ãã£ã¼ã«ã 303 * @returns {string} HTMLã¨ãã¦å®å ¨ã«æ¿å ¥ã§ããã©ãã«æåå 304 * 305 * @description 306 * - ãã¼ã¹ã¨ãªãã©ãã«ããã¹ãã¯ã¨ã¹ã±ã¼ãããããããXSSã鲿¢ã§ãã¾ã 307 * - data-label-suffix ã®å¤ã¯HTMLã¨ãã¦ãã®ã¾ã¾çµåãããããã`<span>`çã§è£ 飾å¯è½ã§ã 308 * - data-label-suffix ã¯ä¿¡é ¼ã§ãã管çè ã®ã¿ãè¨å®ããåæã§ã 309 * 310 * @example 311 * // ãã£ã¼ã«ãã®ã©ãã«ãåå¾ï¼HTMLæååãè¿ãï¼ 312 * const labelHtml = this.getFieldLabel(field); 313 */ 314 getFieldLabel(field) { 315 const baseText = this.findLabelText(field); 316 const escapedBase = this.escapeHtml(baseText); 317 318 // data-label-suffixï¼ç¥å è¦ç´ ã®å±æ§ï¼ãããã°æ«å°¾ã«HTMLã¨ãã¦çµå 319 const suffixAncestor = field.closest('[data-label-suffix]'); 320 const suffix = suffixAncestor ? (suffixAncestor.getAttribute('data-label-suffix') || '') : ''; 321 322 return escapedBase + suffix; 323 } 324 325 /** 326 * ãã£ã¼ã«ãã«ç´ã¥ãã©ãã«ã®ããã¹ãï¼ãã¬ã¼ã³ããã¹ãï¼ãåå¾ 327 * 328 * ãã©ã¼ã ã®æ§é ã«å¿ãã¦è¤æ°ã®æ¹æ³ã§ã©ãã«ããã¹ããæ¤ç´¢ãã 329 * åªå é ä½ã«åºã¥ãã¦æåã«è¦ã¤ãã£ãããã¹ããè¿ãã¾ãã 330 * 331 * @param {HTMLInputElement|HTMLSelectElement|HTMLTextAreaElement} field - ã©ãã«ãåå¾ãããã©ã¼ã ãã£ã¼ã«ã 332 * @returns {string} ãã£ã¼ã«ãã«é¢é£ä»ããããã©ãã«ããã¹ãï¼æªã¨ã¹ã±ã¼ãã®ãã¬ã¼ã³ããã¹ãï¼ 333 * 334 * @description 335 * åªå é ä½: 336 * - 0. ç¥å è¦ç´ ã® data-label 屿§ï¼æåªå ï¼ 337 * - 1. for屿§ã§é¢é£ä»ããããlabelã¿ã° 338 * - 2. 親è¦ç´ å ã®labelã¿ã°ï¼æ°ããæ§é ï¼ 339 * - 3. 親ã®labelè¦ç´ ï¼å¤ãæ§é ï¼ 340 * - 4. ç´åã®labelã¿ã° 341 * - 5. wpcf7-form-control-wrapã®ç´åè¦ç´ 342 * - 6. ãã¬ã¼ã¹ãã«ãã¼ 343 * - 7. name屿§ï¼æçµææ®µï¼ 344 */ 345 findLabelText(field) { 346 // 0. ç¥å è¦ç´ ã® data-label 屿§ããåå¾ï¼æåªå ï¼ 347 const ancestor = field.closest('[data-label]'); 348 if (ancestor) { 349 return ancestor.getAttribute('data-label') || ''; 350 } 351 352 // 1. for屿§ã§é¢é£ä»ããããlabelã¿ã°ããåå¾ 353 const labelElement = this.form.querySelector(`label[for="${field.id}"]`); 354 if (labelElement) { 355 const clone = labelElement.cloneNode(true); 356 // ä¸è¦ãªè¦ç´ ãåé¤ 357 clone.querySelectorAll('input, select, textarea, span.required, .wpcf7-form-control-wrap, [data-label-required]').forEach(el => el.remove()); 358 let labelText = clone.textContent.trim(); 359 if (labelText) { 360 return labelText; 361 } 362 } 363 364 // 2. 親ã®divã¾ãã¯pã¿ã°å ã®labelããåå¾ï¼æ°ããæ§é ã«å¯¾å¿ï¼ 365 const parentContainer = field.closest('div, p'); 366 if (parentContainer) { 367 const containerLabel = parentContainer.querySelector('label'); 368 if (containerLabel) { 369 // labelã®ããã¹ãã®ã¿ãåå¾ï¼åè¦ç´ ã®ããã¹ãã¯é¤ãï¼ 370 const clone = containerLabel.cloneNode(true); 371 // ä¸è¦ãªè¦ç´ ãåé¤ 372 clone.querySelectorAll('input, select, textarea, span.required, .wpcf7-form-control-wrap, [data-label-required]').forEach(el => el.remove()); 373 let labelText = clone.textContent.trim(); 374 if (labelText) { 375 return labelText; 376 } 377 } 378 } 379 380 // 3. 親ã®labelããåå¾ï¼å¤ãæ§é ã®å ´åï¼ 381 const parentLabel = field.closest('label'); 382 if (parentLabel) { 383 const clone = parentLabel.cloneNode(true); 384 clone.querySelectorAll('input, select, textarea, span.required, .wpcf7-form-control-wrap, [data-label-required]').forEach(el => el.remove()); 385 let labelText = clone.textContent.trim(); 386 if (labelText) { 387 return labelText; 388 } 389 } 390 391 // 4. ç´åã®labelã¿ã°ããåå¾ï¼è¦ªè¦ç´ ããªãå ´åï¼ 392 let previousElement = field.previousElementSibling; 393 while (previousElement) { 394 if (previousElement.tagName === 'LABEL') { 395 const clone = previousElement.cloneNode(true); 396 clone.querySelectorAll('input, select, textarea, span.required, .wpcf7-form-control-wrap, [data-label-required]').forEach(el => el.remove()); 397 let labelText = clone.textContent.trim(); 398 if (labelText) { 399 return labelText; 400 } 401 } 402 // CF7ãæ¿å ¥ãã<br>ã¿ã°ãªã©ãã¹ããã 403 if (previousElement.tagName === 'BR' || previousElement.nodeType === Node.TEXT_NODE) { 404 previousElement = previousElement.previousElementSibling; 405 } else { 406 break; 407 } 408 } 409 410 // 5. wpcf7-form-control-wrapã®ç´åã®labelãåå¾ 411 const wrapper = field.closest('.wpcf7-form-control-wrap'); 412 if (wrapper) { 413 let prevElement = wrapper.previousElementSibling; 414 while (prevElement) { 415 if (prevElement.tagName === 'LABEL') { 416 const clone = prevElement.cloneNode(true); 417 clone.querySelectorAll('input, select, textarea, span.required, .wpcf7-form-control-wrap, [data-label-required]').forEach(el => el.remove()); 418 let labelText = clone.textContent.trim(); 419 if (labelText) { 420 return labelText; 421 } 422 } 423 if (prevElement.tagName === 'BR' || prevElement.nodeType === Node.TEXT_NODE) { 424 prevElement = prevElement.previousElementSibling; 425 } else { 426 break; 427 } 428 } 429 } 430 431 // 6. ãã¬ã¼ã¹ãã«ãã¼ããåå¾ 432 if (field.placeholder) { 433 return field.placeholder; 434 } 435 436 // 7. name屿§ããåå¾ï¼æçµææ®µï¼ 437 return field.name || ''; 438 } 439 440 /** 441 * ãã£ã¼ã«ããCF7 Conditional Fieldsã§é表示ã®ã°ã«ã¼ãå ã«ãããå¤å® 442 * 443 * @param {HTMLElement} field - å¤å®ãããã©ã¼ã ãã£ã¼ã«ã 444 * @returns {boolean} é表示ã°ã«ã¼ãå ãªãtrue 445 */ 446 isFieldInHiddenGroup(field) { 447 return field.closest('.wpcf7cf-hidden') !== null; 448 } 449 450 /** 451 * HTMLã¨ã¹ã±ã¼ã 452 * 453 * ãã®ã¡ã½ããã¯ãããã¹ããHTMLã¨ã¹ã±ã¼ãã㦠454 * XSSï¼ã¯ãã¹ãµã¤ãã¹ã¯ãªããã£ã³ã°ï¼æ»æããä¿è·ãã¾ãã 455 * 456 * @param {string} text - ã¨ã¹ã±ã¼ãããããã¹ã 457 * @returns {string} ã¨ã¹ã±ã¼ããããHTMLæåå 458 * 459 * @description 460 * - ããã¹ããdivè¦ç´ ã«è¨å®ãã¦ããinnerHTMLãåå¾ãããã¨ã§ã 461 * ã¯ãªãã£ã«ã«ãªHTMLã¿ã°ãã¨ã¹ã±ã¼ããã¾ã 462 * - ããã«ãããã¦ã¼ã¶ã¼å ¥åãã¼ã¿ãHTMLã¨ãã¦å®è¡ãããã®ãé²ãã¾ã 463 * 464 * @example 465 * // XSSä¿è·ã®ããã®ã¨ã¹ã±ã¼ã 466 * const escaped = this.escapeHtml('<script>alert("XSS")</script>'); 467 * // æ»ãå¤: <script>alert("XSS")</script> 468 */ 469 escapeHtml(text) { 470 const div = document.createElement('div'); 471 div.textContent = text; 472 return div.innerHTML; 473 } 474 475 /** 476 * CF7å¿ é ãã£ã¼ã«ãã®ããªãã¼ã·ã§ã³ 477 * 478 * @returns {boolean} ããªãã¼ã·ã§ã³æåãªãtrue 479 */ 480 validateRequiredFields() { 481 // CF7å¿ é ãã£ã¼ã«ãï¼wpcf7-validates-as-requiredï¼ã®ç©ºãã§ã㯠482 // CF7 Conditional Fieldsã§é表示ã®ã°ã«ã¼ãå ã®ãã£ã¼ã«ãã¯ã¹ããã 483 const requiredFields = this.form.querySelectorAll('.wpcf7-validates-as-required'); 484 for (const field of requiredFields) { 485 if (this.isFieldInHiddenGroup(field)) continue; 486 if (field.type === 'checkbox' || field.type === 'radio') { 487 const name = field.name; 488 const checked = this.form.querySelector(`input[name="${name}"]:checked`); 489 if (!checked) return false;
490 } else { 491 if (!field.value || field.value.trim() === '') return false; 492 } 493 } 494 495 // CF7 acceptanceãã£ã¼ã«ãï¼æªãã§ãã¯ã®å¿ é acceptanceï¼ 496 const uncheckedAcceptance = this.form.querySelectorAll('.wpcf7-acceptance:not(.optional) input[type="checkbox"]:not(:checked)'); 497 if (uncheckedAcceptance.length > 0) return false; 498 499 return true; 500 } 501 502 /** 503 * ã¢ã¼ãã«ãéã 504 */ 505 openModal() { 506 this.modal.classList.add('is-open'); 507 document.body.style.overflow = 'hidden'; 508 } 509 510 /** 511 * ã¢ã¼ãã«ãéãã 512 */ 513 closeModal() { 514 this.modal.classList.remove('is-open'); 515 document.body.style.overflow = ''; 516 } 517 518 /** 519 * 確èªå¾ã®éä¿¡ 520 */ 521 confirmSubmit() { 522 this.isConfirming = true; 523 524 // ã¢ã¼ãã«ãéãã 525 this.closeModal(); 526 527 // Contact Form 7ã®éä¿¡ãå®è¡ 528 if (typeof wpcf7 !== 'undefined' && this.form.wpcf7) { 529 wpcf7.submit(this.form); 530 } 531 532 // ãã©ã°ããªã»ããï¼éä¿¡å¾ï¼ 533 setTimeout(() => { 534 this.isConfirming = false; 535 }, 2000); 536 } 537 538 /** 539 * Contact Form 7ã®ã¤ãã³ããªã¹ãã¼ãè¨å® 540 * 541 * CF7ã®ã¤ãã³ã㯠document ã«çºç«ããåä¸ãã¼ã¸ã®è¤æ°ãã©ã¼ã ã§å ±æãããããã 542 * event.detail.contactFormId ã§èªãã©ã¼ã å®ã¦ã®ã¤ãã³ãã ããå¦çããã 543 */ 544 attachCF7EventListeners() { 545 const isOwnEvent = (e) => e && e.detail && e.detail.contactFormId === this.formId; 546 547 // éä¿¡æåã¤ãã³ã 548 document.addEventListener('wpcf7mailsent', (e) => { 549 if (!isOwnEvent(e)) return; 550 this.closeModal(); 551 this.isConfirming = false; 552 }); 553 554 // ããªãã¼ã·ã§ã³ã¨ã©ã¼ã¤ãã³ã 555 document.addEventListener('wpcf7invalid', (e) => { 556 if (!isOwnEvent(e)) return; 557 this.closeModal(); 558 this.isConfirming = false; 559 }); 560 561 // ã¹ãã å¤å®ã¤ãã³ã 562 document.addEventListener('wpcf7spam', (e) => { 563 if (!isOwnEvent(e)) return; 564 this.closeModal(); 565 this.isConfirming = false; 566 }); 567 568 // é信失æã¤ãã³ã 569 document.addEventListener('wpcf7mailfailed', (e) => { 570 if (!isOwnEvent(e)) return; 571 this.closeModal(); 572 this.isConfirming = false; 573 }); 574 575 // 䏿ã¤ãã³ã 576 document.addEventListener('wpcf7aborted', (e) => { 577 if (!isOwnEvent(e)) return; 578 this.closeModal(); 579 this.isConfirming = false; 580 }); 581 } 582} 583 584// åæå: ãã¼ã¸å ã®ãã¹ã¦ã®CF7ãã©ã¼ã ã«å¯¾ãã¦ã¤ã³ã¹ã¿ã³ã¹ãçæ 585document.addEventListener('DOMContentLoaded', () => { 586 const forms = document.querySelectorAll('.wpcf7-form'); 587 forms.forEach((form) => new ContactFormConfirm(form)); 588});
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.