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