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