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