1/** 2 * @package BaForms 3 * @author Balbooa http://www.balbooa.com/ 4 * @copyright Copyright @ Balbooa 5 * @license http://www.gnu.org/licenses/gpl.html GNU/GPL 6 */ 7 8var $f = jQuery, 9 formsApp = { 10 loaded: {} 11 }; 12 13!function($){ 14 class formsModal 15 { 16 constructor(element) { 17 this.element = $(element); 18 this.position = element.dataset.position ? element.dataset.position : ''; 19 this.setEvents(); 20 if (element.parentNode != document.body) { 21 $('body').append(this.element); 22 } 23 } 24 25 setEvents() 26 { 27 this.element.on('click keyup', (event) => { 28 FormsAccessibilityHelper.processAction(event, () => { 29 this.hide(event) 30 }) 31 }) 32 this.element.on('keyup', event => { 33 if (event.key == 'Escape') { 34 this.hide(); 35 } 36 }) 37 } 38 39 show() { 40 this.element.css({ 41 'opacity': '', 42 'pointer-events': '' 43 }); 44 this.setScroll(); 45 this.element.addClass('visible-forms-modal'); 46 setTimeout(() => { 47 this.element.addClass('motion-start'); 48 }, 1) 49 FormsAccessibilityHelper.trapFocus(this.element[0], 100); 50 let scroll = this.element[0].offsetWidth - this.element[0].clientWidth; 51 this.element[0].style.setProperty('--forms-modal-scroll-width', scroll + 'px'); 52 } 53 54 setScroll() { 55 document.body.classList.add('forms-modal-position-' + this.position); 56 if (!document.body.classList.contains('forms-modal-opened')) { 57 let scroll = window.innerWidth - document.documentElement.clientWidth; 58 document.body.classList.add('forms-modal-opened'); 59 document.body.style.setProperty('--forms-body-scroll-width', scroll + 'px'); 60 } 61 } 62 63 hide(event) { 64 if (!event || event.target.dataset.dismiss == 'formsModal') { 65 let $this = this; 66 this.element.removeClass('motion-start') 67 setTimeout(() => { 68 this.element.removeClass('visible-forms-modal'); 69 }, 800) 70 FormsAccessibilityHelper.releaseTrap(this.element[0]) 71 setTimeout(function () { 72 $this.hideScroll(); 73 }, 300); 74 } 75 } 76 77 hideScroll() { 78 document.body.classList.remove('forms-modal-position-' + this.position); 79 if (!document.querySelector('.visible-forms-modal')) { 80 document.body.classList.remove('forms-modal-opened'); 81 document.body.style.removeProperty('--forms-body-scroll-width'); 82 } 83 } 84 } 85 $.fn.formsModal = function(option){ 86 return this.each(function() { 87 let data = $(this).data('formsModal'); 88 if (!data) { 89 $(this).data('formsModal', (data = new formsModal(this))); 90 } 91 if (typeof option == 'string') { 92 data[option](); 93 } else { 94 data.show(); 95 } 96 }); 97 } 98 $.fn.formsModal.Constructor = formsModal; 99}(window.$f); 100 101class FormsAccessibilityHelper 102{ 103 static focusableSelectors = [ 104 'a[href]:not([tabindex="-1"])', 105 'area[href]:not([tabindex="-1"])', 106 'input:not([disabled]):not([tabindex="-1"])', 107 'select:not([disabled]):not([tabindex="-1"])', 108 'textarea:not([disabled]):not([tabindex="-1"])', 109 'button:not([disabled]):not([tabindex="-1"])', 110 'iframe:not([tabindex="-1"])', 111 'object:not([tabindex="-1"])', 112 'embed:not([tabindex="-1"])', 113 '[tabindex]:not([tabindex="-1"])', 114 '[contenteditable]:not([tabindex="-1"])', 115 ]; 116 117 constructor(wrapper, timeout = 0) 118 { 119 this.wrapper = wrapper; 120 this.timeout = timeout; 121 this.handleKeydown = this.handleTrappedKeydown.bind(this); 122 } 123 124 getVisibleFocusableElements() 125 { 126 const elements = Array.from( 127 this.wrapper.querySelectorAll(FormsAccessibilityHelper.focusableSelectors.join(',')) 128 ); 129 130 return elements.filter(element => 131 element.offsetParent !== null && getComputedStyle(element).visibility !== 'hidden' 132 ); 133 } 134 135 trap() 136 { 137 const elements = this.getVisibleFocusableElements(); 138 if (elements.length === 0) return; 139 140 this.focusedElement = document.activeElement; 141 this.focusedElement.blur(); 142 this.wrapper.setAttribute('tabindex', '-1'); 143 this.wrapper.style.outline = 'none'; 144 setTimeout(() => {
145 this.wrapper.focus(); 146 this.wrapper.addEventListener('keydown', this.handleKeydown); 147 }, this.timeout); 148 } 149 150 handleTrappedKeydown(event) 151 { 152 if (event.key !== 'Tab') { 153 return; 154 } 155 const elements = this.getVisibleFocusableElements(); 156 if (elements.length === 0) return; 157 158 const first = elements[0]; 159 const last = elements[elements.length - 1]; 160 if (event.shiftKey && document.activeElement === first) { 161 event.preventDefault(); 162 last.focus(); 163 } else if (!event.shiftKey && document.activeElement === last) { 164 event.preventDefault(); 165 first.focus(); 166 } 167 } 168 169 release() 170 { 171 this.wrapper.removeEventListener('keydown', this.handleKeydown); 172 this.wrapper.removeAttribute('tabindex'); 173 this.wrapper.style.outline = ''; 174 clearTimeout(this.delay); 175 this.delay = setTimeout(() => { 176 this.focusedElement.focus(); 177 }, 300); 178 } 179 180 static trapFocus(wrapper, timeout = 0) 181 { 182 if (!wrapper.accessibility) { 183 wrapper.accessibility = new this(wrapper, timeout); 184 } 185 wrapper.accessibility.trap(); 186 } 187 188 static releaseTrap(wrapper) 189 { 190 if (!wrapper.accessibility) return; 191 setTimeout(() => { 192 wrapper.accessibility.release() 193 }, 100); 194 } 195 196 static isClick(event) 197 { 198 return event.type == "click" || event.type == "touchend" 199 } 200 201 static processAction(event, callback, eventsList) 202 { 203 if (eventsList && eventsList.indexOf(event.type) == -1) return; 204 if (this.isClick(event) || (event.type == "keyup" && event.key == 'Enter')) { 205 callback.call(); 206 } 207 } 208} 209 210formsApp.renderFormsCalendar = function(input){ 211 if (input) { 212 formsApp.calendar.formInput = input; 213 } 214 formsApp.fetch.request(JUri+'index.php?option=com_baforms&task=form.renderFormsCalendar', { 215 start: formsApp.calendar.start, 216 year: formsApp.calendar.year, 217 month: formsApp.calendar.month * 1 + 1 218 }).then(function(text){ 219 let data = JSON.parse(text), 220 disable = formsApp.calendar.disable, 221 input = formsApp.calendar.formInput, 222 div = document.createElement('div'); 223 div.innerHTML = data.body; 224 for (let i = 0; i < disable.days.length; i++) { 225 div.querySelectorAll('.ba-date-cell[data-day-number="'+disable.days[i]+'"]').forEach((cell) => { 226 cell.classList.add('disabled-date'); 227 cell.setAttribute('tabindex', -1); 228 }); 229 } 230 for (let i = 0; i < disable.dates.length; i++) { 231 div.querySelectorAll('.ba-date-cell[data-day-date="'+disable.dates[i]+'"]').forEach((cell) => { 232 cell.classList.add('disabled-date'); 233 cell.setAttribute('tabindex', -1); 234 }) 235 } 236 for (let i = 0; i < disable.range.length; i++) { 237 let minMax = disable.range[i].split(' - '); 238 div.querySelectorAll('.ba-date-cell:not(.disabled-date)').forEach((cell) => { 239 if (cell.dataset.dayDate >= minMax[0] && cell.dataset.dayDate <= minMax[1]) { 240 cell.classList.add('disabled-date'); 241 cell.setAttribute('tabindex', -1); 242 } 243 }); 244 } 245 div.querySelectorAll('.ba-curent-date').forEach(($this) => { 246 let today = formsApp.calendar.querySelector('.ba-forms-today-btn'), 247 action = $this.classList.contains('disabled-date') ? 'add' : 'remove'; 248 today.dataset.date = $this.dataset.date; 249 today.dataset.dayDate = $this.dataset.dayDate; 250 today.classList[action]('disabled-date'); 251 today.setAttribute('tabindex', (action == 'add' ? -1 : 0)); 252 }); 253 if (input.rangeBtn && input.dataset.index == 1) { 254 let date = input.rangeBtn.dataset.value; 255 div.querySelectorAll('.ba-date-cell:not(.disabled-date)').forEach((cell) => { 256 if (cell.dataset.dayDate <= date) { 257 cell.classList.add('disabled-date'); 258 cell.setAttribute('tabindex', -1); 259 } 260 }); 261 } 262 formsApp.calendar.querySelector('.ba-forms-calendar-title').textContent = data.title; 263 formsApp.calendar.querySelector('.ba-forms-calendar-header').innerHTML = data.header; 264 formsApp.calendar.querySelector('.ba-forms-calendar-body').innerHTML = div.innerHTML; 265 if (!formsApp.calendar.classList.contains('visible-forms-calendar')) { 266 formsApp.calendar.classList.add('visible-forms-calendar'); 267 FormsAccessibilityHelper.trapFocus(formsApp.calendar); 268 } 269 }); 270} 271 272formsApp.setFormsCalendarEvents = function(){ 273 let $calendar = $f(formsApp.calendar); 274 $calendar.find('.ba-forms-today-btn').on('click keyup', function(event){ 275 if (this.classList.contains('disabled-date')) return; 276 277 FormsAccessibilityHelper.processAction(event, () => { 278 formsApp.calendar.formInput.value = this.dataset.date; 279 formsApp.calendar.formInput.dataset.value = this.dataset.dayDate; 280 $f(formsApp.calendar.formInput).trigger('input');
281 formsApp.hideCalendar(); 282 }); 283 }); 284 $calendar.find('i[data-action]').on('click keyup', function(event){ 285 FormsAccessibilityHelper.processAction(event, () => { 286 let year = formsApp.calendar.year * 1, 287 month = formsApp.calendar.month * 1; 288 if (this.dataset.action == 'next') { 289 year = (month === 11) ? year + 1 : year; 290 month = (month + 1) % 12; 291 } else if (this.dataset.action == 'prev') { 292 year = (month === 0) ? year - 1 : year; 293 month = (month === 0) ? 11 : month - 1; 294 } else if (this.dataset.action == 'next-year') { 295 year = year + 1; 296 } else if (this.dataset.action == 'prev-year') { 297 year = year - 1; 298 } 299 formsApp.calendar.year = year; 300 formsApp.calendar.month = month; 301 formsApp.renderFormsCalendar(); 302 }); 303 }); 304 $calendar.on('click keyup', '.ba-date-cell', function(event){ 305 FormsAccessibilityHelper.processAction(event, () => { 306 if (!(formsApp.calendar.classList.contains('disable-previous-date') && this.classList.contains('ba-previous-date')) 307 && !this.classList.contains('disabled-date')) { 308 formsApp.calendar.formInput.value = this.dataset.date; 309 formsApp.calendar.formInput.dataset.value = this.dataset.dayDate; 310 $f(formsApp.calendar.formInput).trigger('input'); 311 formsApp.hideCalendar(); 312 } 313 }); 314 }); 315 $calendar.on('keyup', function(event){ 316 if (event.key == 'Escape') { 317 formsApp.hideCalendar(); 318 } 319 }); 320 $calendar.find('.ba-close-calendar').on('click', function(){ 321 formsApp.hideCalendar(); 322 }); 323} 324 325formsApp.hideCalendar = function(){ 326 formsApp.calendar.classList.add('forms-calendar-out'); 327 FormsAccessibilityHelper.releaseTrap(formsApp.calendar); 328 setTimeout(function(){ 329 formsApp.calendar.classList.remove('visible-forms-calendar'); 330 formsApp.calendar.classList.remove('forms-calendar-out'); 331 }, 600); 332} 333 334formsApp.createCalendar = function($this){ 335 formsApp.calendar = document.createElement('div'); 336 formsApp.calendar.className = 'forms-calendar-wrapper'; 337 formsApp.calendar.innerHTML = `<div class="ba-forms-calendar"> 338 <div class="ba-forms-calendar-title-wrapper"> 339 <span class="forms-calendar-btn"> 340 <i class="ba-form-icons ba-icon-chevron-left" tabindex="0" data-action="prev-year"></i> 341 <span class="ba-tooltip ba-bottom ba-hide-element"> 342 ${formsApp._('YEAR')} 343 </span> 344 </span> 345 <span class="forms-calendar-btn"> 346 <i class="ba-form-icons ba-icon-chevron-left" tabindex="0" data-action="prev"></i> 347 <span class="ba-tooltip ba-bottom ba-hide-element"> 348 ${formsApp._('MONTH')} 349 </span> 350 </span> 351 <span class="ba-forms-calendar-title"></span> 352 <span class="forms-calendar-btn"> 353 <i class="ba-form-icons ba-icon-chevron-right" tabindex="0" data-action="next"></i> 354 <span class="ba-tooltip ba-bottom ba-hide-element"> 355 ${formsApp._('MONTH')} 356 </span> 357 </span> 358 <span class="forms-calendar-btn"> 359 <i class="ba-form-icons ba-icon-chevron-right" tabindex="0" data-action="next-year"></i> 360 <span class="ba-tooltip ba-bottom ba-hide-element"> 361 ${formsApp._('YEAR')} 362 </span> 363 </span> 364 </div> 365 <div class="ba-forms-calendar-header"></div> 366 <div class="ba-forms-calendar-body"></div> 367 <div class="ba-forms-calendar-footer"> 368 <span class="ba-forms-today-btn" tabindex="0"> 369 ${formsApp._('TODAY')} 370 </span> 371 </div> 372 </div> 373 <div class="ba-close-calendar"></div>` 374 document.body.appendChild(formsApp.calendar); 375 formsApp.calendar.year = $this.dataset.year; 376 formsApp.calendar.month = $this.dataset.month; 377 formsApp.setFormsCalendarEvents(); 378} 379 380formsApp.hideNotice = function(){ 381 this.notification.classList.remove('notification-in'); 382 this.notification.classList.add('animation-out'); 383} 384 385formsApp.showNotice = function(message, className = ''){ 386 if (!this.notification) { 387 this.notification = document.createElement('div'); 388 this.notification.id = 'ba-forms-notification'; 389 this.notification.innerHTML = '<i class="ba-form-icons ba-icon-close"></i><h4>'+this._('ERROR')+'</h4><p></p>'; 390 this.notification.querySelector('.ba-icon-close').addEventListener('click', function(){ 391 formsApp.hideNotice(); 392 }); 393 document.body.append(this.notification); 394 } 395 this.notification.showCallback = function(){}; 396 if (this.notification.classList.contains('notification-in')) { 397 this.notification.showCallback = function(){ 398 formsApp.notification.showCallback = function(){}; 399 formsApp.addNoticeText(message, className); 400 }; 401 } else { 402 this.addNoticeText(message, className); 403 } 404} 405 406formsApp.addNoticeText = function(message, className){ 407 $f(this.notification).find(' > p').html(message); 408 if (className) { 409 this.notification.classList.add(className); 410 } else { 411 this.notification.classList.remove('ba-alert'); 412 } 413 this.notification.classList.remove('animation-out') 414 this.notification.classList.add('notification-in'); 415 clearTimeout(this.notification.hideDelay); 416 this.notification.hideDelay = setTimeout(function(){ 417 formsApp.hideNotice(); 418 setTimeout(function(){ 419 if (className) { 420 formsApp.notification.classList.remove(className); 421 } 422 formsApp.notification.showCallback(); 423 }, 400); 424 }, 6000); 425} 426 427formsApp.getLocalStorage = function(){ 428 let storage = localStorage.getItem('forms-progress'), 429 date = +new Date(), 430 expire = false;
431 if (!storage) { 432 storage = '{}'; 433 } 434 formsApp.storage = JSON.parse(storage); 435 for (let ind in formsApp.storage) { 436 let page = formsApp.storage[ind]; 437 for (let key in page) { 438 let data = page[key]; 439 if (Math.floor((date - data.date) / (1000 * 60 * 60 * 24)) > 30) { 440 expire = true; 441 delete formsApp.storage[ind][key]; 442 } 443 } 444 } 445 if (expire) { 446 localStorage.setItem('forms-progress', JSON.stringify(formsApp.storage)); 447 } 448} 449 450formsApp.fetch = { 451 getErrorText: function(text){ 452 let div = document.createElement('div'); 453 div.innerHTML = text; 454 if (div.querySelector('title')) { 455 text = div.querySelector('title').textContent; 456 } 457 458 return text; 459 }, 460 request: async function(url, data){ 461 let request = await fetch(url, { 462 headers: { 463 'Content-Type': 'application/x-www-form-urlencoded', 464 }, 465 method: 'POST', 466 cache: 'no-cache', 467 body: this.getFormData(data) 468 }), 469 response = null; 470 if (request.ok) { 471 response = await request.text(); 472 } else { 473 let utf8Decoder = new TextDecoder("utf-8"), 474 reader = request.body.getReader(), 475 textData = await reader.read(), 476 text = utf8Decoder.decode(textData.value); 477 console.info(this.getErrorText(text)); 478 } 479 480 return response; 481 }, 482 getFormData: function(data){ 483 let formData = new URLSearchParams(); 484 formData.append(formsApp.token, '1'); 485 if (data) { 486 for (let ind in data) { 487 if (Array.isArray(data[ind])) { 488 data[ind].forEach(v => { 489 formData.append(`${ind}[]`, v); 490 }) 491 } else if (typeof data[ind] == 'object') { 492 for (let i in data[ind]) { 493 formData.append(`${ind}[${i}]`, data[ind][i]); 494 } 495 } else { 496 formData.append(ind, data[ind]); 497 } 498 } 499 } 500 501 return formData; 502 }, 503 504} 505 506formsApp.countries = { 507 append: function(){ 508 document.querySelectorAll('.ba-form-phone-field .ba-phone-countries-list').forEach(function(ul){ 509 if (!ul.querySelector('li')) { 510 ul.innerHTML = formsApp.countries.html; 511 } 512 }) 513 }, 514 check: function(){ 515 if (this.data) { 516 this.append() 517 } else if (document.querySelector('.ba-form-phone-field') && !this.loading) { 518 this.load(); 519 } 520 }, 521 readCountries: function(){ 522 return new Promise(function(resolve) { 523 fetch(JUri+'index.php?option=com_baforms&task=form.readCountries').then(function(response){ 524 if (response.ok) { 525 response.json().then(function(json){ 526 resolve(json); 527 }); 528 } else { 529 console.info(response) 530 } 531 }); 532 }); 533 }, 534 load: function(){ 535 this.loading = true; 536 fetch(JUri+'components/com_baforms/libraries/countries/countries.json').then(function(response){ 537 if (!response.ok) { 538 return formsApp.countries.readCountries() 539 } else { 540 return response.json(); 541 } 542 }).then(function(json){ 543 formsApp.countries.set(json); 544 }); 545 }, 546 set: function(data){ 547 let html = ''; 548 for (let ind in data) { 549 const prefix = data[ind].prefix; 550 const title = data[ind].title; 551 const placeholder = data[ind].placeholder.replace(/X/g, '_'); 552 html += `<li class="ba-phone-country-item" data-prefix="+${prefix}" tabindex="0" 553 data-flag="${ind}" data-title="${title}" data-placeholder="${placeholder}"> 554 <span class="ba-phone-flag ba-phone-flag-${ind}"></span>
555 <span class="ba-phone-country-title">${title}</span> 556 <span class="ba-phone-country-prefix">+${prefix}</span> 557 </li>`; 558 } 559 this.html = html; 560 this.data = data; 561 this.append(); 562 }, 563 hide: () => { 564 const wrapper = $f('.visible-countries-list').removeClass('visible-countries-list'); 565 const list = wrapper.find('.ba-phone-countries-list-wrapper')[0]; 566 if (!list) return; 567 568 FormsAccessibilityHelper.releaseTrap(list); 569 } 570} 571 572formsApp.createForms = function(){ 573 FormsSignature.boot(); 574 formsApp.refreshToken() 575 formsApp.checkGoogleMaps(); 576 formsApp.checkLanguage(); 577 formsApp.countries.check(); 578 formsApp.getLocalStorage(); 579 CaptchaHelper.loadIfExist(); 580 $f('.com-baforms-wrapper').each(formsApp.createForm) 581 .closest('.ba-form-lightbox-layout').each(formsApp.renderLightbox); 582} 583 584formsApp.renderLightbox = function(){ 585 if (!this.trigger) { 586 this.trigger = JSON.parse(this.dataset.trigger); 587 this.session = JSON.parse(this.dataset.session); 588 $f(this).removeAttr('data-trigger').removeAttr('data-session') 589 } 590 if (!this.session.enable) { 591 formsApp.initLightbox(this); 592 } else if (this.session.enable && this.trigger.type != '') { 593 let flag = true; 594 if (localStorage['formsModal-'+this.dataset.id]) { 595 let date = new Date().getTime(), 596 expires = new Date(localStorage[this.dataset.id]); 597 expires.getTime(); 598 if (date >= expires) { 599 flag = true; 600 localStorage.removeItem(this.dataset.id); 601 } else { 602 flag = false; 603 } 604 } 605 if (flag) { 606 formsApp.initLightbox(this); 607 } 608 } 609} 610 611formsApp.showLightbox = function($this){ 612 if ($this.session.enable) { 613 const expiration = new Date(); 614 expiration.setDate(expiration.getDate()+$this.session.duration); 615 localStorage.setItem('formsModal-'+$this.dataset.id, expiration); 616 } 617 $f($this).formsModal().find('.ba-form-submit-btn').each(function(){ 618 CaptchaHelper.createIfExist(this); 619 }); 620} 621 622formsApp.initLightbox = function($this){ 623 if ($this.trigger.type == 'time-delay') { 624 setTimeout(function(){ 625 formsApp.showLightbox($this); 626 }, $this.trigger.time); 627 } else if ($this.trigger.type == 'scrolling') { 628 formsApp.lightboxScroll($this, $this.trigger.scroll * 1); 629 } else if ($this.trigger.type == 'exit-intent') { 630 $f(document).one('mouseleave', function(){ 631 formsApp.showLightbox($this); 632 }); 633 } else if ($this.trigger.type == 'bottom-of-page') { 634 formsApp.lightboxScroll($this, 100); 635 } 636} 637 638formsApp.lightboxScroll = function($this, scroll){ 639 let top, 640 docHeight, 641 htmlHeight; 642 $f(window).on('scroll.ba-lightbox'+$this.dataset.id+' load.ba-lightbox'+$this.dataset.id, function(){ 643 top = $f(window).scrollTop(); 644 docHeight = document.documentElement.clientHeight 645 htmlHeight = Math.max( 646 document.body.scrollHeight, document.documentElement.scrollHeight, 647 document.body.offsetHeight, document.documentElement.offsetHeight, 648 document.body.clientHeight, document.documentElement.clientHeight 649 ); 650 const x = (docHeight + top) * 100 / htmlHeight; 651 if (x >= scroll || (scroll > 97 && x >= 97)) { 652 $f(window).off('scroll.ba-lightbox'+$this.dataset.id+' load.ba-lightbox'+$this.dataset.id); 653 formsApp.showLightbox($this) 654 } 655 }); 656} 657 658formsApp.checkAlert = function(form){ 659 form.find('.confirm-email-wrapper').find('input').each(function(){ 660 let alert = !this.value.trim(), 661 key = 'THIS_FIELD_REQUIRED'; 662 if (this.value) { 663 alert = !(/@/g.test(this.value) && this.value.match(/@/g).length == 1); 664 key = 'ENTER_VALID_VALUE'; 665 if (!alert) { 666 let email = this.closest('.ba-form-field-item').querySelector('.ba-input-wrapper input').value.trim(); 667 alert = !(email == this.value.trim()); 668 key = 'EMAIL_ADDRESSES_NOT_MATCH'; 669 } 670 } 671 formsApp.toggleAlertTooltip(alert, this, this.closest('.ba-field-container'), key); 672 }); 673 form.find('.ba-form-signature-field').each(function(){ 674 if (this.dataset.required) { 675 let alert = this.instance.isEmpty(), 676 container = this.querySelector('.ba-field-container'); 677 formsApp.toggleAlertTooltip(alert, container, container, 'THIS_FIELD_REQUIRED'); 678 } 679 }) 680 form.find('.confirm-password-wrapper').find('input').each(function(){ 681 let password = this.closest('.ba-form-field-item').querySelector('.ba-input-wrapper input').value.trim(), 682 alert = this.required && !this.value.trim(), 683 key = 'THIS_FIELD_REQUIRED'; 684 if (password) { 685 alert = !(password == this.value.trim()); 686 key = 'PASSWORDS_NOT_MATCH'; 687 } 688 formsApp.toggleAlertTooltip(alert, this, this.closest('.ba-field-container'), key); 689 }); 690 form.find('.ba-form-input-field, .ba-form-address-field').find(' > .ba-input-wrapper').find('input, textarea').each(function(){ 691 let alert = this.required && !this.value.trim(), 692 key = 'THIS_FIELD_REQUIRED'; 693 if (this.formsInputMask) { 694 alert = this.required && this.value == this.formsInputMask; 695 } 696 if (this.value && this.characters && this.characters.key == 'min') { 697 alert = !(this.value.length >= this.characters.length); 698 key = 'ENTER_VALID_VALUE'; 699 } else if (this.value && this.dataset.validation == 'email') { 700 alert = !(/@/g.test(this.value) && this.value.match(/@/g).length == 1); 701 key = 'ENTER_VALID_VALUE'; 702 } else if (this.value && this.dataset.validation == 'numbers') { 703 alert = !(/\d+\.{0,1}\d{0,}/.test(this.value)); 704 key = 'ENTER_VALID_VALUE'; 705 } else if (this.value && this.dataset.validation == 'url') { 706 alert = !(/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i.test(this.value)); 707 key = 'ENTER_VALID_VALUE'; 708 } else if (!alert && this.value && this.formsInputMask) { 709 alert = this.value != this.formsInputMask && this.value.indexOf('_') != -1; 710 key = 'ENTER_VALID_VALUE'; 711 } 712 formsApp.toggleAlertTooltip(alert, this, this.closest('.ba-field-container'), key); 713 }); 714 form.find('.ba-form-phone-field input.ba-phone-number-input').each(function(){ 715 let alert = this.required && this.value == this.formsInputMask, 716 key = 'THIS_FIELD_REQUIRED'; 717 if (!alert && this.value) { 718 alert = this.value != this.formsInputMask && this.value.indexOf('_') != -1; 719 key = 'ENTER_VALID_VALUE'; 720 } 721 formsApp.toggleAlertTooltip(alert, this, this.closest('.ba-field-container'), key); 722 }); 723 form.find('.ba-form-upload-field').find('input[type="file"]').each(function(){ 724 const alert = this.required && this.uploads.count == 0; 725 formsApp.toggleAlertTooltip(alert, this, this.closest('.upload-file-input'), 'THIS_FIELD_REQUIRED'); 726 }); 727 form.find('.ba-form-field-item').find('.ba-form-rating-group-wrapper').each(function(){ 728 if (this.dataset.required) { 729 let alert = false;
730 $f(this).find('input').each(function(){ 731 alert = !this.checked; 732 if (this.checked) { 733 return false; 734 } 735 }) 736 formsApp.toggleAlertTooltip(alert, this, this.closest('.ba-form-rating-group-wrapper'), 'THIS_FIELD_REQUIRED'); 737 } 738 }); 739 form.find('.ba-form-field-item').find('.ba-form-checkbox-group-wrapper').each(function(){ 740 if (this.dataset.required) { 741 let alert = false; 742 $f(this).find('input').each(function(){ 743 alert = !this.checked; 744 if (this.checked) { 745 return false; 746 } 747 }) 748 formsApp.toggleAlertTooltip(alert, this, this.closest('.ba-form-checkbox-group-wrapper'),'THIS_FIELD_REQUIRED'); 749 } 750 }); 751 form.find('.ba-form-dropdown-field, .ba-form-select-multiple-field').find('select').each(function(){ 752 let alert = this.required && !this.value.trim(); 753 formsApp.toggleAlertTooltip(alert, this, this.closest('.ba-field-container'), 'THIS_FIELD_REQUIRED'); 754 }); 755 form.find('.ba-form-acceptance-field').find('.ba-field-container').each(function(){ 756 if (this.dataset.required) { 757 let alert = false; 758 $f(this).find('input').each(function(){ 759 alert = !this.checked; 760 if (this.checked) { 761 return false; 762 } 763 }) 764 formsApp.toggleAlertTooltip(alert, this, this, 'THIS_FIELD_REQUIRED'); 765 } 766 }); 767 form.find('.ba-form-calendar-field input[required]').each(function(){ 768 formsApp.toggleAlertTooltip(!this.value.trim(), this, this.closest('.calendar-field-wrapper'), 'THIS_FIELD_REQUIRED'); 769 }) 770 let tooltip = form.find('.ba-form-field-item .ba-alert-tooltip'); 771 if (tooltip.length) { 772 tooltip[0].closest('.ba-form-field-item').scrollIntoView({ 773 block: 'center' 774 }); 775 return false; 776 } 777} 778 779formsApp.toggleAlertTooltip = function(alert, $this, parent, key){ 780 if (alert && !$this.alertTooltip && !$this.closest('.hidden-condition-field')) { 781 $this.alertTooltip = document.createElement('span'); 782 $this.alertTooltip.className = 'ba-alert-tooltip'; 783 $this.alertTooltip.textContent = formsApp._(key); 784 let str = '.ba-input-wrapper, .confirm-email-wrapper, .confirm-password-wrapper, .forms-recaptcha,'+ 785 ' .calendar-field-wrapper, .ba-forms-authorize-field-wrapper'; 786 parent.closest(str).classList.add('ba-alert'); 787 parent.appendChild($this.alertTooltip); 788 } else if (alert && $this.alertTooltip) { 789 $this.alertTooltip.textContent = formsApp._(key); 790 } else if (!alert && $this.alertTooltip) { 791 formsApp.removeAlertTooltip($this); 792 } 793} 794 795formsApp.removeAlertTooltip = function($this){ 796 if ($this.alertTooltip) { 797 $this.alertTooltip.remove(); 798 $this.alertTooltip = null; 799 $this.closest('.ba-alert').classList.remove('ba-alert'); 800 } 801} 802 803formsApp.checkLanguage = function(){ 804 if (!formsApp.language) { 805 fetch(JUri+'index.php?option=com_baforms&task=form.getFormsLanguage').then(function(response){ 806 return response.json(); 807 }).then(function(json){ 808 formsApp.language = json; 809 }); 810 } 811} 812 813formsApp._ = function(key){ 814 if (formsApp.language && formsApp.language[key]) { 815 return formsApp.language[key]; 816 } 817 818 return key; 819} 820 821class FormsSignature 822{ 823 static loading = false; 824 static loaded = false; 825 static selector = '.ba-form-signature-field'; 826 827 static boot() 828 { 829 if (!document.querySelector(this.selector)) return; 830 831 if (!this.loaded && !this.loading) { 832 this.loadScript(); 833 } else if (this.loaded) { 834 this.make(); 835 } 836 } 837 838 static loadScript() 839 { 840 this.loading = true; 841 const script = document.createElement('script'); 842 script.src = `${JUri}components/com_baforms/assets/js/signature.js`; 843 script.onload = () => { 844 this.loaded = true; 845 this.make(); 846 } 847 document.head.append(script); 848 } 849 850 constructor(element) 851 { 852 this.element = element; 853 this.container = this.element.querySelector('.ba-field-container'); 854 this.clearButton = this.element.querySelector('.ba-clear-signature-canvas'); 855 this.textarea = this.element.querySelector('textarea'); 856 this.$textarea = $f(this.textarea); 857 this.signature = this.create(); 858 this.setEvents(); 859 } 860 861 isEmpty() 862 { 863 return this.signature.isEmpty(); 864 } 865 866 create() 867 { 868 const canvas = this.element.querySelector('canvas'); 869 canvas.width = canvas.offsetWidth; 870 canvas.height = canvas.offsetHeight; 871 872 return new SignaturePad(canvas, { 873 backgroundColor: canvas.dataset.bg, 874 penColor: canvas.dataset.color 875 }); 876 } 877 878 setEvents() 879 { 880 this.signature.addEventListener('beginStroke', this.beginStroke.bind(this)); 881 this.signature.addEventListener('endStroke', this.endStroke.bind(this)); 882 this.clearButton.addEventListener('click', this.clear.bind(this)); 883 } 884 885 beginStroke() 886 { 887 formsApp.removeAlertTooltip(this.container); 888 } 889 890 endStroke() 891 { 892 const str = JSON.stringify({ 893 image: this.signature.toDataURL('image/jpeg') 894 }); 895 this.updateTextarea(str) 896 } 897 898 clear() 899 { 900 this.signature.clear(); 901 this.updateTextarea() 902 } 903 904 updateTextarea(value = '') 905 { 906 this.textarea.value = value; 907 this.$textarea.trigger('input'); 908 } 909 910 static make() 911 { 912 document.querySelectorAll(this.selector).forEach(field => { 913 if (field.instance || field.closest('.ba-hidden-form-page')) { 914 return; 915 } 916 field.instance = new this(field); 917 }); 918 } 919} 920 921formsApp.checkGoogleMaps = function(){
922 if (loadFormsMap.load && !formsApp.googleMaps && !loadFormsMap.loading) { 923 loadFormsMap.loading = true; 924 let script = document.createElement('script'); 925 script.src = JUri+'components/com_baforms/assets/js/mapStyles.js'; 926 script.onload = function(){ 927 formsApp.mapScript = document.createElement('script'); 928 formsApp.mapScript.onload = function(){ 929 formsApp.googleMaps = true; 930 $f('.ba-form-map-field .ba-map-wrapper').each(function(){ 931 formsApp.createGoogleMap(this, this.options); 932 }); 933 $f('.ba-form-address-field input').each(function(){ 934 this.createAutocomplete(); 935 }); 936 } 937 formsApp.mapScript.src = 'https://maps.googleapis.com/maps/api/js?libraries=places&key='+loadFormsMap.api_key; 938 document.head.append(formsApp.mapScript); 939 } 940 document.head.append(script); 941 } 942} 943 944formsApp.createGoogleMap = function(div, obj){ 945 div.map = new google.maps.Map(div, obj.map); 946 div.map.setOptions({styles: mapStyles[obj.styleType]}); 947 if (obj.marker.position) { 948 let object = { 949 position : obj.marker.position, 950 map : div.map 951 } 952 if (obj.marker.icon) { 953 object.icon = JUri+obj.marker.icon; 954 } 955 let marker = new google.maps.Marker(object); 956 if (obj.marker.description) { 957 marker.infoWindow = new google.maps.InfoWindow({ 958 content : obj.marker.description 959 }); 960 if (obj.marker.infobox == 1) { 961 marker.infoWindow.open(div.map, marker); 962 } 963 marker.addListener('click', function(){ 964 this.infoWindow.open(div.map, this); 965 }); 966 } 967 } 968} 969 970formsApp.removeTmpAttachment = function(attachment, input, $this){ 971 if (attachment.dataset.id) { 972 delete input.uploads[attachment.dataset.id]; 973 input.uploads.count--; 974 formsApp.updateFieldsValues($this.fields, input, input.fieldId); 975 formsApp.calculation($this); 976 formsApp.fetch.request(JUri+'index.php?option=com_baforms&task=form.removeTmpAttachment', { 977 id: attachment.dataset.id 978 }).then(() => attachment.remove()); 979 } 980} 981
982formsApp.getAttachmentHTML = function(input, type, name, $this){ 983 let attachment = document.createElement('div'), 984 str = ''; 985 attachment.className = 'ba-form-xhr-attachment'; 986 if (type == 'file') { 987 str += '<i class="ba-form-icons ba-icon-attachment"></i>'; 988 } else { 989 str += '<span class="attachment-intro-image"></span>'; 990 } 991 str += '<span class="forms-attachment-title">'+name; 992 str += '</span><span class="forms-attachment-progress-bar-wrapper"><span class="forms-attachment-progress-bar">'; 993 str += '</span></span><i class="ba-form-icons ba-icon-delete" tabindex="0"></i>'; 994 attachment.innerHTML = str; 995 $f(attachment).find('.ba-icon-delete').on('click keyup', function(event){ 996 FormsAccessibilityHelper.processAction(event, () => { 997 formsApp.removeTmpAttachment(attachment, input, $this); 998 }) 999 }); 1000 1001 return attachment; 1002} 1003 1004formsApp.uploadAttachmentFile = function(files, input, $this){ 1005 if (files.length && 1006 (input.options.count == '' || (input.options.count != '' && input.uploads.count < input.options.count))) { 1007 let file = files.shift(), 1008 type = input.options.images.indexOf(file.ext) == -1 ? 'file' : 'image', 1009 attachment = formsApp.getAttachmentHTML(input, type, file.name, $this), 1010 xhr = new XMLHttpRequest(), 1011 formData = new FormData(); 1012 if (type == 'image') { 1013 let reader = new FileReader(); 1014 reader.onloadend = function() { 1015 attachment.querySelector('.attachment-intro-image').style.backgroundImage = 'url('+reader.result+')'; 1016 } 1017 reader.readAsDataURL(file); 1018 } 1019 1020 const { token } = formsApp; 1021 formData.append(token, "1"); 1022 1023 formData.append('file', file); 1024 formData.append('id', input.options.id); 1025 formData.append('field_id', input.dataset.id); 1026 formData.append('option', 'com_balbooa_forms'); 1027 formData.append('task', 'form.uploadAttachmentFile'); 1028 1029 xhr.upload.onprogress = function(e) { 1030 const bar = attachment.querySelector('.forms-attachment-progress-bar'); 1031 bar.style.width = Math.round(e.loaded / e.total * 100) + "%"; 1032 } 1033 xhr.onload = xhr.onerror = function(){ 1034 try { 1035 const response = JSON.parse(this.responseText); 1036 if (response.id) { 1037 input.uploads[response.id] = response; 1038 attachment.dataset.id = response.id; 1039 input.uploads.count++; 1040 } else { 1041 attachment.remove() 1042 } 1043 } catch (error) { 1044 console.info(error) 1045 console.info(this.responseText) 1046 } 1047 formsApp.uploadAttachmentFile(files, input, $this); 1048 setTimeout(function(){ 1049 attachment.classList.add('forms-attachment-file-uploaded') 1050 }, 300); 1051 }; 1052 input.options[type+'Container'].appendChild(attachment); 1053 xhr.open("POST", JUri+"index.php", true); 1054 xhr.send(formData); 1055 } else { 1056 input.uploading = ''; 1057 formsApp.updateFieldsValues($this.fields, input, input.fieldId); 1058 formsApp.calculation($this); 1059 } 1060} 1061 1062formsApp.sendAjaxForm = function(form, $this){ 1063 $this.form.find('.ba-form-total-field .ba-cart-total-row .field-price-value').each(function(){ 1064 let object = { 1065 products: $f.extend(true, {}, this.calculation.products), 1066 total: this.calculation.total, 1067 resultTotal : this.calculation.resultTotal 1068 } 1069 for (let ind in object.products) { 1070 for (let i in object.products[ind]) { 1071 delete object.products[ind][i].input; 1072 } 1073 } 1074 if (this.calculation.shipping) { 1075 this.calculation.shipping.forEach(function(input){ 1076 if (input.checked) { 1077 object.shipping = { 1078 price: input.price * 1, 1079 ind: input.dataset.ind, 1080 title: input.dataset.title 1081 } 1082 } 1083 }); 1084 } 1085 if (this.calculation.promo) { 1086 object.promo = this.calculation.promo.code; 1087 } 1088 this.calculation.input.value = JSON.stringify(object); 1089 });
1090 let clone = form.cloneNode(true), 1091 payments = ['authorize', 'cloudpayments', 'paypal_sdk'], 1092 submitBtn = form.submitBtn; 1093 clone['submit-btn'].value = submitBtn.options.id; 1094 clone.task.value = 'form.message'; 1095 $this.form.find('.upload-file-input .ba-forms-attachment').each(function(){ 1096 let obj = $f.extend(true, {}, this.uploads), 1097 str, 1098 name = this.dataset.id; 1099 delete obj.count; 1100 str = JSON.stringify(obj); 1101 clone.querySelector('textarea[name="'+name+'"]').value = str; 1102 }); 1103 $this.form.find('select[name]').each(function(){ 1104 let cloneOptions = $f(clone).find('select[name="'+this.name+'"] option'); 1105 this.querySelectorAll('option').forEach(function(element, ind){ 1106 cloneOptions.get(ind).selected = element.selected; 1107 }); 1108 }); 1109 $f(clone).find('.hidden-condition-field').remove(); 1110 if (!(submitBtn.options.onclick == 'payment' && payments.indexOf(submitBtn.options.payment) != -1)) { 1111 submitBtn.classList.add('ba-thank-you-animation-in'); 1112 } 1113 if (submitBtn.options.onclick == 'payment' && submitBtn.options.payment == 'stripe') { 1114 formsApp.executeStripePayment(form, clone, $this); 1115 } else if (submitBtn.options.onclick == 'payment' && submitBtn.options.payment == 'paypal_sdk') { 1116 formsApp.executePaypalPayment(form, clone, $this); 1117 } else if (submitBtn.options.onclick == 'payment' && submitBtn.options.payment == 'authorize') { 1118 formsApp.executeAuthorizePayment(form, clone, $this); 1119 } else if (submitBtn.options.onclick == 'payment' && submitBtn.options.payment == 'cloudpayments') { 1120 formsApp.executeCloudPayments(form, clone, $this); 1121 } else if (submitBtn.options.onclick == 'payment') { 1122 const tokenInput = document.createElement('input'); 1123 tokenInput.name = formsApp.token; 1124 tokenInput.value = '1'; 1125 clone.append(tokenInput); 1126 1127 clone.style.display = 'none'; 1128 document.body.append(clone); 1129 clone.submit(); 1130 } else { 1131 formsApp.XMLHttpRequestForm(form, clone, $this); 1132 } 1133} 1134 1135formsApp.executeCloudPayments = function(form, clone, $this){ 1136 if (!('cp' in window)) { 1137 let script = document.createElement('script'); 1138 script.onload = function(){ 1139 formsApp.loadCloudPaymentsData(form, clone, $this); 1140 } 1141 script.src = "https://widget.cloudpayments.ru/bundles/cloudpayments"; 1142 document.head.append(script); 1143 } else { 1144 let object = {}, 1145 title = [], 1146 code = 'RUB', 1147 widget = new cp.CloudPayments(), 1148 invoiceId = +(new Date()); 1149 $this.form.find('.ba-form-total-field .ba-cart-total-row .field-price-value').each(function(){ 1150 if (!this.closest('.hidden-condition-field')) { 1151 code = this.calculation.code; 1152 object = JSON.parse(this.calculation.input.value); 1153 } 1154 }); 1155 for (let ind in object.products) { 1156 for (let i in object.products[ind]) { 1157 title.push(object.products[ind][i].title) 1158 } 1159 } 1160 if (object.shipping) { 1161 title.push(object.shipping.title); 1162 } 1163 const options = { 1164 publicId: formsApp.cloudPayments.public_id, 1165 description: title.join(', '), 1166 amount: object.resultTotal, 1167 invoiceId: invoiceId, 1168 currency: code, 1169 skin: 'modern' 1170 } 1171 if (formsApp.cloudPayments.fiscalization) { 1172 const receipt = { 1173 email: form.querySelector('input[type="email"]')?.value ?? '', 1174 taxationSystem: formsApp.cloudPayments.taxationSystem, 1175 Items: [ 1176 { 1177 "label": options.description, 1178 "price": object.resultTotal, 1179 "quantity": 1.00, 1180 "amount": object.resultTotal, 1181 "vat": formsApp.cloudPayments.vat == 'null' ? null : formsApp.cloudPayments.vat, 1182 "method": formsApp.cloudPayments.method, 1183 "object": formsApp.cloudPayments.object 1184 } 1185 ] 1186 } 1187 options.data = { 1188 CloudPayments: { 1189 CustomerReceipt: receipt, 1190 } 1191 }; 1192 } 1193 1194 1195 widget.charge(options, function(){ 1196 let input = document.createElement('input'); 1197 form.submitBtn.classList.add('ba-thank-you-animation-in'); 1198 input.type = 'hidden'; 1199 input.name = 'invoiceId'; 1200 input.value = invoiceId; 1201 clone.append(input); 1202 formsApp.XMLHttpRequestForm(form, clone, $this); 1203 }, function(){ 1204 form.status = ''; 1205 }); 1206 } 1207} 1208 1209formsApp.showMessagePopup = (btn, html, animation, $this) => { 1210 if (!btn.popup) { 1211 let div = document.createElement('div'), 1212 properties = ['width', 'radius', 'background-color', 'backdrop-color', 'icon-color'], 1213 wrapper = btn.closest('.ba-form-submit-wrapper'); 1214 div.innerHTML = '<div class="ba-forms-modal-backdrop" data-dismiss="formsModal"></div>'+ 1215 '<div class="ba-forms-modal">'+ 1216 '<i class="ba-form-icons ba-icon-close" data-dismiss="formsModal" tabindex="0"></i>'+ 1217 '<div class="ba-forms-modal-body"></div>'+ 1218 '</div>'; 1219 div.className = 'ba-forms-modal-wrapper ba-form-message-popup '+animation; 1220 div.dataset.form = $this.formId;
1221 properties.forEach((property) => { 1222 div.style.setProperty('--submit-popup-'+property, wrapper.style.getPropertyValue('--submit-popup-'+property)); 1223 }) 1224 btn.popup = $f(div); 1225 document.body.append(div); 1226 } 1227 btn.popup.find('.ba-forms-modal-body').html(html); 1228 setTimeout(() => { 1229 btn.popup.formsModal(); 1230 btn.popup.find('.ba-forms-modal').each(function(){ 1231 this.style.setProperty('--popup-modal-height', this.offsetHeight+'px'); 1232 }); 1233 }, 300); 1234} 1235 1236formsApp.executeAuthorizePayment = function(form, clone, $this){ 1237 if (!formsApp.authorize) { 1238 let div = document.createElement('div'), 1239 btn; 1240 div.innerHTML = '<div class="ba-forms-modal-backdrop" data-dismiss="formsModal"></div>'+ 1241 '<div class="ba-forms-modal">'+ 1242 '<div class="ba-forms-modal-header"><span class="ba-forms-modal-title">Authorize.Net</span>'+ 1243 '<i class="ba-form-icons ba-icon-close" data-dismiss="formsModal" tabindex="0"></i></div>'+ 1244 '<div class="ba-forms-modal-body">'+ 1245 '<div class="ba-forms-authorize-field-wrapper">'+ 1246 '<input type="text" class="ba-forms-authorize-card-number"><i class="ba-form-icons ba-icon-card"></i></div>'+ 1247 '<div class="ba-forms-authorize-field-wrapper">'+ 1248 '<input type="text" class="ba-forms-authorize-expiration-date"><i class="ba-form-icons ba-icon-calendar"></i>'+ 1249 '</div>'+ 1250 '<div class="ba-forms-authorize-field-wrapper">'+ 1251 '<input type="text" class="ba-forms-authorize-card-code"><i class="ba-form-icons ba-icon-lock"></i></div>'+ 1252 '</div><div class="ba-forms-modal-footer"><span class="ba-forms-authorize-pay-btn">'+ 1253 '<span class="ba-forms-authorize-pay">'+formsApp._('PAY')+'</span>'+ 1254 '<span class="field-price-currency"></span><span class="field-price-value"></span>'+ 1255 '</span></div></div>'; 1256 div.className = 'ba-forms-modal-wrapper ba-form-authorize-modal'; 1257 btn = div.querySelector('.ba-forms-authorize-pay-btn'); 1258 btn.cardNumber = div.querySelector('.ba-forms-authorize-card-number'); 1259 btn.expirationDate = div.querySelector('.ba-forms-authorize-expiration-date'); 1260 btn.cardCode = div.querySelector('.ba-forms-authorize-card-code'); 1261 btn.cardNumber.placeholder = 'Card Number'; 1262 btn.expirationDate.placeholder = 'MM / YY'; 1263 btn.cardCode.placeholder = 'CVC'; 1264 btn.cardNumber.addEventListener('input', function(){ 1265 let value = this.value.replace(/\s/g, ''), 1266 match = value.match(/\d{1,16}/); 1267 if (!match) { 1268 this.value = ''; 1269 } else { 1270 let str = '', 1271 j = 1; 1272 for (let i = 0; i < match[0].length; i++) { 1273 if (j == 5) { 1274 j = 1; 1275 str += ' '; 1276 } 1277 str += match[0][i]; 1278 j++; 1279 } 1280 if (str != this.value) { 1281 this.value = str; 1282 } 1283 } 1284 this.filled = this.value.length >= 14; 1285 }); 1286 btn.expirationDate.addEventListener('input', function(){ 1287 formsApp.executeMask(this, '##/##'); 1288 this.filled = !!this.value.match(/\d\d\/\d{2}/); 1289 }); 1290 btn.cardCode.addEventListener('input', function(){ 1291 let match = this.value.match(/\d{1,4}/); 1292 if (!match) { 1293 this.value = ''; 1294 } else if (match[0] != this.value) { 1295 this.value = match[0]; 1296 } 1297 this.filled = this.value.length >= 3; 1298 }); 1299 btn.cardNumber.addEventListener('focus', function(){ 1300 formsApp.removeAlertTooltip(this); 1301 }); 1302 btn.expirationDate.addEventListener('focus', function(){ 1303 formsApp.removeAlertTooltip(this); 1304 }); 1305 btn.cardCode.addEventListener('focus', function(){ 1306 formsApp.removeAlertTooltip(this); 1307 }); 1308 formsApp.authorize = $f(div); 1309 document.body.append(div); 1310 } 1311 formsApp.authorize.attr('data-form', $this.formId); 1312 let price = symbol = '', 1313 position = false, 1314 total = 0; 1315 $this.form.find('.ba-form-total-field .ba-cart-total-row .field-price-value').each(function(){ 1316 if (!this.closest('.hidden-condition-field')) { 1317 total = this.calculation.resultTotal; 1318 price = this.textContent; 1319 symbol = this.calculation.symbol; 1320 position = this.closest('.ba-field-container').classList.contains('right-currency-position'); 1321 } 1322 }); 1323 formsApp.authorize.find('input').val('').each(function(){ 1324 this.filled = false;
1325 formsApp.removeAlertTooltip(this); 1326 }); 1327 formsApp.authorize.find('.ba-forms-authorize-pay-btn').each(function(){ 1328 this.classList[position ? 'add' : 'remove']('right-currency-position'); 1329 this.querySelector('.field-price-currency').textContent = symbol; 1330 this.querySelector('.field-price-value').textContent = price; 1331 this.total = total; 1332 }).off('click').on('click', function(){ 1333 let btn = this; 1334 if (!btn.status && btn.cardNumber.filled && btn.expirationDate.filled && btn.cardCode.filled) { 1335 btn.status = 'pending'; 1336 btn.classList.add('ba-thank-you-animation-in'); 1337 formsApp.fetch.request(JUri+'index.php?option=com_baforms&task=form.payAuthorize', { 1338 id : $this.formId, 1339 cardNumber: btn.cardNumber.value, 1340 expirationDate: btn.expirationDate.value, 1341 cardCode: btn.cardCode.value, 1342 total : total 1343 }).then(function(text){ 1344 let obj = JSON.parse(text), 1345 input = document.createElement('input'), 1346 flag = obj.transactionResponse && obj.transactionResponse.transId != '' 1347 && obj.transactionResponse.transId != 0; 1348 setTimeout(function(){ 1349 btn.classList.remove('ba-thank-you-animation-in'); 1350 btn.classList.add('ba-thank-you-animation-out'); 1351 setTimeout(function(){ 1352 btn.classList.remove('ba-thank-you-animation-out'); 1353 if (!flag) { 1354 msg = ''; 1355 if (obj.transactionResponse) { 1356 obj.transactionResponse.errors.forEach(function(error){ 1357 msg += (msg ? ', ' : '')+error.errorText; 1358 }); 1359 } 1360 msg = msg ? msg : 'Transaction failed'; 1361 formsApp.showNotice(msg, 'ba-alert'); 1362 } 1363 setTimeout(function(){ 1364 btn.status = ''; 1365 if (flag) { 1366 input.type = 'hidden'; 1367 input.name = 'transId'; 1368 input.value = obj.transactionResponse.transId; 1369 clone.append(input); 1370 form.submitBtn.options.authorize_return_url = obj.return_url; 1371 form.submitBtn.classList.add('ba-thank-you-animation-in'); 1372 formsApp.authorize.formsModal('hide'); 1373 formsApp.XMLHttpRequestForm(form, clone, $this); 1374 } 1375 }, 600); 1376 }, 300); 1377 }, 2000); 1378 }) 1379 } else if (!btn.status) { 1380 ['cardNumber', 'expirationDate', 'cardCode'].forEach(function(el){ 1381 if (!btn[el].filled) { 1382 let key = btn[el].value ? 'ENTER_VALID_VALUE' : 'THIS_FIELD_REQUIRED'; 1383 formsApp.toggleAlertTooltip(true, btn[el], btn[el].closest('.ba-forms-authorize-field-wrapper'), key); 1384 } 1385 }); 1386 } 1387 }); 1388 form.status = ''; 1389 setTimeout(function(){ 1390 formsApp.authorize.formsModal(); 1391 }, 100); 1392} 1393 1394formsApp.executePaypalPayment = function(form, clone, $this){ 1395 let obj = null; 1396 $this.form.find('.ba-form-total-field .ba-cart-total-row .field-price-value').each(function(){ 1397 if (!this.closest('.hidden-condition-field')) { 1398 obj = this.calculation; 1399 } 1400 }); 1401 if (!formsApp.paypalData) { 1402 formsApp.loadPaypalData(form, clone, $this); 1403 } else if (!('paypal' in window)) { 1404 let script = document.createElement('script'); 1405 script.onload = function(){ 1406 formsApp.executePaypalPayment(form, clone, $this); 1407 } 1408 script.src = 'https://www.paypal.com/sdk/js?client-id='+formsApp.paypalData.client_id+'¤cy='+obj.code; 1409 document.head.append(script); 1410 } else { 1411 if (!formsApp.paypal) { 1412 let div = document.createElement('div'); 1413 div.innerHTML = '<div class="ba-forms-modal-backdrop" data-dismiss="formsModal"></div>'+ 1414 '<div class="ba-forms-modal">'+ 1415 '<div class="ba-forms-modal-header"><span class="ba-forms-modal-title">PayPal</span>'+ 1416 '<i class="ba-form-icons ba-icon-close" data-dismiss="formsModal" tabindex="0"></i></div>'+ 1417 '<div class="ba-forms-modal-body">'+ 1418 '<div id="paypal-buttons-wrapper"></div>'+ 1419 '</div></div>'; 1420 div.className = 'ba-forms-modal-wrapper ba-form-paypal-modal'; 1421 formsApp.paypal = $f(div); 1422 document.body.append(div); 1423 } 1424 formsApp.paypal.attr('data-form', $this.formId); 1425 formsApp.paypal.find('#paypal-buttons-wrapper')[0].innerHTML = ''; 1426 let total = obj.total, 1427 item_total = 0, 1428 discount = obj.promo ? (obj.promo.unit == '%' ? total * obj.promo.discount / 100 : obj.promo.discount) : 0, 1429 tax = obj.taxResult ? (total - discount) * obj.tax / 100 : 0, 1430 shipping = 0, 1431 purchase_units = [{ 1432 amount: { 1433 currency: obj.code, 1434 breakdown: { 1435 item_total: { 1436 currency_code: obj.code, 1437 value: 0 1438 } 1439 }, 1440 value: obj.resultTotal 1441 }, 1442 items: [], 1443 }]; 1444 for (let i in obj.products) { 1445 for (let ind in obj.products[i]) { 1446 purchase_units[0].items.push({ 1447 name: obj.products[i][ind].title, 1448 unit_amount: { 1449 currency_code: obj.code, 1450 value: formsApp.decimalAdjust('round', obj.products[i][ind].price * 1, -2), 1451 }, 1452 quantity: obj.products[i][ind].quantity 1453 }); 1454 item_total += obj.products[i][ind].total; 1455 } 1456 } 1457 purchase_units[0].amount.breakdown.item_total.value = formsApp.decimalAdjust('round', item_total, -2); 1458 if (tax) { 1459 tax = formsApp.decimalAdjust('round', tax, -2); 1460 purchase_units[0].amount.breakdown.tax_total = { 1461 currency_code: obj.code, 1462 value: tax 1463 } 1464 } 1465 if (discount) { 1466 discount = formsApp.decimalAdjust('round', discount, -2); 1467 purchase_units[0].amount.breakdown.discount = { 1468 currency_code: obj.code, 1469 value: discount 1470 } 1471 } 1472 if (obj.shipping) { 1473 obj.shipping.forEach(function(input){ 1474 if (input.checked) { 1475 shipping = formsApp.decimalAdjust('round', input.price * 1, -2); 1476 purchase_units[0].amount.breakdown.shipping = { 1477 currency_code: obj.code, 1478 value: shipping 1479 } 1480 } 1481 }); 1482 } 1483 purchase_units[0].amount.value = formsApp.decimalAdjust('round', total + tax + shipping - discount, -2); 1484 paypal.Buttons({ 1485 createOrder: function (data, actions){ 1486 return actions.order.create({ 1487 purchase_units: purchase_units 1488 }); 1489 }, 1490 onApprove: function(data, actions){ 1491 return actions.order.capture().then(function(){ 1492 formsApp.paypal.formsModal('hide'); 1493 form.submitBtn.classList.add('ba-thank-you-animation-in'); 1494 formsApp.XMLHttpRequestForm(form, clone, $this); 1495 }); 1496 } 1497 }).render('#paypal-buttons-wrapper').then(function(){ 1498 formsApp.paypal.formsModal(); 1499 }); 1500 form.status = ''; 1501 } 1502} 1503 1504formsApp.executeStripePayment = function(form, clone, $this){ 1505 if (!('Stripe' in window)) { 1506 let script = document.createElement('script'); 1507 script.onload = function(){ 1508 formsApp.loadStripeData(form, clone, $this); 1509 } 1510 script.src = "https://js.stripe.com/v3"; 1511 document.head.append(script); 1512 } else if (!formsApp.stripeData) { 1513 formsApp.loadStripeData(form, clone, $this); 1514 } else { 1515 let object = '{}', 1516 name = 0; 1517 formsApp.stripe = Stripe(formsApp.stripeData.api_key); 1518 $this.form.find('.ba-form-total-field .ba-cart-total-row .field-price-value').last().each(function(){ 1519 if (!this.closest('.hidden-condition-field')) { 1520 name = this.calculation.input.name; 1521 object = this.calculation.input.value; 1522 } 1523 }); 1524 formsApp.fetch.request(JUri+'index.php?option=com_baforms&task=form.stripeCharges', { 1525 object : object, 1526 name: name, 1527 id : $this.formId 1528 }).then(function(text){ 1529 let obj = JSON.parse(text), 1530 input = document.createElement('input'); 1531 if (obj.error) { 1532 console.error(obj.error.message); 1533 form.status = ''; 1534 form.submitBtn.classList.remove('ba-thank-you-animation-in'); 1535 form.submitBtn.classList.add('ba-thank-you-animation-out'); 1536 setTimeout(function(){ 1537 form.submitBtn.classList.remove('ba-thank-you-animation-out'); 1538 }, 300); 1539 } else { 1540 formsApp.stripeData.sessionId = obj.id; 1541 input.type = 'hidden'; 1542 input.name = 'payment_id'; 1543 input.value = obj.payment_intent; 1544 clone.append(input); 1545 formsApp.XMLHttpRequestForm(form, clone, $this); 1546 } 1547 }); 1548 } 1549} 1550 1551formsApp.loadPaypalData = function(form, clone, $this){ 1552 fetch(JUri+'index.php?option=com_baforms&task=form.getPaypalData').then(function(response){ 1553 return response.json(); 1554 }).then(function(json){ 1555 formsApp.paypalData = json; 1556 formsApp.executePaypalPayment(form, clone, $this); 1557 }); 1558} 1559 1560formsApp.loadStripeData = function(form, clone, $this){ 1561 fetch(JUri+'index.php?option=com_baforms&task=form.getStripeData').then(function(response){ 1562 return response.json(); 1563 }).then(function(json){ 1564 formsApp.stripeData = json; 1565 formsApp.executeStripePayment(form, clone, $this); 1566 }); 1567} 1568 1569formsApp.loadCloudPaymentsData = function(form, clone, $this){ 1570 fetch(JUri+'index.php?option=com_baforms&task=form.getCloudPaymentsData').then(function(response){ 1571 return response.json(); 1572 }).then(function(json){ 1573 formsApp.cloudPayments = json; 1574 formsApp.executeCloudPayments(form, clone, $this); 1575 }); 1576} 1577 1578formsApp.XMLHttpRequestForm = async function(form, clone, $this){ 1579 let btn = form.submitBtn, 1580 xhr = new XMLHttpRequest(), 1581 data = new FormData(clone); 1582 1583 const { token } = formsApp; 1584 data.append(token, "1"); 1585 1586 xhr.onload = xhr.onerror = function(){ 1587 if (xhr.readyState == 4) { 1588 setTimeout(function(){ 1589 btn.classList.remove('ba-thank-you-animation-in'); 1590 btn.classList.add('ba-thank-you-animation-out'); 1591 setTimeout(function(){ 1592 btn.classList.remove('ba-thank-you-animation-out'); 1593 setTimeout(function(){ 1594 form.status = ''; 1595 if (formsApp.debug || xhr.status != 200) { 1596 console.info(xhr.responseText); 1597 } 1598 let response = btn.options.onclick == 'payment' ? { 1599 status: true 1600 } : JSON.parse(xhr.responseText); 1601 if (!response.status) { 1602 formsApp.showNotice(response.message, 'ba-alert'); 1603 return; 1604 } 1605 formsApp.clearFields($this); 1606 $this.form.find('.ba-form-page') 1607 .addClass('ba-hidden-form-page') 1608 .first() 1609 .removeClass('ba-hidden-form-page'); 1610 $f(btn).trigger('success-submit'); 1611 if (response.isClosed) { 1612 $this.form.html('<div class="ba-form-expiration-message">'+response.closedMessage+'</div>') 1613 } 1614 if (btn.options.onclick == 'message' && btn.options.messageType == 'advanced') { 1615 formsApp.showMessagePopup(btn, response.message, btn.options.popupAnimation, $this); 1616 } else if (btn.options.onclick == 'message') { 1617 formsApp.showNotice(response.message); 1618 } else if (btn.options.onclick == 'redirect') { 1619 window.location.href = response.message; 1620 } else if (btn.options.payment == 'stripe') { 1621 formsApp.stripe.redirectToCheckout({ 1622 sessionId: formsApp.stripeData.sessionId 1623 }).then(function(result) { 1624 console.info(result) 1625 }); 1626 } else if (btn.options.payment == 'authorize' && btn.options.authorize_return_url) { 1627 window.location.href = btn.options.authorize_return_url; 1628 } else if (btn.options.payment == 'cloudpayments') { 1629 window.location.href = formsApp.cloudPayments.return_url; 1630 } else if (btn.options.payment == 'paypal_sdk') { 1631 window.location.href = formsApp.paypalData.return_url; 1632 } 1633 }, 500); 1634 }, 300); 1635 }, 1500); 1636 } 1637 }; 1638 xhr.open("POST", clone.action, true); 1639 xhr.send(data); 1640} 1641 1642formsApp.clearFields = function($this){ 1643 if (formsApp.storage[$this.formURL] && formsApp.storage[$this.formURL][$this.formId]) { 1644 delete formsApp.storage[$this.formURL][$this.formId]; 1645 localStorage.setItem('forms-progress', JSON.stringify(formsApp.storage)); 1646 } 1647 let not = '[data-type="submit"],[data-type="map"],[data-type="html"],[data-type="text"],[data-type="image"],'+ 1648 '[data-type="headline"]'; 1649 $this.form.find('.forms-recaptcha[data-captcha="turnstile"]').each(function(){
1650 CaptchaFactory.get('turnstile').reset(this.id); 1651 }) 1652 $this.form.find('.ba-form-field-item').not(not).each(function(){ 1653 let input = $f(this).find('[name]'); 1654 switch (this.dataset.type) { 1655 case 'signature': 1656 this.instance.clear(); 1657 input.value = ''; 1658 break; 1659 case 'poll': 1660 let id = 0; 1661 this.querySelectorAll('input').forEach(function(input){ 1662 id = input.name.replace('[]', ''); 1663 }); 1664 if (id != 0) { 1665 let item = this.querySelector('.ba-form-checkbox-group-wrapper'); 1666 formsApp.fetch.request(JUri+'index.php?option=com_baforms&task=form.getPollResults', { 1667 id: id, 1668 form_id: $this.formId 1669 }).then(function(text){ 1670 let div = document.createElement('div'); 1671 div.innerHTML = text; 1672 item.querySelectorAll('.ba-form-checkbox-wrapper').forEach(function(wrapper){ 1673 wrapper.remove(); 1674 }); 1675 div.querySelectorAll('.ba-form-checkbox-wrapper').forEach(function(wrapper){ 1676 item.append(wrapper); 1677 }); 1678 formsApp.sortPoll(item); 1679 item.classList.add('ba-poll-results'); 1680 if ($this.form.find('.ba-poll-results').length != 0) { 1681 setTimeout(function(){ 1682 $this.form.find('.ba-form-submit-btn').remove(); 1683 }, 200); 1684 } 1685 }); 1686 } 1687 break; 1688 case 'input': 1689 case 'address': 1690 case 'calendar': 1691 input.val('').trigger('input'); 1692 if (this.dataset.type == 'calendar') { 1693 $f(this).find('input').val(''); 1694 } 1695 if (this.querySelector('.confirm-email-wrapper')) { 1696 this.querySelector('.confirm-email-wrapper input').value = ''; 1697 } 1698 if (this.querySelector('.confirm-password-wrapper')) { 1699 this.querySelector('.confirm-password-wrapper input').value = ''; 1700 this.querySelector('.confirm-password-wrapper input').type = 'password'; 1701 } 1702 if (this.querySelector('.ba-input-password-icons')) { 1703 input[0].type = 'password'; 1704 } 1705 break; 1706 case 'phone': 1707 let parent = input.closest('.ba-field-container'), 1708 flag = parent.find('.ba-phone-selected-country').attr('data-default'); 1709 parent.find(`li.ba-phone-country-item[data-flag="${flag}"]`).trigger('click'); 1710 break; 1711 case 'radio': 1712 case 'checkbox': 1713 case 'rating': 1714 input.prop('checked', false).trigger('change'); 1715 break; 1716 case 'select': 1717 case 'selectMultiple': 1718 input.find('option').prop('selected', false); 1719 input.trigger('change'); 1720 break; 1721 case 'acceptance': 1722 input[0].checked = false; 1723 break; 1724 case 'slider': 1725 input.val(''); 1726 $f(this).find('input[type="range"]').each(function(){ 1727 if ('index' in this.dataset) { 1728 this.value = this.dataset.index == 0 ? this.min : this.max; 1729 } else { 1730 this.value = this.min; 1731 } 1732 }).trigger('input'); 1733 break; 1734 case 'upload': 1735 input.val(''); 1736 this.classList.remove('has-uploaded-file'); 1737 this.querySelector('.ba-forms-attachment').uploads = { 1738 count: 0 1739 } 1740 $f(this).find('.ba-forms-xhr-attachment-wrapper').empty(); 1741 break; 1742 } 1743 }); 1744} 1745 1746class FormProgressHelper { 1747 static #disabledFields = { 1748 submit: true, 1749 map: true, 1750 html: true, 1751 text: true, 1752 image: true, 1753 headline: true, 1754 upload: true 1755 } 1756 1757 static setSavedProgress(formWrapper) { 1758 const { formURL, formId } = formWrapper; 1759 const data = formsApp.storage[formURL]?.[formId] ?? null; 1760 if (!data) { 1761 return; 1762 } 1763 1764 data.fields.forEach(field => { 1765 const input = formWrapper.form.find(`[name="${field.name}"]`); 1766 if (!input.length) { 1767 return; 1768 } 1769 1770 switch (field.type) { 1771 case 'input' : 1772 case 'address': 1773 if (input[0].formsInputMask) { 1774 input[0].setSelectionRange(0, 0); 1775 input[0].setRangeText(field.data.value); 1776 } else { 1777 input.val(field.data.value); 1778 } 1779 input.trigger('input');
1780 if ('confirm' in field.data) { 1781 input.closest('.ba-form-field-item').find('.confirm-email-wrapper input').val(field.data.confirm); 1782 } 1783 if ('password' in field.data) { 1784 input.closest('.ba-form-field-item').find('.confirm-password-wrapper input').val(field.data.password); 1785 } 1786 break; 1787 case 'phone': 1788 let parent = input.closest('.ba-field-container'); 1789 parent.find('.ba-phone-country-item[data-flag="'+field.data.flag+'"]').trigger('click'); 1790 parent.find('.ba-phone-number-input').each(function(){ 1791 this.setSelectionRange(0, 0); 1792 this.setRangeText(field.data.value); 1793 }).trigger('input'); 1794 break; 1795 case 'calendar': 1796 let value = field.data.value.split(' - '); 1797 input.closest('.ba-field-container').find('input[type="text"]').each(function(i){ 1798 this.value = value[i]; 1799 }).trigger('input'); 1800 break; 1801 case 'radio': 1802 case 'checkbox': 1803 case 'rating': 1804 input.each(function(){ 1805 if (field.data.checked.indexOf(this.value) != -1) { 1806 this.checked = true; 1807 $f(this).trigger('change'); 1808 } 1809 }); 1810 break; 1811 case 'select': 1812 case 'selectMultiple': 1813 input.find('option').each(function(){ 1814 if (field.data.selected.indexOf(this.value) != -1) { 1815 this.selected = true; 1816 input.trigger('change'); 1817 } 1818 }); 1819 break; 1820 case 'acceptance': 1821 if (field.data.selected) { 1822 input.prop('checked', field.data.selected); 1823 } 1824 break; 1825 case 'slider': 1826 let range = input.closest('.ba-field-container').find('input[type="range"]'); 1827 input.value = field.data.value; 1828 if (field.data.type == 'range') { 1829 range.val(field.data.value).trigger('input'); 1830 } else { 1831 let array = field.data.value.split(' '); 1832 range.first().val(array[0]).trigger('input'); 1833 range.last().val(array[1]).trigger('input'); 1834 } 1835 break; 1836 } 1837 }) 1838 } 1839 1840 static getData(formWrapper) { 1841 const progress = { 1842 id: formWrapper.formId, 1843 date: +new Date(), 1844 url: formWrapper.formURL, 1845 fields: [] 1846 } 1847 1848 Array.from(formWrapper.form.find('.ba-form-field-item')).forEac
1848h(item => { 1849 const { type } = item.dataset; 1850 if (this.#disabledFields[type]) { 1851 return; 1852 } 1853 1854 const input = item.querySelector('[name]'); 1855 const field = { 1856 name: input.name, 1857 type: type, 1858 data: {} 1859 } 1860 switch (type) { 1861 case 'input' : 1862 case 'address': 1863 case 'calendar': 1864 field.data.value = input.value; 1865 if (input.formsInputMask) { 1866 field.data.value = ''; 1867 for (let i = 0; i < input.value.length; i++) { 1868 if (input.formsInputMask[i] == '_') { 1869 field.data.value += input.value[i]; 1870 } 1871 } 1872 } 1873 if (item.querySelector('.confirm-email-wrapper')) { 1874 field.data.confirm = item.querySelector('.confirm-email-wrapper input').value; 1875 } 1876 if (item.querySelector('.confirm-password-wrapper')) { 1877 field.data.password = item.querySelector('.confirm-password-wrapper input').value; 1878 } 1879 break; 1880 case 'phone': 1881 const parent = input.closest('.ba-field-container'); 1882 const flag = parent.querySelector('.ba-phone-selected-country .ba-phone-flag'); 1883 const match = flag.className.match(/ba-phone-flag-\w+/); 1884 const phoneNumber = parent.querySelector('.ba-phone-number-input'); 1885 field.data.value = ''; 1886 field.data.flag = match[0].replace('ba-phone-flag-', ''); 1887 for (let i = 0; i < phoneNumber.value.length; i++) { 1888 if (phoneNumber.placeholder[i] == '_') { 1889 field.data.value += phoneNumber.value[i]; 1890 } 1891 } 1892 break; 1893 case 'radio': 1894 case 'checkbox': 1895 case 'rating': 1896 field.data.checked = []; 1897 item.querySelectorAll('[name]').forEach(checkbox => { 1898 if (checkbox.checked) { 1899 field.data.checked.push(checkbox.value) 1900 } 1901 }) 1902 break; 1903 case 'select': 1904 case 'selectMultiple': 1905 field.data.selected = []; 1906 item.querySelectorAll('select[name] option').forEach(option => { 1907 if (option.selected) { 1908 field.data.selected.push(option.value) 1909 } 1910 }) 1911 break; 1912 case 'acceptance': 1913 field.data.selected = input.checked; 1914 break; 1915 case 'slider': 1916 field.data.type = item.querySelector('.form-range-wrapper') ? 'range' : 'slider'; 1917 field.data.value = input.value; 1918 break; 1919 } 1920 progress.fields.push(field); 1921 }); 1922 1923 return progress; 1924 } 1925} 1926 1927formsApp.checkAutoNavigation = function($this, field){ 1928 if ($this.autoNavigation.enable) { 1929 let page = field.closest('.ba-form-page'), 1930 next = true; 1931 page.querySelectorAll('.ba-form-field-item').forEach(function(el){ 1932 let empty = true; 1933 if ($this.autoNavigation.fields.indexOf(el.dataset.type) == -1) { 1934 1935 } else if (el.dataset.type == 'select') { 1936 empty = el.querySelector('select').value == ''; 1937 } else { 1938 el.querySelectorAll('input').forEach(function(input){ 1939 if (input.checked) { 1940 empty = false; 1941 return false; 1942 } 1943 }); 1944 } 1945 if (empty) { 1946 next = false;
1947 return false; 1948 } 1949 }); 1950 if (next) { 1951 $f(page).find('.ba-form-page-break-button[data-action="next"]').trigger('click'); 1952 } 1953 } 1954} 1955 1956formsApp.submitData = () => { 1957 const form = formsApp.submitForm.form; 1958 if (form.find('.ba-form-field-item:not(.hidden-condition-field)').find('.ba-alert-tooltip').length == 0) { 1959 form[0].status = 'pending'; 1960 formsApp.sendAjaxForm(form[0], formsApp.submitForm); 1961 } 1962 formsApp.submitForm = null; 1963} 1964 1965formsApp.createForm = function(){ 1966 if (this.formId) { 1967 return true; 1968 } 1969 let $this = this, 1970 defaultValues = {}; 1971 $this.carts = []; 1972 $this.products = {}; 1973 $this.fields = {}; 1974 $this.calculation = {}; 1975 $this.items = {}; 1976 $this.autoNavigation = { 1977 enable : false, 1978 fields: ['select', 'radio', 'rating'] 1979 }; 1980 this.formId = this.querySelector('input[name="form-id"]').value * 1; 1981 formsApp.loaded[this.formId] = this; 1982 this.querySelector('input[name="page-title"]').value = document.querySelector('title').textContent; 1983 this.querySelector('input[name="page-url"]').value = window.location.href; 1984 this.querySelectorAll('input[name="page-id"]').forEach(function(el){ 1985 if (el.value == 0 && window.themeData) { 1986 el.value = window.themeData.id; 1987 } 1988 }); 1989 this.formURL = window.location.host.replace('www.', '')+window.location.pathname.replace('/index.php', ''); 1990 if (this.formURL[this.formURL.length - 1] != '/') { 1991 this.formURL += '/'; 1992 } 1993 this.form = $f(this).find('form').on('submit', function(event){ 1994 event.preventDefault(); 1995 }); 1996 this.form.find('.ba-form-submit-btn').each(function(){ 1997 this.options = { 1998 id: this.dataset.id, 1999 onclick: this.dataset.onclick, 2000 payment: this.dataset.payment, 2001 popupAnimation: this.dataset.popupAnimation, 2002 messageType: this.dataset.messageType, 2003 productTitle: this.dataset.productTitle, 2004 productPrice: this.dataset.productPrice 2005 } 2006 }).removeAttr('data-payment').removeAttr('data-id').removeAttr('data-message-type') 2007 .removeAttr('data-popup-animation').on('click', async function (event) { 2008 event.preventDefault(); 2009 let form = $this.form[0]; 2010 if (form.status != 'pending') { 2011 form.submitBtn = this; 2012 formsApp.submitForm = $this; 2013 formsApp.checkAlert($this.form); 2014 const canSubmit = await CaptchaHelper.checkResponse(this); 2015 if (canSubmit) { 2016 formsApp.submitData(); 2017 } 2018 } 2019 }).removeAttr('data-onclick').removeAttr('data-message'); 2020 this.form.find('.ba-poll-results').each(function(){ 2021 formsApp.sortPoll(this); 2022 }) 2023 this.form.find('.ba-form-page-break-button').each(function(){ 2024 if (this.dataset.action == 'next' && this.dataset.auto) { 2025 $this.autoNavigation.enable = true; 2026 } 2027 }).on('click keyup', function(event){ 2028 FormsAccessibilityHelper.processAction(event, () => { 2029 let page = $f(this).closest('.ba-form-page'), 2030 rect = $this.form[0].getBoundingClientRect(), 2031 pageKey = page[0].dataset.pageKey; 2032 if (this.dataset.action == 'next') { 2033 formsApp.checkAlert(page); 2034 if (page.find('.ba-form-field-item').not('.hidden-condition-field').find('.ba-alert-tooltip').length) { 2035 return false; 2036 } 2037 } 2038 page.addClass('ba-hidden-form-page'); 2039 if ($this.pages && $this.pages[pageKey] && this.dataset.action == 'next') { 2040 page = $f($this.pages[pageKey].next).removeClass('ba-hidden-form-page'); 2041 page.find('.ba-form-page-break-button[data-action="back"]')[0].prevPage = pageKey; 2042 } else if (this.dataset.action == 'back' && this.prevPage) { 2043 page = $f($this.pages[this.prevPage].prev).removeClass('ba-hidden-form-page'); 2044 this.prevPage = null; 2045 } else { 2046 page = page[this.dataset.action == 'next' ? 'next': 'prev']().removeClass('ba-hidden-form-page'); 2047 } 2048 if (rect.top < 0) { 2049 $this.form[0].scrollIntoView(true); 2050 } 2051 if (this.dataset.action == 'next') { 2052 page.find('.ba-form-submit-btn').each(function(){ 2053 CaptchaHelper.createIfExist(this); 2054 }); 2055 FormsSignature.make(); 2056 } 2057 }) 2058 }); 2059 this.form.find('.upload-file-btn').each(function(){ 2060 this.file = this.closest('.upload-file-input').querySelector('input[type="file"]'); 2061 }).on('click keyup', function(event){ 2062 FormsAccessibilityHelper.processAction(event, () => { 2063 formsApp.removeAlertTooltip(this.file); 2064 if (this.file.uploading != 'pending') { 2065 this.file.click(); 2066 } 2067 }); 2068 }); 2069 this.form.find('.drag-drop-upload-file').on('dragenter dragover', function(event){ 2070 event.preventDefault(); 2071 event.stopPropagation(); 2072 this.classList.add('upload-file-drag-over'); 2073 return false;
2074 }).on('dragleave', function(event){ 2075 event.preventDefault(); 2076 event.stopPropagation(); 2077 this.classList.remove('upload-file-drag-over'); 2078 return false; 2079 }).on('drop', function(event){ 2080 event.preventDefault(); 2081 event.stopPropagation(); 2082 this.classList.remove('upload-file-drag-over'); 2083 var files = event.originalEvent.target.files || event.originalEvent.dataTransfer.files; 2084 $f(this).find('.ba-forms-attachment').each(function(){ 2085 this.files = files; 2086 }).trigger('change'); 2087 }); 2088 this.form.find('input[type="file"].ba-forms-attachment').each(function(){ 2089 let name = '.ba-forms-xhr-attachment-wrapper'; 2090 this.options = { 2091 id: $this.formId, 2092 size: this.dataset.size * 1000, 2093 types: this.dataset.types.replace(/\s/g, '').split(','), 2094 count: this.multiple ? this.dataset.count : 1, 2095 images: ['gif', 'jpg', 'jpeg', 'png', 'svg', 'webp'], 2096 fileContainer: this.closest('.ba-field-container').querySelector(name+'[data-type="file"]'), 2097 imageContainer: this.closest('.ba-field-container').querySelector(name+'[data-type="image"]') 2098 } 2099 this.uploads = { 2100 count: 0 2101 } 2102 }).on('change', function(){ 2103 this.uploading = 'pending'; 2104 let files = [].slice.call(this.files), 2105 uploaded = {}, 2106 msg = ''; 2107 for (let ind in this.uploads) { 2108 if (ind == 'count') { 2109 continue; 2110 } 2111 uploaded[this.uploads[ind].name] = true; 2112 } 2113 if (this.options.count != '' && this.uploads.count == this.options.count * 1) { 2114 msg = 'MAXIMUM_FILES_NUMBER_EXCEEDED'; 2115 } else { 2116 for (let i = 0; i < files.length; i++) { 2117 let name = files[i].name.split('.'); 2118 files[i].ext = name[name.length - 1].toLowerCase() 2119 if (this.options.size < files[i].size) { 2120 msg = 'NOT_ALLOWED_FILE_SIZE'; 2121 break; 2122 } else if (this.options.types.indexOf(files[i].ext) == -1) { 2123 msg = 'NOT_SUPPORTED_FILE'; 2124 break; 2125 } else if (uploaded[files[i].name]) { 2126 msg = 'FILES_ALREADY_UPLOADED'; 2127 break; 2128 } 2129 } 2130 } 2131 this.value = ''; 2132 if (msg != '') { 2133 this.uploading = ''; 2134 formsApp.showNotice(formsApp._(msg), 'ba-alert'); 2135 } else { 2136 formsApp.uploadAttachmentFile(files, this, $this); 2137 } 2138 }); 2139 this.form.find('.ba-form-save-progress-link').on('click', function(){ 2140 const progress = FormProgressHelper.getData($this); 2141 if (!formsApp.storage[progress.url]) { 2142 formsApp.storage[progress.url] = {}; 2143 } 2144 formsApp.storage[progress.url][progress.id] = progress; 2145 localStorage.setItem('forms-progress', JSON.stringify(formsApp.storage)); 2146 formsApp.showNotice(formsApp._('PROGRESS_SAVED_MESSAGE')); 2147 }); 2148 this.form.find('.ba-form-map-field .ba-map-wrapper').each(function(){ 2149 this.options = { 2150 map: JSON.parse(this.dataset.map), 2151 marker: JSON.parse(this.dataset.marker), 2152 controls: Boolean(this.dataset.controls * 1), 2153 styleType: this.dataset.styleType 2154 } 2155 if (formsApp.googleMaps || (('google' in window) && google.maps)) { 2156 formsApp.createGoogleMap(this, this.options); 2157 } 2158 }).removeAttr('data-map').removeAttr('data-marker').removeAttr('data-controls').removeAttr('data-style-type'); 2159 this.form.find('.ba-input-password-icons i').on('click', function(){ 2160 let input = this.closest('.ba-field-container').querySelector('input'), 2161 icons = this.closest('.ba-input-password-icons').querySelectorAll('i'); 2162 this.style.display = 'hide'; 2163 if (this.dataset.action == 'show') { 2164 input.type = 'text'; 2165 icons[1].style.display = ''; 2166 } else { 2167 input.type = 'password'; 2168 icons[0].style.display = ''; 2169 } 2170 }); 2171 this.form.find('.ba-form-calendar-field input[type="text"]').each(function(){ 2172 this.rangeBtn = $f(this).closest('.calendar-range-type').find('input[type="text"]').not(this)[0]; 2173 this.hiddenInput = this.closest('.ba-field-container').querySelector('input[type="hidden"]'); 2174 }); 2175 this.form.find('.ba-form-calendar-field input[type="text"]').on('click keyup', function(event){ 2176 FormsAccessibilityHelper.processAction(event, () => { 2177 formsApp.removeAlertTooltip(this); 2178 if (this.rangeBtn && this.dataset.index == 1 && !this.rangeBtn.value) { 2179 this.rangeBtn.click(); 2180 return false;
2181 } 2182 if (!formsApp.calendar) { 2183 formsApp.createCalendar(this); 2184 } 2185 formsApp.calendar.disable = { 2186 days: [], 2187 dates: [], 2188 range: [] 2189 }; 2190 if (this.dataset.disableDays) { 2191 formsApp.calendar.disable.days = this.dataset.disableDays.split(','); 2192 let pos = formsApp.calendar.disable.days.indexOf('0'); 2193 if (this.dataset.start == 1 && pos != -1) { 2194 formsApp.calendar.disable.days[pos] = '7'; 2195 } 2196 } 2197 if (this.dataset.disableDates) { 2198 formsApp.calendar.disable.dates = this.dataset.disableDates.split(','); 2199 } 2200 if (this.dataset.disableRangeDates) { 2201 formsApp.calendar.disable.range = this.dataset.disableRangeDates.split(','); 2202 } 2203 if (this.dataset.disablePrevious == 1) { 2204 formsApp.calendar.classList.add('disable-previous-date'); 2205 } else { 2206 formsApp.calendar.classList.remove('disable-previous-date'); 2207 } 2208 formsApp.calendar.dataset.form = $this.form.attr('data-id'); 2209 formsApp.calendar.start = this.dataset.start; 2210 formsApp.calendar.current = { 2211 year: this.dataset.year, 2212 month: this.dataset.month 2213 } 2214 formsApp.renderFormsCalendar(this); 2215 }) 2216 }).on('input', function(){ 2217 if (this.rangeBtn && this.dataset.index == 0) { 2218 this.rangeBtn.value = ''; 2219 } 2220 this.hiddenInput.price = 0; 2221 if (!this.rangeBtn) { 2222 this.hiddenInput.value = this.value; 2223 } else if (this.rangeBtn && this.dataset.index == 0) { 2224 this.hiddenInput.value = this.value+' - '+this.rangeBtn.value; 2225 } else { 2226 this.hiddenInput.value = this.rangeBtn.value+' - '+this.value; 2227 var date1 = new Date(this.rangeBtn.dataset.value), 2228 date2 = new Date(this.dataset.value); 2229 this.hiddenInput.price = Math.ceil(Math.abs(date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)) 2230 } 2231 formsApp.updateFieldsValues($this.fields, this.hiddenInput, this.hiddenInput.fieldId); 2232 formsApp.checkConditionLogic($this); 2233 formsApp.calculation($this); 2234 }); 2235 this.form.find('.ba-form-address-field input').each(function(){ 2236 this.createAutocomplete = function(){ 2237 let autocomplete = new google.maps.places.Autocomplete(this), 2238 input = this; 2239 autocomplete.addListener('place_changed', function(){ 2240 formsApp.updateFieldsValues($this.fields, input, input.fieldId); 2241 formsApp.checkConditionLogic($this); 2242 }); 2243 } 2244 if (formsApp.googleMaps || (('google' in window) && google.maps)) { 2245 this.createAutocomplete(); 2246 } 2247 }).on('input', function(){ 2248 formsApp.updateFieldsValues($this.fields, this, this.fieldId); 2249 formsApp.checkConditionLogic($this); 2250 }).on('focus', function(){ 2251 formsApp.removeAlertTooltip(this); 2252 }); 2253 this.form.find('.ba-form-slider-field .form-range-wrapper input').each(function(){ 2254 let parent = this.closest('.ba-field-container'); 2255 this.linear = parent.querySelector('.ba-form-range-liner'); 2256 this.number = parent.querySelector('.form-slider-input-wrapper input[data-type="range"]'); 2257 this.input = parent.querySelector('.form-slider-input-wrapper input[type="hidden"][name]'); 2258 this.number.range = this; 2259 }).on('input', function(){ 2260 var max = this.max * 1, 2261 min = this.min * 1, 2262 value = this.value * 1, 2263 sx = (value - min) * 100 / (max - min); 2264 this.input.value = value; 2265 this.number.value = this.value; 2266 this.linear.style.width = sx+'%'; 2267 formsApp.updateFieldsValues($this.fields, this.input, this.input.fieldId); 2268 formsApp.checkConditionLogic($this); 2269 formsApp.calculation($this); 2270 }); 2271 this.form.find('.ba-form-slider-field .form-slider-input-wrapper input[data-type="range"]').on('input', function(){ 2272 var max = this.range.max * 1, 2273 min = this.range.min * 1, 2274 value = this.value * 1; 2275 if (value > max) { 2276 this.value = value = max; 2277 } 2278 if (value >= min) { 2279 this.range.value = value; 2280 $f(this.range).trigger('input'); 2281 } 2282 }); 2283 this.form.find('.ba-form-slider-field .form-slider-wrapper input[type="range"]').each(function(){ 2284 let parent = this.closest('.ba-field-container'); 2285 this.linear = parent.querySelector('.ba-form-range-liner'); 2286 this.slides = parent.querySelectorAll('input[type="range"]'); 2287 this.numbers = parent.querySelectorAll('.form-slider-input-wrapper input[data-type="slider"]');
2288 this.numbers[0].slides = this.slides; 2289 this.numbers[1].slides = this.slides; 2290 this.input = parent.querySelector('.form-slider-input-wrapper input[type="hidden"][name]'); 2291 if (!this.input.values) { 2292 this.input.values = []; 2293 } 2294 this.input.values.push(this.value); 2295 }).on('input', function(){ 2296 var max = this.max * 1, 2297 min = this.min * 1, 2298 ind = this.dataset.index * 1, 2299 index = ind == 0 ? 1 : 0, 2300 value = this.value * 1, 2301 value2 = this.slides[index].value * 1, 2302 sx = left = 0; 2303 if (this.slides[0].value * 1 > this.slides[1].value * 1) { 2304 ind = ind == 0 ? 1 : 0; 2305 index = index == 0 ? 1 : 0; 2306 } 2307 this.input.values[index] = value2; 2308 this.numbers[index].value = value2; 2309 this.numbers[ind].value = value; 2310 this.input.values[ind] = value; 2311 this.input.value = this.input.values[0]+' '+this.input.values[1]; 2312 sx = (this.input.values[1] * 1 - this.input.values[0] * 1) * 100 / (max - min) 2313 left = (max - this.input.values[1] * 1) * 100 / (max - min); 2314 this.linear.style.width = sx+'%'; 2315 this.linear.style.marginLeft = (100 - sx - left)+'%'; 2316 formsApp.updateFieldsValues($this.fields, this.input, this.input.fieldId); 2317 formsApp.checkConditionLogic($this); 2318 }); 2319 this.form.find('.ba-form-slider-field .form-slider-input-wrapper input[data-type="slider"]').on('input', function(){ 2320 let $this = this 2321 clearTimeout(this.delay); 2322 this.delay = setTimeout(function(){ 2323 if ($this.value) { 2324 let value = $this.value * 1, 2325 values = $this.slides[0].input.values, 2326 index = $this.dataset.index * 1; 2327 if (index == 0 && value > values[1] * 1) { 2328 index = 1; 2329 $this.slides[1].numbers[1].focus(); 2330 $this.value = values[1]; 2331 $this.slides[0].input.values[0] = $this.value; 2332 $f($this.slides[0]).val($this.value); 2333 } else if (index == 1 && value < values[0] * 1) { 2334 index = 0; 2335 $this.slides[0].numbers[0].focus(); 2336 $this.value = values[0]; 2337 $this.slides[0].input.values[1] = $this.value; 2338 $f($this.slides[1]).val($this.value); 2339 } 2340 $this.slides[index].value = value; 2341 $f($this.slides[index]).trigger('input'); 2342 } 2343 }, 500); 2344 }); 2345 this.form.find('.ba-form-phone-field').on('click', function(){ 2346 formsApp.removeAlertTooltip(this.querySelector('input.ba-phone-number-input')); 2347 }).on('keyup', '.ba-phone-countries-list-wrapper', function(event){ 2348 if (event.key == 'Escape') { 2349 formsApp.countries.hide(); 2350 } 2351 }).on('click keydown', '.ba-phone-selected-country', function(event){ 2352 if (event.type != 'click' && !(event.type == 'keydown' && event.key == 'ArrowDown')) return; 2353 2354 event.preventDefault(); 2355 let wrapper = this.closest('.ba-phone-countries-wrapper'), 2356 search = wrapper.querySelector('.ba-phone-countries-search'); 2357 setTimeout(function(){ 2358 wrapper.querySelectorAll('li').forEach(function(li){ 2359 li.style.display = ''; 2360 }); 2361 wrapper.classList.remove('top-countries-list'); 2362 wrapper.classList.add('visible-countries-list'); 2363 const countriesList = wrapper.querySelector('.ba-phone-countries-list-wrapper'); 2364 FormsAccessibilityHelper.trapFocus(countriesList); 2365 const rect = wrapper.querySelector('ul').getBoundingClientRect(); 2366 if (window.innerHeight < rect.bottom) { 2367 wrapper.classList.add('top-countries-list'); 2368 } 2369 search.value = ''; 2370 setTimeout(() => { 2371 search.focus(); 2372 }, 50); 2373 $f('body').off('click.selected-country').one('click.selected-country', function(){ 2374 formsApp.countries.hide();; 2375 }); 2376 }, 100); 2377 }).on('input', '.ba-phone-countries-search', function(){ 2378 var li = this.closest('.ba-phone-countries-wrapper').querySelectorAll('li'), 2379 search = this.value.toLowerCase(); 2380 clearTimeout(this.delay); 2381 this.delay = setTimeout(function(){
2382 li.forEach(function(el){ 2383 let title = el.dataset.title.toLowerCase(); 2384 el.style.display = !search || title.indexOf(search) != -1 ? '' : 'none'; 2385 }); 2386 }, 300); 2387 }).on('click', '.ba-phone-countries-search', function(event){ 2388 event.stopPropagation(); 2389 }).on('click keyup', '.ba-phone-countries-list li.ba-phone-country-item', function(event){ 2390 FormsAccessibilityHelper.processAction(event, () => { 2391 event.stopPropagation(); 2392 let wrapper = this.closest('.ba-field-container'); 2393 if (!wrapper.phoneInput) { 2394 wrapper.countryFlag = wrapper.querySelector('.ba-phone-selected-country .ba-phone-flag'); 2395 wrapper.countryPrefix = wrapper.querySelector('.ba-phone-selected-country .ba-phone-prefix'); 2396 wrapper.phoneInput = wrapper.querySelector('input.ba-phone-number-input'); 2397 } 2398 wrapper.countryFlag.className = 'ba-phone-flag ba-phone-flag-'+this.dataset.flag; 2399 wrapper.countryPrefix.textContent = this.dataset.prefix; 2400 wrapper.phoneInput.placeholder = this.dataset.placeholder; 2401 wrapper.phoneInput.value = ''; 2402 wrapper.phoneInput.formsInputMask = this.dataset.placeholder; 2403 wrapper.phoneInput.dataset.prefix = this.dataset.prefix; 2404 wrapper.phoneInput.dispatchEvent(wrapper.phoneInput.inputEvent); 2405 formsApp.prepareInputMask(wrapper.phoneInput, wrapper.phoneInput.formsInputMask); 2406 formsApp.countries.hide(); 2407 }) 2408 }).on('keydown', 'input.ba-phone-number-input', function(event){ 2409 formsApp.prepareInputMask(this, this.formsInputMask, event); 2410 }).on('input', 'input.ba-phone-number-input', function(){ 2411 formsApp.executeInputMask(this, this.formsInputMask); 2412 let value = this.dataset.prefix+' '+this.value, 2413 placeholder = this.dataset.prefix+' '+this.placeholder; 2414 this.hiddenInput.value = this.value && value != placeholder ? value : ''; 2415 this.hiddenInput.dispatchEvent(this.inputEvent); 2416 }).find('input.ba-phone-number-input').each(function(){ 2417 this.prefix = this.dataset.prefix; 2418 this.formsInputMask = this.placeholder; 2419 formsApp.prepareInputMask(this, this.formsInputMask); 2420 this.hiddenInput = this.closest('.ba-field-container').querySelector('input[type="hidden"]'); 2421 this.hiddenInput.addEventListener('input', function(){ 2422 formsApp.updateFieldsValues($this.fields, this, this.fieldId); 2423 formsApp.checkConditionLogic($this); 2424 formsApp.calculation($this); 2425 }); 2426 this.inputEvent = new Event('input'); 2427 }); 2428 this.form.find('.ba-form-input-field > .ba-input-wrapper').find('[data-mask]').each(function(){ 2429 this.formsInputMask = this.dataset.mask.replace(/#/g, '_'); 2430 formsApp.prepareInputMask(this, this.formsInputMask); 2431 }).on('keydown', function(event){ 2432 formsApp.prepareInputMask(this, this.formsInputMask, event); 2433 }).on('input', function(event){ 2434 formsApp.executeInputMask(this, this.formsInputMask); 2435 }); 2436 this.form.find('.characters-wrapper').each(function(){ 2437 let input = this.closest('.ba-field-container').querySelector('input, textarea'); 2438 input.characters = { 2439 div: this, 2440 key: this.dataset.direction, 2441 length: this.dataset.length 2442 } 2443 }); 2444 this.form.find('.ba-form-input-field > .ba-input-wrapper').find('input, textarea').on('input', function(){ 2445 if (this.dataset.validation == 'numbers') { 2446 let match = this.value.match(/\d+\.{0,1}\d{0,}/); 2447 if (!match) { 2448 this.value = ''; 2449 } else if (match[0] != this.value) { 2450 this.value = match[0]; 2451 } 2452 } 2453 if (this.characters) { 2454 let length = this.value.length; 2455 this.characters.div.querySelector('.current-characters').textContent = length; 2456 } 2457 formsApp.updateFieldsValues($this.fields, this, this.fieldId); 2458 formsApp.checkConditionLogic($this); 2459 formsApp.calculation($this); 2460 }).on('focus', function(){ 2461 formsApp.removeAlertTooltip(this); 2462 }); 2463 this.form.find('.ba-form-signature-field textarea').on('input', function(){ 2464 formsApp.updateFieldsValues($this.fields, this, this.fieldId); 2465 formsApp.checkConditionLogic($this); 2466 }); 2467 this.form.find('.confirm-email-wrapper, .confirm-password-wrapper').find('input').on('focus', function(){ 2468 formsApp.removeAlertTooltip(this); 2469 }); 2470 this.form.find('.ba-form-dropdown-field, .ba-form-select-multiple-field').find('select').on('focus', function(){ 2471 formsApp.removeAlertTooltip(this); 2472 }).on('change', function(){ 2473 $this.fields[this.fieldId] = { 2474 value: '', 2475 price: 0 2476 } 2477 formsApp.updateFieldsValues($this.fields, this, this.fieldId); 2478 formsApp.checkConditionLogic($this); 2479 formsApp.calculation($this); 2480 formsApp.checkAutoNavigation($this, this); 2481 if (this.product) { 2482 formsApp.productChange($this, this.name); 2483 } 2484 }); 2485 this.form.find('.ba-form-rating-group-wrapper').on('change', function(){ 2486 formsApp.removeAlertTooltip(this); 2487 let input = this.querySelectorAll('input'); 2488 $this.fields[input[0].fieldId] = { 2489 value: '', 2490 price: 0 2491 } 2492 this.classList.remove('active'); 2493 $f(this).find('label.active').removeClass('active'); 2494 for (let i = 0; i < input.length; i++) { 2495 formsApp.updateFieldsValues($this.fields, input[i], input[i].fieldId); 2496 if (input[i].checked) { 2497 this.classList.add('active'); 2498 input[i].closest('label').classList.add('active'); 2499 } 2500 } 2501 formsApp.checkConditionLogic($this); 2502 formsApp.calculation($this); 2503 formsApp.checkAutoNavigation($this, this); 2504 }); 2505 this.form.find('.ba-form-checkbox-group-wrapper').each(function(){ 2506 if (this.querySelector('.ba-checkbox-image')) { 2507 this.classList.add('checkbox-image-group-wrapper'); 2508 } 2509 let checkbox = this.querySelector('.ba-form-checkbox-wrapper:last-child'); 2510 if (checkbox && !checkbox.classList.contains('last-row-checkbox-wrapper')) { 2511 checkbox.classList.add('last-row-checkbox-wrapper') 2512 } 2513 }).on('change', function(){ 2514 formsApp.removeAlertTooltip(this); 2515 let input = this.querySelectorAll('input'), 2516 name = product = null, 2517 image = this.classList.contains('checkbox-image-group-wrapper'); 2518 $this.fields[input[0].fieldId] = { 2519 value: '', 2520 price: 0 2521 } 2522 if (image) { 2523 $f(this).find('.checked-image-container').removeClass('checked-image-container'); 2524 } 2525 for (let i = 0; i < input.length; i++) { 2526 formsApp.updateFieldsValues($this.fields, input[i], input[i].fieldId);
2527 name = input[i].name; 2528 product = input[i].product; 2529 if (input[i].checked) { 2530 input[i].closest('.ba-form-checkbox-wrapper').classList.add('checked-image-container'); 2531 } 2532 } 2533 formsApp.checkConditionLogic($this); 2534 formsApp.calculation($this); 2535 formsApp.checkAutoNavigation($this, this); 2536 if (product && name) { 2537 formsApp.productChange($this, name); 2538 } 2539 }).find('.ba-form-checkbox-wrapper').on('click', function(event){ 2540 if (!event.target.classList.contains('ba-form-checkbox') && !event.target.closest('.ba-form-checkbox') && 2541 !event.target.closest('.ba-form-radio')) { 2542 $f(this).find('> .ba-checkbox-wrapper input').each(function(){ 2543 if (this.type == 'radio' && !this.checked) { 2544 this.checked = true; 2545 } else if (this.type == 'checkbox') { 2546 this.checked = !this.checked; 2547 } 2548 }).trigger('change'); 2549 } 2550 }); 2551 this.form.find('.ba-form-acceptance-field .ba-field-container').on('change', function(){ 2552 formsApp.removeAlertTooltip(this); 2553 let input = this.querySelector('input'); 2554 $this.fields[input.fieldId] = { 2555 value: '', 2556 price: 0 2557 } 2558 formsApp.updateFieldsValues($this.fields, input, input.fieldId); 2559 formsApp.checkConditionLogic($this); 2560 }); 2561 this.form.find('[data-price]').each(function(){ 2562 this.price = this.dataset.price; 2563 }).removeAttr('data-price'); 2564 this.form.find('[data-field-id]').each(function(){ 2565 this.fieldId = this.dataset.fieldId; 2566 $this.items[this.fieldId] = this.closest('.ba-form-field-item'); 2567 if (this.classList.contains('ba-form-submit-btn')) { 2568 return true; 2569 } 2570 if (!$this.fields[this.fieldId]) { 2571 $this.fields[this.fieldId] = { 2572 value: '', 2573 price: 0 2574 } 2575 } 2576 formsApp.updateFieldsValues($this.fields, this, this.fieldId); 2577 }).removeAttr('data-field-id'); 2578 this.form.find('[data-default]').each(function(){ 2579 let match = this.dataset.default.match(/\[Field ID=\d+\]/) || this.dataset.default.match(/\[Page Title\]/); 2580 match = match || this.dataset.default.match(/\[Page URL\]/); 2581 if (this.dataset.default && match) { 2582 let key = this.fieldId ? this.fieldId : +new Date(), 2583 obj = { 2584 item: this, 2585 value: this.dataset.default 2586 } 2587 defaultValues[key] = obj; 2588 } 2589 }); 2590 this.form.find('.ba-form-calculation-field .field-price-value').each(function(){ 2591 let name = '.ba-form-calculation-price-wrapper'; 2592 this.calculation = $f.extend({}, this.dataset); 2593 this.calculation.result = this; 2594 this.calculation.input = this.closest('.ba-field-container').querySelector('input'); 2595 this.calculation.product = this.closest(name).querySelector('input').dataset.product == 'product'; 2596 for (ind in this.dataset) { 2597 $f(this).removeAttr('data-'+ind) 2598 } 2599 $this.calculation[this.calculation.input.fieldId] = this.calculation; 2600 }); 2601 this.form.find('.ba-form-calculation-field input[type="hidden"]').on('change', function(){ 2602 formsApp.updateFieldsValues($this.fields, this, this.fieldId); 2603 formsApp.checkConditionLogic($this); 2604 if (this.product) { 2605 formsApp.productChange($this, this.name); 2606 } 2607 }); 2608 this.form.find('.ba-form-total-field .ba-cart-total-row .field-price-value').each(function(){ 2609 this.calculation = $f.extend({}, this.dataset); 2610 let calculation = this.calculation, 2611 name = '.ba-cart-subtotal-row .field-price-value'; 2612 calculation.subtotal = this.closest('.ba-cart-total-container').querySelector(name); 2613 calculation.result = this; 2614 calculation.input = this.closest('.ba-form-calculation-price-wrapper').querySelector('textarea'); 2615 calculation.cart = this.closest('.ba-input-wrapper').querySelector('.ba-form-products-cart'); 2616 calculation.products = {}; 2617 calculation.total = 0; 2618 calculation.resultTotal = 0; 2619 name = '.ba-cart-discount-row .field-price-value';
2620 calculation.discount = this.closest('.ba-cart-total-container').querySelector(name); 2621 name = '.ba-cart-tax-row .field-price-value'; 2622 calculation.taxResult = this.closest('.ba-cart-total-container').querySelector(name); 2623 name = '.ba-cart-shipping-row input[type="radio"]'; 2624 calculation.shipping = this.closest('.ba-cart-total-container').querySelectorAll(name); 2625 calculation.shipping.forEach(function(el){ 2626 el.addEventListener('change', function(){ 2627 formsApp.calculateCartTotal(calculation); 2628 }) 2629 }); 2630 $this.carts.push(this); 2631 for (ind in this.dataset) { 2632 $f(this).removeAttr('data-'+ind) 2633 } 2634 }); 2635 this.form.find('.ba-form-total-field textarea').on('change', function(){ 2636 let calc = this.closest('.ba-form-calculation-price-wrapper').querySelector('.field-price-value').calculation; 2637 if ($this.fields[this.fieldId].price != calc.resultTotal) { 2638 $this.fields[this.fieldId] = { 2639 value: calc.resultTotal, 2640 price: calc.resultTotal 2641 } 2642 formsApp.calculation($this, true); 2643 } 2644 }); 2645 2646 this.form.find('.ba-cart-promo-code-btn').each(function(){ 2647 this.promo = { 2648 input: this.closest('.ba-cart-promo-code-container').querySelector('.ba-cart-promo-code-input'), 2649 total: this.closest('.ba-field-container').querySelector('.ba-cart-total-row .field-price-value'), 2650 discount: this.closest('.ba-field-container').querySelector('.ba-cart-discount-row') 2651 } 2652 }).on('click keyup', function(event){ 2653 if (this.status == 'pending') { 2654 return; 2655 } 2656 FormsAccessibilityHelper.processAction(event, () => { 2657 this.status = 'pending'; 2658 let btn = this; 2659 formsApp.fetch.request(JUri+'index.php?option=com_baforms&task=form.checkCoupon', { 2660 coupon: btn.promo.input.value.trim(), 2661 id: btn.dataset.name 2662 }).then(function(text){ 2663 btn.status = ''; 2664 if (!text || !btn.promo.input.value.trim()) { 2665 formsApp.showNotice(formsApp._('PROMO_CODE_NOT_VALID'), 'ba-alert'); 2666 btn.promo.total.calculation.promo = null; 2667 btn.promo.discount.style.display = 'none'; 2668 } else { 2669 btn.promo.total.calculation.promo = JSON.parse(text); 2670 btn.promo.discount.style.display = ''; 2671 } 2672 formsApp.calculateCartTotal(btn.promo.total.calculation); 2673 }); 2674 }) 2675 }) 2676 this.form.find('[data-product]').each(function(){ 2677 if (this.dataset.product) { 2678 this.product = this.dataset.product; 2679 let name = this.name; 2680 if (!$this.products[name]) { 2681 $this.products[name] = []; 2682 } 2683 if (this.localName == 'select') { 2684 this.querySelectorAll('option').forEach(function(option){ 2685 $this.products[name].push(option); 2686 }); 2687 } else { 2688 $this.products[name].push(this); 2689 } 2690 } 2691 }).removeAttr('data-product'); 2692 formsApp.updateFieldsDefaultValues($this, defaultValues); 2693 FormProgressHelper.setSavedProgress($this); 2694 formsApp.checkConditionLogic($this); 2695 formsApp.calculation($this); 2696 formsApp.updateCarts($this); 2697} 2698 2699formsApp.productChange = function($this, name){ 2700 for (let i = 0; i < $this.carts.length; i++) { 2701 if (!$this.carts[i].calculation.products[name]) { 2702 continue; 2703 } 2704 let calculation = $this.carts[i].calculation; 2705 formsApp.updateProducts($this, calculation, name); 2706 } 2707} 2708 2709formsApp.updateCarts = function($this){ 2710 for (let i = 0; i < $this.carts.length; i++) { 2711 let calculation = $this.carts[i].calculation; 2712 for (let name in $this.products) { 2713 if (!calculation.products[name]) { 2714 calculation.products[name] = {}; 2715 } 2716 formsApp.updateProducts($this, calculation, name); 2717 } 2718 } 2719} 2720 2721formsApp.updateProducts = function($this, calculation, name){ 2722 let products = $this.products[name], 2723 object = {}; 2724 for (let i = 0; i < products.length; i++) { 2725 if (products[i].closest('.hidden-condition-field')) { 2726 continue; 2727 } 2728 if (products[i].price != '' && 2729 (((products[i].type == 'radio' || products[i].type == 'checkbox') && products[i].checked) 2730 || (products[i].localName == 'option' && products[i].selected) || products[i].type == 'hidden')) { 2731 let obj = { 2732 key: products[i].dataset.key ?? '0', 2733 input: products[i], 2734 quantity: 1, 2735 title: products[i].dataset.title ? products[i].dataset.title : products[i].value, 2736 price: products[i].price 2737 } 2738 obj.total = obj.price * obj.quantity; 2739 object[i] = obj; 2740 } 2741 } 2742 for (let ind in calculation.products[name]) { 2743 if (!object[ind] || calculation.products[name][ind].input.type == 'hidden') { 2744 calculation.total -= calculation.products[name][ind].total; 2745 if (calculation.cart) { 2746 calculation.cart.querySelector('.ba-form-product-row[data-name="'+name+'"][data-ind="'+ind+'"]').remove(); 2747 } 2748 delete calculation.products[name][ind]; 2749 } 2750 } 2751 for (let ind in object) { 2752 if (!calculation.products[name][ind]) { 2753 if (Number.isNaN(object[ind].total)) { 2754 object[ind].total = 0; 2755 } 2756 calculation.total += object[ind].total; 2757 if (calculation.cart) { 2758 let div = formsApp.getProductCartHTML(object[ind], name, ind, calculation); 2759 calculation.cart.append(div); 2760 } 2761 calculation.products[name][ind] = object[ind]; 2762 } 2763 } 2764 calculation.total = formsApp.decimalAdjust('round', calculation.total, calculation.decimals * -1); 2765 formsApp.calculateCartTotal(calculation); 2766 2767} 2768 2769formsApp.calculateCartTotal = function(calculation){ 2770 let decimals = calculation.decimals, 2771 price = formsApp.renderPrice(String(calculation.total), calculation.thousand, calculation.separator, decimals), 2772 total = calculation.total, 2773 tax = 0, 2774 discount = calculation.promo ? calculation.promo.discount * 1 : 0; 2775 if (calculation.subtotal) { 2776 calculation.subtotal.textContent = price; 2777 } 2778 if (calculation.promo && calculation.promo.unit == '%') { 2779 discount = total * discount / 100; 2780 } 2781 total -= discount; 2782 if (calculation.taxResult) { 2783 tax = total * calculation.tax / 100 2784 price = formsApp.renderPrice(String(tax), calculation.thousand, calculation.separator, decimals) 2785 calculation.taxResult.textContent = price; 2786 } 2787 total += tax; 2788 if (calculation.discount) { 2789 price = formsApp.renderPrice(String(discount), calculation.thousand, calculation.separator, decimals); 2790 calculation.discount.textContent = '-'+price; 2791 } 2792 if (calculation.shipping) { 2793 calculation.shipping.forEach(function(input){ 2794 if (input.checked) { 2795 total += input.price * 1; 2796 } 2797 }); 2798 } 2799 calculation.resultTotal = total; 2800 price = formsApp.renderPrice(String(total), calculation.thousand, calculation.separator, decimals) 2801 calculation.result.textContent = price; 2802 $f(calculation.input).trigger('change'); 2803} 2804 2805formsApp.getProductCartHTML = function(product, name, ind, calculation){ 2806 let div = document.createElement('div'), 2807 decimals = calculation.decimals, 2808 price = formsApp.renderPrice(String(product.total), calculation.thousand, calculation.separator, decimals), 2809 image = product.input.closest('.checkbox-image-wrapper'); 2810 div.className = 'ba-form-product-row'; 2811 div.dataset.name = name; 2812 div.dataset.ind = ind; 2813 div.innerHTML = '<div class="ba-form-product-title-cell">'+product.title+'</div>'+ 2814 '<div class="ba-form-product-quantity-cell"><i class="ba-form-icons ba-icon-minus-circle '+ 2815 (product.quantity == 1 ? 'ba-disabled' : '')+'" data-action="-"></i>'+ 2816 '<input type="number" value="'+product.quantity+'" min="1" step="1">'+ 2817 '<i class="ba-form-icons ba-icon-plus-circle" data-action="+"></i></div>'+ 2818 '<div class="ba-form-product-total-cell"><div class="ba-form-calculation-price-wrapper">'+ 2819 '<span class="field-price-currency">'+calculation.symbol+'</span><span class="field-price-value">'+price+ 2820 '</span></div>'+ 2821 '</div><div class="ba-form-product-remove-cell"><i class="ba-form-icons ba-icon-delete" tabindex="0"></i></div>'; 2822 if (image) { 2823 let img = document.createElement('div'); 2824 img.className = 'ba-form-product-image-cell'; 2825 img.append(image.querySelector('img').cloneNode()); 2826 div.insertBefore(img, div.querySelector('.ba-form-product-title-cell')); 2827 } 2828 let input = div.querySelector('.ba-form-product-quantity-cell input'), 2829 trash = div.querySelector('.ba-form-product-remove-cell i'), 2830 quantityBtns = div.querySelectorAll('.ba-form-product-quantity-cell i[data-action]'); 2831 quantityBtns.forEach(function(element){ 2832 element.addEventListener('click', function(){ 2833 if (this.classList.contains('ba-disabled')) { 2834 return false;
2835 } 2836 if (this.dataset.action == '+') { 2837 input.value = input.value * 1 + 1; 2838 } else { 2839 input.value = input.value * 1 - 1; 2840 } 2841 let event = new Event('input'); 2842 input.dispatchEvent(event); 2843 }); 2844 }); 2845 input.addEventListener('input', function(){ 2846 if (this.value != '') { 2847 quantityBtns[0].classList[this.value == 1 ? 'add' : 'remove']('ba-disabled'); 2848 let match = this.value.match(/\d+/), 2849 decimals = calculation.decimals; 2850 if (!match || match[0] == 0) { 2851 this.value = 1; 2852 } else if (match[0] != this.value) { 2853 this.value = match[0]; 2854 } 2855 if (this.value * 1 > 0) { 2856 calculation.total -= product.total; 2857 product.quantity = this.value * 1; 2858 product.total = product.price * product.quantity; 2859 price = formsApp.renderPrice(String(product.total), calculation.thousand, calculation.separator, decimals); 2860 div.querySelector('.field-price-value').textContent = price; 2861 calculation.total += product.total; 2862 formsApp.calculateCartTotal(calculation); 2863 } 2864 } 2865 }); 2866 $f(trash).on('click keyup', function(event){ 2867 FormsAccessibilityHelper.processAction(event, () => { 2868 if (product.input.type == 'hidden') { 2869 calculation.total -= product.total; 2870 delete calculation.products[name][ind]; 2871 div.remove(); 2872 let decimals = calculation.decimals; 2873 price = formsApp.renderPrice(String(calculation.total), calculation.thousand, calculation.separator, decimals); 2874 calculation.result.textContent = price; 2875 } else { 2876 product.input[product.input.localName == 'option' ? 'selected' : 'checked'] = false; 2877 $f(product.input).trigger('change'); 2878 } 2879 }); 2880 }); 2881 2882 return div; 2883} 2884 2885formsApp.decimalAdjust = function(type, value, exp){ 2886 if (typeof exp === 'undefined' || +exp === 0) { 2887 return Math[type](value); 2888 } 2889 value = +value; 2890 exp = +exp; 2891 if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0)) { 2892 return NaN; 2893 } 2894 value = value.toString().split('e'); 2895 value = Math[type](+(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp))); 2896 value = value.toString().split('e'); 2897 2898 return +(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)); 2899} 2900 2901formsApp.calculation = function($this, fromCart){ 2902 formsApp.calculated = {}; 2903 for (let i in $this.calculation) { 2904 if (fromCart && $this.calculation[i].product) { 2905 continue; 2906 } 2907 let calc = $this.calculation[i], 2908 total = formsApp.calculate(calc.formula, $this), 2909 price = String(total); 2910 total = formsApp.decimalAdjust('round', total, calc.decimals * -1); 2911 price = String(total); 2912 calc.input.price = total; 2913 formsApp.calculated[i] = total; 2914 if (total != calc.input.value * 1) { 2915 price = formsApp.renderPrice(price, calc.thousand, calc.separator, calc.decimals); 2916 calc.input.value = total; 2917 calc.result.textContent = price; 2918 $f(calc.input).trigger('change'); 2919 } 2920 } 2921} 2922 2923formsApp.calculate = function(formula, $this){ 2924 if (formula == '') { 2925 return 0; 2926 } 2927 formula = formula.replace(/\s/g, '').replace(/elseif/g, 'else if'); 2928 let matches = formula.match(/\[FieldID=\d+\]/g), 2929 total = 0; 2930 if (matches) { 2931 for (let i = 0; i < matches.length; i++) { 2932 let match = matches[i].match(/\d+/g), 2933 price = $this.fields['baform-'+match[0]] ? $this.fields['baform-'+match[0]].price : 0; 2934 if (!$this.items['baform-'+match[0]] || $this.items['baform-'+match[0]].closest('.hidden-condition-field')) { 2935 price = 0; 2936 } else if ('baform-'+match[0] in formsApp.calculated) { 2937 price = formsApp.calculated['baform-'+match[0]]; 2938 } else if ($this.calculation['baform-'+match[0]]) { 2939 price = formsApp.calculate($this.calculation['baform-'+match[0]].formula, $this) 2940 formsApp.calculated['baform-'+match[0]] = price; 2941 } 2942 formula = formula.replace(matches[i], price); 2943 } 2944 } 2945 const method = 'ZXZhbA=='; 2946 try { 2947 total = window[window.atob(method)](formula); 2948 } catch (error) { 2949 console.error(error) 2950 } 2951 if (total == -Infinity || total == Infinity || Number.isNaN(total)) { 2952 total = 0; 2953 } 2954 2955 return total; 2956} 2957 2958formsApp.updateFieldsDefaultValues = function($this, defaultValues){ 2959 let object = {}; 2960 for (let ind in defaultValues) { 2961 object[ind] = ''; 2962 object[ind] = formsApp.updateFieldsDefaultValue($this, defaultValues, defaultValues[ind].value, object); 2963 defaultValues[ind].item.value = object[ind]; 2964 } 2965} 2966 2967formsApp.updateFieldsDefaultValue = function($this, defaultValues, value, object){ 2968 let matches = value.match(/\[Field ID=\d+\]/g), 2969 title = $this.querySelector('input[name="page-title"]').value, 2970 url = $this.querySelector('input[name="page-url"]').value; 2971 if (matches) { 2972 for (let i = 0; i < matches.length; i++) { 2973 let match = matches[i].match(/\d+/g), 2974 key = 'baform-'+match[0], 2975 val = $this.fields[key].value; 2976 if (key in object) { 2977 val = object[match[0]]; 2978 } else if (key in defaultValues) { 2979 object[key] = ''; 2980 val = formsApp.updateFieldsDefaultValue($this, defaultValues, defaultValues[key].value, object); 2981 object[key] = val; 2982 } 2983 } 2984 } 2985 value = value.replace(/\[Page Title\]/g, title); 2986 value = value.replace(/\[Page URL\]/g, url); 2987 2988 return value; 2989} 2990 2991formsApp.updateFieldsValues = function(fields, $this, id){ 2992 if ($this.type == 'radio' && $this.checked) { 2993 fields[id] = { 2994 value: $this.value, 2995 price: $this.price * 1 2996 } 2997 } else if ($this.type == 'checkbox' && $this.checked) { 2998 fields[id].value += fields[id].value != '' ? ' '+$this.value : $this.value; 2999 fields[id].price += $this.price * 1; 3000 } else if ($this.localName == 'select') { 3001 $f($this).find('option').each(function(){ 3002 if (this.selected) { 3003 fields[id].value += fields[id].value != '' ? ' '+this.value : this.value; 3004 fields[id].price += this.price * 1; 3005 } 3006 }); 3007 } else if ($this.dataset.calendar) { 3008 fields[id].value = $this.value; 3009 fields[id].price = $this.price * 1; 3010 } else if ($this.type == 'hidden' || $this.type == 'text' || $this.type == 'number' 3011 || $this.localName == 'textarea' || $this.type == 'email') { 3012 fields[id].value = $this.value; 3013 fields[id].price = $this.value.replace(/,/g, '.') * 1; 3014 } else if ($this.type == 'file') { 3015 fields[id].value = ''; 3016 fields[id].price = $this.uploads.count; 3017 $this.closest('.ba-form-upload-field').classList[$this.uploads.count > 0 ? 'add' : 'remove']('has-uploaded-file'); 3018 } 3019 if (String(fields[id].price) == 'NaN') { 3020 fields[id].price = 0; 3021 } 3022} 3023 3024formsApp.checkConditionLogic = function($this){ 3025 $this.pages = {}; 3026 $this.querySelectorAll('.hidden-condition-field').forEach((div) => { 3027 div.classList.remove('hidden-condition-field'); 3028 });
3029 conditionLogic[$this.formId].forEach(function(el){ 3030 if (!el.publish) { 3031 return true; 3032 } 3033 let flags = [], 3034 page = null, 3035 value; 3036 el.when.forEach(function(obj){ 3037 if (!obj.field || !obj.state) { 3038 return true; 3039 } 3040 if (!$this.fields['baform-'+obj.field]) { 3041 return true; 3042 } 3043 page = $this.items['baform-'+obj.field].closest('.ba-form-page'); 3044 if ($this.items['baform-'+obj.field].classList.contains('hidden-condition-field') 3045 || $this.items['baform-'+obj.field].closest('.hidden-condition-field')) { 3046 flags.push(false); 3047 return true; 3048 } 3049 value = $this.fields['baform-'+obj.field].value; 3050 if ($this.items['baform-'+obj.field].dataset.type == 'checkbox' 3051 || $this.items['baform-'+obj.field].dataset.type == 'selectMultiple') { 3052 value = []; 3053 $this.items['baform-'+obj.field].querySelectorAll('input[name], option').forEach(function(input){ 3054 input.checked || input.selected ? value.push(input.value) : ''; 3055 }); 3056 } 3057 switch (obj.state) { 3058 case 'equal': 3059 if (typeof value == 'string') { 3060 flags.push(value == obj.value); 3061 } else { 3062 flags.push(value.indexOf(obj.value) != -1); 3063 } 3064 break; 3065 case 'not-equal': 3066 if (typeof value == 'string') { 3067 flags.push(value != obj.value); 3068 } else { 3069 flags.push(value.indexOf(obj.value) == -1); 3070 } 3071 break; 3072 case 'not-empty': 3073 if (typeof value == 'string') { 3074 flags.push(value != ''); 3075 } else { 3076 flags.push(value.length != 0); 3077 } 3078 break; 3079 case 'empty': 3080 if (typeof value == 'string') { 3081 flags.push(value == ''); 3082 } else { 3083 flags.push(value.length == 0); 3084 } 3085 break; 3086 case 'greater': 3087 flags.push((!isNaN(value) ? value * 1 : value) > (!isNaN(obj.value) ? obj.value * 1 : obj.value)); 3088 break; 3089 case 'less': 3090 flags.push((!isNaN(value) ? value * 1 : value) < (!isNaN(obj.value) ? obj.value * 1 : obj.value)); 3091 break; 3092 case 'contain': 3093 flags.push(value.indexOf(obj.value) != -1); 3094 break; 3095 case 'not-contain': 3096 flags.push(value.indexOf(obj.value) == -1); 3097 break; 3098 } 3099 }); 3100 if (!flags.length) { 3101 return true; 3102 } 3103 let method = el.operation == 'OR' ? 'some' : 'every', 3104 flag = flags[method](function(state){return state}); 3105 el.do.forEach(function(obj){ 3106 if (obj.field && obj.action) { 3107 let item = $this.items['baform-'+obj.field] 3108 || $this.form[0].querySelector('.ba-form-page[data-page-key="'+obj.field+'"]'); 3109 if (!item) { 3110 return true; 3111 } 3112 if (obj.action == 'show' || obj.action == 'hide') { 3113 let method = (obj.action == 'show' && flag) || (obj.action == 'hide' && !flag) ? 'remove' : 'add'; 3114 item.classList[method]('hidden-condition-field'); 3115 item.querySelectorAll('input[name], select[name], textarea[name]').forEach(function(itm){ 3116 if (itm.product) { 3117 formsApp.productChange($this, itm.name); 3118 } 3119 }); 3120 if (item.classList.contains('ba-form-submit-field') && method == 'remove') { 3121 CaptchaHelper.createIfExist(item.querySelector('.ba-form-submit-btn')); 3122 } 3123 } else if (obj.action == 'move' && flag) { 3124 $this.pages[page.dataset.pageKey] = { 3125 prev: page, 3126 next: item 3127 } 3128 let hidden = []; 3129 $f(page).nextAll('.ba-form-page').each(function(){ 3130 if (this == item) { 3131 this.classList.remove('hidden-condition-field'); 3132 return false;
3133 } 3134 this.classList.add('hidden-condition-field'); 3135 hidden.push(this.dataset.pageKey); 3136 }); 3137 $this.pages[page.dataset.pageKey].hidden = hidden; 3138 } 3139 } 3140 }); 3141 $f(window).trigger('scroll'); 3142 }); 3143} 3144 3145formsApp.strrev = function(string){ 3146 var ret = '', i = 0; 3147 for (i = string.length - 1; i >= 0; i--) { 3148 ret += string[i]; 3149 } 3150 3151 return ret; 3152} 3153 3154formsApp.renderPrice = function(value, thousand, separator, decimals){ 3155 let delta = value < 0 ? '-' : '', 3156 priceArray = value.replace('-', '').trim().split('.'), 3157 priceThousand = priceArray[0], 3158 priceDecimal = priceArray[1] ? priceArray[1] : '', 3159 price = ''; 3160 if (priceThousand.length > 3 && thousand != '') { 3161 for (let i = 0; i < priceThousand.length; i++) { 3162 if (i % 3 == 0 && i != 0) { 3163 price += thousand; 3164 } 3165 price += priceThousand[priceThousand.length - 1 - i]; 3166 } 3167 price = formsApp.strrev(price); 3168 } else { 3169 price += priceThousand; 3170 } 3171 if (decimals != 0) { 3172 price += separator; 3173 for (let i = 0; i < decimals; i++) { 3174 price += priceDecimal[i] ? priceDecimal[i] : '0'; 3175 } 3176 } 3177 3178 return delta + price; 3179} 3180 3181function formsHCaptchaOnload() { 3182 CaptchaFactory.get('hcaptcha').setCaptcha(hcaptcha); 3183} 3184 3185function formsTurnstileOnload() { 3186 CaptchaFactory.get('turnstile').setCaptcha(turnstile); 3187} 3188 3189class FormsCaptcha { 3190 static captcha = null; 3191 static loaded = false; 3192 static type = ''; 3193 static src = ''; 3194 static settings = { 3195 site_key: '', 3196 secret_key: '' 3197 } 3198 static data = {}; 3199 3200 static setCaptcha(captcha) { 3201 this.captcha = captcha; 3202 this.loaded = true; 3203 this.init(); 3204 } 3205 3206 static loadSettings() { 3207 formsApp.fetch.request(JUri + 'index.php?option=com_baforms&task=form.loadCaptchaSettings', { 3208 type: this.type 3209 }).then(text => { 3210 const settings = JSON.parse(text); 3211 this.setSettings(settings); 3212 this.createScript(); 3213 document.head.append(this.script); 3214 }); 3215 } 3216 3217 static setSettings(settings) { 3218 this.settings = settings; 3219 } 3220 3221 static check(id) { 3222 return app.items[id] && app.items[id].recaptcha == this.type; 3223 } 3224 3225 static createScript() { 3226 this.script = document.createElement('script'); 3227 this.script.src = this.src; 3228 } 3229 3230 static load() { 3231 if (this.loaded) { 3232 this.init(); 3233 } else if (!this.loaded && !this.loading) { 3234 this.loading = true; 3235 this.loadSettings(); 3236 } 3237 } 3238 3239 static init() { 3240 document.querySelectorAll(`.ba-form-submit-btn[data-captcha="${this.type}"]`).forEach(btn => { 3241 this.create(btn); 3242 }); 3243 } 3244 3245 static create(btn) { 3246 if (!this.loaded) { 3247 return; 3248 } 3249 3250 const element = btn.closest('.ba-form-submit-field'); 3251 if (element.offsetHeight == 0 || element.rendered) { 3252 return; 3253 } 3254 3255 this.set(element); 3256 } 3257 3258 3259 static set(element) { 3260 const div = document.createElement('div'); 3261 const parent = element.querySelector('.ba-form-submit-recaptcha-wrapper'); 3262 div.id = `forms-recaptcha-${Date.now()}`; 3263 div.className = 'forms-recaptcha'; 3264 div.dataset.captcha = this.type; 3265 parent.append(div); 3266 this.render(div); 3267 element.rendered = true; 3268 } 3269 3270 static render(div) { 3271 3272 } 3273 3274 static get(key) { 3275 return this.settings[key]; 3276 } 3277 3278 static async getResponse(id, element) { 3279 return new Promise(resolve => { 3280 resolve(''); 3281 }) 3282 } 3283} 3284 3285class FormsTurnstileCaptcha extends FormsCaptcha { 3286 static src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?onload=formsTurnstileOnload'; 3287 static type = 'turnstile'; 3288 3289 static async getResponse(id, element) { 3290 return new Promise(resolve => { 3291 resolve(!this.captcha.isExpired(id) ? this.captcha.getResponse(id) : ''); 3292 }) 3293 } 3294 3295 static render(div) { 3296 FormsCaptcha.data[div.id] = this.captcha.render(div, { 3297 sitekey: this.settings.site_key, 3298 theme: this.settings.theme, 3299 size: this.settings.size, 3300 callback: CaptchaHelper.clearAlerts 3301 }); 3302 } 3303 3304 static reset(id) { 3305 const widgetId = FormsCaptcha.data[id]; 3306 this.captcha.reset(widgetId); 3307 } 3308} 3309 3310class FormsHCaptcha extends FormsCaptcha { 3311 static src = 'https://js.hcaptcha.com/1/api.js?onload=formsHCaptchaOnload'; 3312 static type = 'hcaptcha'; 3313 3314 static async getResponse(id, element) { 3315 if (!this.settings.invisible) { 3316 return await this.captcha.getResponse(id); 3317 } 3318 3319 const token = await this.captcha.getResponse(); 3320 if (!token) { 3321 await this.captcha.execute(id); 3322 } 3323 3324 return await this.captcha.getResponse(); 3325 } 3326 3327 static render(div) { 3328 const size = this.settings.invisible ? 'invisible' : 'normal' 3329 div.dataset.size = size; 3330 FormsCaptcha.data[div.id] = this.captcha.render(div, { 3331 sitekey: this.settings.site_key, 3332 theme: this.settings.theme, 3333 size: size, 3334 callback: CaptchaHelper.clearAlerts 3335 }); 3336 } 3337} 3338 3339class FormsGoogleRecaptcha extends FormsCaptcha { 3340 static src = 'https://www.google.com/recaptcha/api.js?render='; 3341 static type = 'grecaptcha'; 3342 3343 static createScript() { 3344 super.createScript(); 3345 this.script.src = this.src + this.settings.site_key; 3346 this.script.onload = () => { 3347 grecaptcha.ready(function () { 3348 CaptchaFactory.get('grecaptcha').setCaptcha(grecaptcha); 3349 }); 3350 } 3351 } 3352 3353 static async getResponse(id, element) { 3354 return new Promise(resolve => { 3355 this.execute().then(token => { 3356 element.innerHTML = `<input type="hidden" name="g-recaptcha-response" value="${token}">`; 3357 resolve(token); 3358 }); 3359 }) 3360 } 3361 3362 static render(div) { 3363 this.execute() 3364 } 3365 3366 static async execute() { 3367 return await this.captcha.execute(this.settings.site_key, { 3368 action: 'submit' 3369 }) 3370 } 3371} 3372 3373class CaptchaFactory { 3374 /** @type {Object<string, typeof FormsCaptcha>} */ 3375 static map = { 3376 hcaptcha: FormsHCaptcha, 3377 turnstile: FormsTurnstileCaptcha, 3378 grecaptcha: FormsGoogleRecaptcha 3379 } 3380 3381 /** @param {string} key */ 3382 static has(key) { 3383 return key in this.map; 3384 } 3385 3386 /** 3387 * @param {string} key 3388 * @returns {typeof FormsCaptcha} 3389 */ 3390 static get(key) { 3391 return this.map[key]; 3392 } 3393} 3394 3395class CaptchaHelper { 3396 static getIfExist(element) { 3397 const captcha = element.dataset.captcha; 3398 if (!captcha || !CaptchaFactory.has(captcha)) { 3399 return null; 3400 } 3401 3402 return CaptchaFactory.get(captcha) 3403 } 3404 3405 static loadIfExist() { 3406 document.querySelectorAll('.ba-form-submit-btn').forEach(btn => { 3407 const captcha = this.getIfExist(btn); 3408 if (captcha) { 3409 captcha.load(); 3410 } 3411 }); 3412 } 3413 3414 static createIfExist(btn) { 3415 const captcha = this.getIfExist(btn); 3416 if (captcha) { 3417 captcha.create(btn); 3418 } 3419 } 3420 3421 static async isValidResponse(element) { 3422 if (!CaptchaFactory.has(element.dataset.captcha)) { 3423 return; 3424 } 3425
3426 const widgetId = FormsCaptcha.data[element.id]; 3427 const captcha = CaptchaFactory.get(element.dataset.captcha); 3428 const response = await captcha.getResponse(widgetId, element); 3429 const isValid = response != ''; 3430 formsApp.toggleAlertTooltip(!isValid, element, element, 'THIS_FIELD_REQUIRED'); 3431 3432 return isValid; 3433 } 3434 3435 static async checkResponse(btn) { 3436 let isValid = true; 3437 const recaptcha = btn.closest('.ba-form-submit-wrapper').querySelector('.forms-recaptcha'); 3438 if (recaptcha) { 3439 isValid = await CaptchaHelper.isValidResponse(recaptcha); 3440 } 3441 3442 return isValid; 3443 } 3444 3445 static clearAlerts() { 3446 $f('.forms-recaptcha').each(function () { 3447 formsApp.removeAlertTooltip(this); 3448 }); 3449 } 3450} 3451 3452formsApp.executeInputMask = function(input, mask){ 3453 let n = input.beforeData.start + Math.abs(input.beforeData.value.length - input.value.length), 3454 pos = mask.indexOf('_'), 3455 text = [], 3456 delData = [], 3457 start = null, 3458 updateStart = null, 3459 value = mask; 3460 if (input.value.length > input.beforeData.value.length || input.value.length == input.beforeData.value.length) { 3461 let i = 0; 3462 for (i; i < input.beforeData.start; i++) { 3463 if (mask[i] == '_' && /\d/.test(input.beforeData.value[i])) { 3464 text.push(input.beforeData.value[i]); 3465 } 3466 } 3467 i = input.beforeData.start; 3468 n = input.value.length > input.beforeData.value.length ? n : input.beforeData.end; 3469 for (i; i < n; i++) { 3470 if (/\d/.test(input.value[i])) { 3471 text.push(input.value[i]); 3472 } 3473 } 3474 start = pos; 3475 for (i = 0; i < text.length; i++) { 3476 start = mask.indexOf('_', start + 1); 3477 if (start == -1) { 3478 start = mask.length; 3479 } 3480 } 3481 for (i = input.beforeData.end; i < input.beforeData.value.length; i++) { 3482 if (mask[i] == '_' && /\d/.test(input.beforeData.value[i])) { 3483 text.push(input.beforeData.value[i]); 3484 } 3485 } 3486 } else if (input.beforeData.start == 0 && input.beforeData.end == mask.length) { 3487 for (let i = 0; i < input.value.length; i++) { 3488 if (/\d/.test(input.value[i])) { 3489 text.push(input.value[i]); 3490 } 3491 } 3492 updateStart = true; 3493 } else if (input.beforeData.start < input.selectionStart) { 3494 let i = 0; 3495 for (i; i < input.selectionStart; i++) { 3496 if (mask[i] == '_' && /\d/.test(input.value[i])) { 3497 text.push(input.value[i]); 3498 } 3499 } 3500 start = i; 3501 for (let j = input.beforeData.end; j < input.beforeData.value.length; j++) { 3502 if (mask[j] == '_' && /\d/.test(input.beforeData.value[j])) { 3503 text.push(input.beforeData.value[j]); 3504 } 3505 } 3506 } else { 3507 let i = input.selectionStart < input.beforeData.start ? input.selectionStart : input.beforeData.start; 3508 n = input.selectionStart < input.beforeData.start ? input.beforeData.start : n; 3509 for (i; i < n; i++) { 3510 delData.push(i); 3511 } 3512 } 3513 if (delData.length == 1 && mask[delData[0]] != '_' && input.selectionStart < input.beforeData.start) { 3514 for (let i = input.selectionStart; i >= 0; i--) { 3515 if (mask[i] == '_') { 3516 delData[0] = i; 3517 break; 3518 } 3519 } 3520 } else if (delData.length == 1 && mask[delData[0]] != '_') { 3521 for (let i = input.selectionStart; i < mask.length; i++) { 3522 if (mask[i] == '_') { 3523 delData[0] = i; 3524 break; 3525 } 3526 } 3527 } 3528 if (delData.length) { 3529 start = delData[0]; 3530 for (let i = 0; i < input.beforeData.value.length; i++) { 3531 if (delData.indexOf(i) == -1 && mask[i] == '_') { 3532 text.push(input.beforeData.value[i]); 3533 } 3534 } 3535 } 3536 input.value = value; 3537 text.forEach(function(el){ 3538 if (pos != -1) { 3539 input.setSelectionRange(pos, ++pos); 3540 input.setRangeText(el); 3541 if (updateStart) { 3542 start = pos; 3543 } 3544 } 3545 pos = input.value.indexOf('_'); 3546 }); 3547 if (start !== null) { 3548 input.setSelectionRange(start, start); 3549 } 3550} 3551 3552formsApp.prepareInputMask = function(input, mask, event){ 3553 let value = input.value ? input.value : mask; 3554 if (event) { 3555 input.beforeData = { 3556 start: input.selectionStart, 3557 end: input.selectionEnd, 3558 value: value 3559 }; 3560 } else { 3561 input.beforeData = { 3562 start: 0, 3563 end: 0, 3564 value: value 3565 }; 3566 input.value = value; 3567 } 3568} 3569 3570formsApp.executeMask = function(input, mask){ 3571 let i = 0, 3572 flag = true, 3573 value = ''; 3574 for (i = 0; i < input.value.length; i++) { 3575 flag = input.value[i] == mask[i] || mask[i] == '#' && /\d/.test(input.value[i]) 3576 if (flag) { 3577 value += input.value[i]; 3578 } else { 3579 break; 3580 } 3581 } 3582 if (!flag) { 3583 let subValue = input.value.substr(i), 3584 match = subValue.match(/\d+/), 3585 ind = 0; 3586 for (i; i < mask.length; i++) { 3587 if (mask[i] != '#') { 3588 value += mask[i]; 3589 } else if (match && match[0][ind]) { 3590 value += match[0][ind++]; 3591 } else { 3592 break; 3593 } 3594 } 3595 input.value = value; 3596 } 3597} 3598 3599formsApp.sortPoll = function(field){ 3600 let array = Array.apply(null, field.querySelectorAll('.ba-form-checkbox-wrapper')), 3601 last = null, 3602 count = field.style.getPropertyValue('--checkbox-field-count') * 1, 3603 index = 1; 3604 array.sort(function(a, b){ 3605 if (a.style.getPropertyValue('--poll-order') * 1 > b.style.getPropertyValue('--poll-order') * 1) { 3606 return 1; 3607 } else if (a.style.getPropertyValue('--poll-order') * 1 < b.style.getPropertyValue('--poll-order') * 1) { 3608 return -1; 3609 } else { 3610 return 0; 3611 } 3612 }); 3613 array.forEach(function(div){ 3614 if (index == count) { 3615 div.classList.add('last-row-checkbox-wrapper'); 3616 index = 0; 3617 } else { 3618 div.classList.remove('last-row-checkbox-wrapper'); 3619 } 3620 index++; 3621 }); 3622 last = array.pop(); 3623 last ? last.classList.add('last-row-checkbox-wrapper') : ''; 3624} 3625 3626formsApp.refreshToken = async function(){ 3627 const endPoint = `${JUri}index.php?option=com_baforms&task=form.getFormToken`; 3628 const token = await formsApp.fetch.request(endPoint); 3629 this.token = token.trim(); 3630} 3631 3632document.addEventListener('DOMContentLoaded', formsApp.createForms); 3633if (document.readyState == 'complete') { 3634 formsApp.createForms(); 3635}
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.