https://be-fibre.co.uk/wp-content/plugins/anp-order-journey/resour…?ver=1.5.50.17353200%201790761963
1(function( altnetOrderJourney, $, undefined ) { 2 3/* Go! 4---------------------------------------*/ 5 6var _checkoutForm; 7var _bookingCalendar; 8 9$(function () 10{ 11 _checkoutForm = $('#anp-order-journey-form'); 12 13 if (_checkoutForm.length) { 14 initCheckout(); 15 } 16 17 _bookingCalendar = $('#anp-booking-calendar'); 18 19 if (_bookingCalendar.length) { 20 initCalendar(); 21 } 22 23 var productSelection = $('#anp-product-selection'); 24 25 if (productSelection.length) { 26 initProductSelection(); 27 } 28 29 initAddressSearch(); 30 initRegisterContactForm(); 31 initProductCategorySwitchers(); 32 initSurveys(); 33 initInputs(); 34 initTracking(); 35 initOneTouchSwitch(); 36 initPaymentDetails(); 37 initCoupons(); 38 initInputPlaceholders(); 39 40 // Focus effects 41 42 $('.anp-parent-focus').each(function(){ 43 var element = $(this); 44 var parent = element.closest('.anp-parent-focus-parent'); 45 var activeClass = 'focused'; 46 47 element.focus(function(){ 48 parent.addClass(activeClass); 49 }); 50 51 element.blur(function(){ 52 parent.removeClass(activeClass); 53 }); 54 }); 55 56 // Mouseover effects 57 58 var mouseovers = $('.anp-mouseover'); 59 60 mouseovers.bind('mouseenter', function () { 61 $(this).addClass('anp--over'); 62 }); 63 64 mouseovers.bind('mouseleave', function () { 65 $(this).removeClass('anp--over'); 66 }); 67 68 // Products 69 70 $('.anp-showcase, .anp-new-showcase').bind('click', function(){ 71 var link = $(this).data('link'); 72 document.location.href= link; 73 }); 74 75 $('.anp-showcase__footnote').matchHeight(); 76 77 initProductShowcaseCarousels(); 78 79 // Payment 80 81 $('.anp-change-billing').click(function(){ 82 $('#anp-payment-billing-address').toggleClass('anp-toggleable--active'); 83 return false; 84 }); 85 86 // Terms 87 88 $('.anp-terms--embedded a').click(function(){ 89 var href = $(this).attr('href'); 90 window.open(href); 91 return false; 92 }); 93 94 $('.anp-checkout-terms-trigger').click(function (){ 95 var wrapper = $('#anp-checkout-terms-wrapper'); 96 97 if (wrapper.length) { 98 99 if (wrapper.is(':visible')) { 100 wrapper.hide(); 101 } else { 102 wrapper.show(); 103 scrollToElement(wrapper); 104 } 105 106 } 107 108 return false; 109 }); 110 111 // Read more 112 113 $('.anp-read-more').click(function(){ 114 var element = $(this); 115 var target = element.parent().find('.anp-read-more-reveal'); 116 117 if (target) { 118 target.show(); 119 element.hide(); 120 } 121 122 return false; 123 }); 124 125 // 126 127 $('.anp-restart-confirm').click(function(){ 128 return confirm('Are you sure? You\'ll have to restart your order from the beginning.'); 129 }); 130 131 var sidebarHeight = $('#anp-sidebar').outerHeight(); 132 133 $('#anp-journey-wrapper').css('min-height', sidebarHeight + 'px'); 134 135 $('#anp-is-corporate').change(function(){ 136 var section = $('#anp-corporate-fields'); 137 138 if ($(this).is(':checked')) { 139 section.show(); 140 } else { 141 section.hide(); 142 } 143 }); 144 145 $('.anp-button-bar--relocate').each(function(){ 146 var bar = $(this); 147 var parent = bar.closest('.altnet'); 148 149 if (parent) { 150 bar.appendTo(parent) 151 } 152 }); 153 154 scrollToError(); 155}); 156 157/* CookieBot 158---------------------------------------*/ 159 160if (typeof Cookiebot != 'undefined') { 161 var doNotTrack = $('body').hasClass('anp-do-not-track'); 162 163 if (doNotTrack) { 164 Cookiebot.withdraw(); 165 Cookiebot.hide(); 166 } 167} 168 169/* Address Search 170---------------------------------------*/ 171 172var _addressSelectElement; 173var _addressResultsWrapper; 174 175var _addressSearchResults; 176var _addressSearchPage; 177 178var _addressesLoading; 179var _addressProductLineSelect; 180var _addressProductLineInput; 181 182function initAddressSearch() { 183 184 initFormAddressSearches(); 185 initAddressAutoCompletes(); 186 187 if ($('#anp-postcoder-search').length) { 188 initAddressSearchForm(); 189 } 190 191 $('#anp-postcoder-confirm').click(function() { 192 toggleSpinner(true); 193 var form = $('#anp-postcoder-form'); 194 form.submit(); 195 return false; 196 }); 197
198 $('.anp-postcoder-help').click(function(){ 199 if (typeof window.fcWidget != 'undefined') { 200 window.fcWidget.open(); 201 } else { 202 window.open('/contact'); 203 } 204 205 return false; 206 }); 207 208 _addressProductLineSelect = $('#anp-postcoder-product-line'); 209 _addressProductLineInput = $('#anp-postcoder-product-line-input'); 210 211 _addressProductLineSelect.change(function() { 212 _addressProductLineInput.val($(this).val()); 213 }); 214}; 215 216const debouncedAddressLookup = debounce(submitAddressSearchForm, 400); 217 218function initAddressSearchForm() { 219 220 _addressSelectElement = $('#anp-postcoder-address'); 221 _addressResultsWrapper = $('#anp-postcoder-results'); 222 223 $('#anp-postcoder-submit').click(function() { 224 submitAddressSearchForm(); 225 return false; 226 }); 227 228 const input = document.getElementById('anp-postcoder-partial-address'); 229 230 if (!input) { 231 return false; 232 } 233 234 let lastLookupValue = ''; 235 236 input.addEventListener('input', function (e) { 237 const el = e.target; 238 let cleaned = el.value.replace(/[^a-z0-9]/gi, ''); 239 240 cleaned = cleaned.slice(0, 7); 241 242 if (cleaned !== el.value) { 243 el.value = cleaned; 244 } 245 246 if (cleaned !== lastLookupValue) { 247 if (cleaned.length > 5) { 248 debouncedAddressLookup(); 249 } 250 251 lastLookupValue = cleaned; 252 } 253 }); 254 255 $('#anp-postcoder-new-search').click(function() { 256 $('.anp-postcoder-hidden').hide(); 257 $('.anp-postcoder-has-addresses').removeClass('anp-postcoder-has-addresses'); 258 $('#anp-postcoder-partial-address').val(''); 259 $('#anp-postcoder-partial-address').focus(); 260 return false; 261 }); 262 263 $('#anp-postcoder-partial-address').keydown(function(e){ 264 265 if(e.which == 13){ 266 submitAddressSearchForm(); 267 return false; 268 } 269 }) 270 271 _addressSelectElement.change(onAddressSelectChange); 272 273 var preloadedAddresses = anpPostcodeAddressData; 274 275 if (preloadedAddresses && preloadedAddresses.data) { 276 _addressSearchResults = preloadedAddresses.data; 277 showAddressSearchResults(); 278 } else { 279 $('.anp-postcoder-has-addresses').removeClass('anp-postcoder-has-addresses'); 280 } 281} 282 283function submitAddressSearchForm() 284{ 285 var address = getSearchAddress(); 286 287 if (address.length >= 3) { 288 _addressSearchPage = 0; 289 submitAddressSearch(); 290 } 291} 292 293function submitAddressSearch() { 294 $('.anp-postcoder-hidden').hide(); 295 296 addressApiSearch( getSearchAddress(), _addressSearchPage ); 297} 298 299function addressApiSearch( address, page, callback ) { 300 301 if (_addressesLoading) { 302 return false; 303 } 304 305 if (!address.length) { 306 return false 307 } 308 309 submitAddressSearchRequest(address, page, true, onAddressSearchComplete); 310} 311 312function submitAddressSearchRequest(address, page, cache, callback) 313{ 314 _addressesLoading = true; 315 316 $.ajax({ 317 headers: { 'X-WP-Nonce': window.wpRestNonce }, 318 type: 'POST', 319 url: '/wp-json/altnet/v1/addresses/search', 320 dataType: 'json', 321 data: { address: address, page: page, path: window.location.pathname, cache: cache ? 1 : 0 }, 322 complete: function(response){ 323 _addressesLoading = false; 324 callback(response.responseJSON); 325 } 326 }); 327 328 toggleSpinner(true); 329} 330 331function onAddressSearchComplete(json) 332{ 333 if (!json['success']) { 334 alert('An error occurred. Please try again shortly.'); 335 return; 336 } 337 338 _addressSearchResults = json.data; 339 340 showAddressSearchResults(); 341 toggleSpinner(false); 342} 343 344function showAddressSearchResults() { 345 _addressSelectElement.empty(); 346 347 addSearchSelectOption('', 'Select an address'); 348 349 var addresses = _addressSearchResults; 350 var currentUPRN = $('#anp-postcoder-input-uprn').val(); 351 352 if (addresses && addresses.length) { 353 for (var a in addresses) { 354 var address = addresses[a]; 355 356 addSearchSelectOption(a, address['summaryline'], address['uprn'] == currentUPRN); 357 358 if (address['morevalues'] == 'true') { 359 addSearchSelectOption('more', 'Load more addresses...'); 360 } 361 } 362 363 _addressResultsWrapper.show(); 364 } else { 365 $('#anp-postcoder-no-results').fadeIn(); 366 } 367} 368 369function addSearchSelectOption(key, value, selected) { 370 _addressSelectElement.append('<option value="' + key + '"' + (selected ? ' selected' : '') + '>
370' + value + '</option>'); 371} 372 373function onAddressSelectChange() { 374 var selected = _addressSelectElement.val(); 375 376 if ( typeof _addressSearchResults[selected] != 'undefined' ) { 377 showAddressSearchConfirmation(_addressSearchResults[selected]); 378 } else if ('more' == selected){ 379 _addressSearchPage++; 380 submitAddressSearch(); 381 } else { 382 $('#anp-postcoder-footer').hide(); 383 } 384} 385 386function showAddressSearchConfirmation(selectedAddress) { 387 var addressHTML = ''; 388 var addressFields = ['address1', 'address2', 'posttown', 'postcode']; 389 390 for (var i in addressFields) { 391 var line = selectedAddress[addressFields[i]]; 392 393 if (line != null && line.length > 1) { 394 addressHTML += line + '<br />'; 395 } 396 } 397 398 for (var key in selectedAddress) { 399 var inputElement = $('#anp-postcoder-input-' + key); 400 401 if (inputElement.length) { 402 inputElement.val(selectedAddress[key]); 403 } 404 } 405 //$('#anp-selected-address').html(addressHTML); 406 $('#anp-postcoder-footer').show(); 407} 408 409function getSearchAddress() { 410 return $('#anp-postcoder-partial-address').val(); 411} 412 413function initFormAddressSearches() { 414 415 var postcodeFields = $('.anp-postcoder-adhoc-postcode'); 416 417 postcodeFields.each(function(){ 418 var postcodeField = $(this); 419 var form = postcodeField.closest('form'); 420 421 if (form.length) { 422 initFormAddressSearch(form); 423 } 424 }); 425} 426 427function initFormAddressSearch(form) 428{ 429 var fields = ['postcode', 'uprn', 'address1', 'address2']; 430 var inputs = []; 431 432 for (var i in fields) { 433 var fieldName = fields[i]; 434 var input = form.find('.anp-postcoder-adhoc-' + fieldName); 435 436 if (input.length) { 437 inputs[fieldName] = input; 438 } 439 } 440 441 if (!inputs.uprn || !inputs.postcode) { 442 return; 443 } 444 445 inputs.postcode.change(function(){ 446 var postcode = $(this).val(); 447 448 if (postcode.length > 3) { 449 450 submitAddressSearchRequest(postcode, 0, false, function (json) { 451 var addresses = json.data; 452 var uprnInput = inputs.uprn; 453 454 toggleSpinner(false); 455 456 uprnInput.empty(); 457 uprnInput.off(); 458 459 for (var i in addresses) { 460 var address = addresses[i]; 461 462 uprnInput.append($('<option>', { 463 value: address.uprn, 464 text: address.summaryline 465 })); 466 } 467 468 uprnInput.change(function(){ 469 var uprn = $(this).val(); 470 471 for (var i in addresses) { 472 var address = addresses[i]; 473 474 if (address.uprn == uprn) { 475 if (inputs.address1) { 476 inputs.address1.val(address.address1); 477 } 478 479 if (inputs.address2) { 480 inputs.address2.val(address.address2); 481 } 482 } 483 } 484 }) 485 }); 486 } 487 }); 488} 489 490// AUTOCOMPLETE 491 492const debouncedAutocompleteLookup = debounce(autocompleteLookup, 400); 493 494function initAddressAutoCompletes() 495{ 496 const forms = document.querySelectorAll('.anp-address-autocomplete-form'); 497 498 forms.forEach(form => { 499 500 const input = form.querySelector('.anp-address-autocomplete'); 501 const resultsContainer = form.querySelector('.anp-address-select-addresses'); 502 const spinner = form.querySelector('.anp-address-spinner'); 503 504 const actionInput = form.querySelector('.anp-address-autocomplete-action'); 505 const uprnInput = form.querySelector('.anp-address-autocomplete-uprn'); 506 507 let lastLookupValue = ''; 508 509 input.addEventListener('input', function (e) { 510 const el = e.target; 511 let cleaned = el.value.replace(/[^a-z0-9]/gi, ''); 512 513 cleaned = cleaned.slice(0, 7); 514 515 if (cleaned !== el.value) { 516 el.value = cleaned; 517 } 518 519 if (cleaned !== lastLookupValue) { 520 debouncedAutocompleteLookup(cleaned, resultsContainer, spinner); 521 lastLookupValue = cleaned; 522 } 523 }); 524 525 form.addEventListener('keydown', function (e) { 526 if (e.key === 'Enter' && e.target.tagName.toLowerCase() !== 'textarea') { 527 e.preventDefault(); 528 } 529 }); 530 531 resultsContainer.addEventListener('click', (e) => { 532 const option = e.target.closest('li'); 533 const uprn = option.getAttribute('data-uprn'); 534 535 actionInput.value = 'after_autocomplete'; 536 uprnInput.value = uprn; 537 538 resultsContainer.style.display = 'none'; 539 spinner.style.display = 'block'; 540 541 form.submit(); 542 }); 543 }); 544} 545 546function autocompleteLookup(address, resultsContainer, spinner) 547{ 548 if (address.length < 6) { 549 resultsContainer.style.display = 'none'; 550 return; 551 } 552 553 spinner.style.display = 'block'; 554 555 submitAddressSearchRequest(address, 0, false, function(response) { 556 spinner.style.display = 'none'; 557 onAutoCompleteLookupComplete(response, resultsContainer); 558 }); 559} 560 561function onAutoCompleteLookupComplete(response, resultsContainer) { 562 resultsContainer.style.display = 'block'; 563 564 resultsContainer.innerHTML = ''; 565 566 if (response.data && response.data.length > 0) { 567 resultsContainer.style.display = 'block'; 568 response.data.forEach((suggestion, index) => { 569 const option = document.createElement('li'); 570 option.textContent = suggestion.summaryline; 571 option.setAttribute('data-uprn', suggestion.uprn); 572 resultsContainer.appendChild(option); 573 }); 574 575 } else { 576 resultsContainer.style.display = 'none'; 577 } 578} 579 580/* Checkout Form 581---------------------------------------*/ 582 583function initCheckout() 584{ 585 // Next button 586 587 $('#anp-checkout-next-trigger').click(function () { 588 var step = $('#anp-order-journey-step').val();
589 var validates = true; 590 591 if ('book_installation' == step) { 592 validates = bookInstallationValidation(); 593 } else if ('purchase_products' == step) { 594 validates = productSelectionValidation(); 595 } else { 596 validates = validateCheckoutForm(); 597 } 598 599 if (validates) { 600 601 if ('contact_details' == step && $('#anp-data-layer-postcode').length && $('#anp-track-eligible-lead').length ) { 602 var dlPostcode = $('#anp-data-layer-postcode').val(); 603 var dlAction = $('#anp-data-layer-action').val(); 604 var dlType = $('#anp-data-layer-type').val(); 605 var dlProductLine = $('#anp-data-layer-product_line').val(); 606 var dlSplitTest = $('#anp-data-layer-journey_split').val(); 607 608 trackNewLeadEvent(dlPostcode, dlProductLine, dlType, dlAction, dlSplitTest, function() { 609 _checkoutForm.submit(); 610 }) 611 } else { 612 _checkoutForm.submit(); 613 } 614 615 toggleSpinner(true); 616 } 617 618 return false; 619 }); 620 621 // Direct Debit 622 623 var sortCodeInput = $('#checkout_billing_sort_code'); 624 625 if (sortCodeInput.length) { 626 sortCodeInput.val(formatBillingSortCode(sortCodeInput.val())); 627 628 sortCodeInput.keyup(onBillingSortCodeChange); 629 sortCodeInput.blur(onBillingSortCodeChange); 630 } 631 632 $('.anp-dd-guarantee-trigger').click(function(){ 633 var guarantee = $('#anp-checkout-dd-guarantee'); 634 635 if (guarantee.is(':visible')) { 636 guarantee.hide(); 637 } else { 638 guarantee.show(); 639 scrollToElement(guarantee); 640 } 641 642 return false; 643 }); 644 645 $('#anp-custom-billing-address').change(function(){ 646 var element = $(this); 647 var checked = element.is(':checked'); 648 var addressFields = $('#anp-billing-address') 649 650 if (checked) { 651 addressFields.show(); 652 /* 653 addressFields.find('input').each(function(){ 654 var element = $(this); 655 element.val(''); 656 }); 657 */ 658 } else { 659 addressFields.hide(); 660 } 661 }); 662 663 // Restart/change 664 665 $('.anp-cart-restart-button, .anp-order-submit-button, .anp-order-change-trigger').click(function(){ 666 toggleSpinner(true); 667 }); 668 669 $('#anp-restart-trigger').click(function(){ 670 toggleSpinner(true); 671 $('#anp-restart-form').submit(); 672 }); 673 674 $('.anp-order-change-trigger').click(function(){ 675 $('#anp-order-change-step').val($(this).data('step')); 676 $('#anp-order-change-form').submit(); 677 678 return false; 679 }); 680 681 // Terms 682 683 $('.anp-checkout-terms-trigger').click(function(){ 684 var terms = $('#anp-checkout-terms'); 685 686 if (terms.is(':visible')) { 687 terms.hide(); 688 } else { 689 terms.show(); 690 } 691 692 return false; 693 }); 694 695 $('#anp-checkout-terms a').click(function() { 696 var href = $(this).attr('href'); 697 window.open(href); 698 return false; 699 }); 700} 701 702function onBillingSortCodeChange() 703{ 704 var element = $(this); 705 element.val(formatBillingSortCode(element.val())); 706} 707 708/* Contact/Register for Updates Form 709---------------------------------------*/ 710 711var _contactRegisterForm; 712var _ajaxLoading = false; 713var _contactRegisterFormDataLayerVars = {}; 714 715function initRegisterContactForm() 716{ 717 _contactRegisterForm = $('#anp-order-journey-form'); 718 $('#anp-journey-form-submit-trigger').click(onRegisterContactFormSubmit); 719} 720 721function onRegisterContactFormSubmit() 722{ 723 if (_ajaxLoading) { 724 return false; 725 } 726 727 var data = getFormData(_contactRegisterForm); 728 data['action'] = 'anp_form_submission'; 729 730 _contactRegisterFormDataLayerVars = {
731 type: data['data_layer_type'], 732 action: data['data_layer_action'], 733 postcode: data['data_layer_postcode'], 734 product_line: data['data_layer_product_line'], 735 }; 736 737 _contactRegisterForm.find('.anp-error').removeClass('anp-error'); 738 _ajaxLoading = true; 739 740 toggleSpinner(true); 741 clearFormErrors(_contactRegisterForm); 742 743 $.ajax({ 744 type: 'post', 745 url: anp_settings.ajax_url, 746 dataType: 'json', 747 data: data, 748 complete: function(response){ 749 _ajaxLoading = false; 750 751 toggleSpinner(false); 752 753 var json = response.responseJSON; 754 755 if (json.success) { 756 showContactRegisterFormThanks(json); 757 } else if (json.errors) { 758 showFormErrors(json.errors); 759 } 760 } 761 }); 762 763 return false; 764} 765 766function showContactRegisterFormThanks(response) 767{ 768 _contactRegisterForm.find('input, select, textarea').val(''); 769 770 $('#anp-journey-form-register').hide(); 771 $('#anp-journey-form-thanks').show(); 772 773 $('.anp-button-bar').hide(); 774 775 trackNewLeadEvent( 776 _contactRegisterFormDataLayerVars['postcode'], 777 _contactRegisterFormDataLayerVars['product_line'], 778 _contactRegisterFormDataLayerVars['type'], 779 _contactRegisterFormDataLayerVars['action'], 780 ); 781 782 scrollToElement($('#anp-journey-form-thanks')); 783 784 scrollToElement(_contactRegisterForm, -250); 785} 786 787/* Forms 788---------------------------------------*/ 789 790function initInputs() 791{ 792 initCheckboxes(); 793 794 $('.anp-true-false__label').click(function () { 795 var element = $(this); 796 var parent = element.closest('.anp-true-false'); 797 var checkbox = parent.find('input'); 798 799 checkbox.prop('checked', !checkbox.prop('checked')); 800 checkbox.trigger('change'); 801 }); 802} 803 804function getFormData(form) { 805 var id = form.attr('id'); 806 var data = new FormData(document.getElementById(id)); 807 return Array.from(data.keys()).reduce((result, key) => { 808 result[key] = data.get(key); 809 return result; 810 }, {}); 811} 812 813function showFormError(input, message) 814{ 815 var field = input.closest('.anp-field'); 816 var messageContainer = field.find('.anp-field__error'); 817 818 if (message && message.length) { 819 if (messageContainer.length) { 820 messageContainer.html(message); 821 } 822 } 823 824 field.addClass('anp-error'); 825} 826 827function showFormErrors(errors) 828{ 829 var focused = false; 830 var input; 831 832 for (var i in errors) { 833 input = $('#anp_' + i); 834 input.closest('.anp-field').addClass('anp-error'); 835 } 836 837 scrollToError(); 838} 839 840function clearFormErrors(form) 841{ 842 form.find('.anp-field__error').html(''); 843 form.find('.anp-error').removeClass('anp-error'); 844} 845 846function initCheckboxes() 847{ 848 var boxes = $('.elementor-widget-form').find('input[type=checkbox]').not('.anp-tickbox'); 849 850 boxes.each(function(){ 851 var box = $(this); 852 var name = box.attr('name'); 853 var id = box.attr('id'); 854 var value = box.val(); 855 var parent = box.parent(); 856 857 var html = getCustomCheckboxHTML(name, id, value); 858 parent.addClass('anp-custom-tickbox'); 859 box.replaceWith(html); 860 }); 861} 862 863function getCustomCheckboxHTML(name, id, value) 864{ 865 866 return '<div class="altnet"><div class="anp-checkbox">' 867 + '<input type="checkbox" name="' + name + '" id="' + id + '" value="' + value + '" class="anp-tickbox" />' 868 + '<label for="' + id + '"></label>' 869 + '</div></div>'; 870} 871 872/* Validation 873---------------------------------------*/ 874 875function validateCheckoutForm() 876{ 877 var validates = true; 878 var form = _checkoutForm; 879 880 clearFormErrors(form); 881 882 var mandatoryFields = form.find('.anp-field.mandatory:visible'); 883 884 mandatoryFields.each(function(){ 885 var field = $(this); 886 var input = field.find('.anp-input'); 887 var name = input.attr('name'); 888 var type = input.attr('type'); 889 var value = $.trim(input.val()); 890 891 if (name.match(/_confirm$/i)) { 892 var otherFieldName = name.replace(/_confirm$/i, ''); 893 var otherInput = $('.anp-checkout-input[name="' + otherFieldName + '"]') 894 895 if (otherInput.length) { 896 var otherValue = $.trim(otherInput.val()); 897 898 if (otherValue.toLowerCase() != value.toLowerCase()) { 899 showFormError(input, 'This needs to match the field above.'); 900 validates = false;
901 } 902 } 903 } else if ('telephone' == name && ! validateTelephone(value)) { 904 showFormError(input, 'Please enter a single, valid telephone number.'); 905 validates = false; 906 } else if (!value.length) { 907 showFormError(input, 'This is a required field.'); 908 validates = false; 909 } 910 }); 911 912 $('input[type="email"]').each(function(){ 913 var field = $(this); 914 var input = field.closest('.anp-input'); 915 var value = $.trim(input.val()); 916 917 if (value.length && !validateEmail(value)) { 918 showFormError(input, 'Please enter a valid email address.'); 919 validates = false; 920 } 921 }) 922 923 if ( ! validates ) { 924 scrollToError(); 925 } 926 927 return validates; 928} 929 930function scrollToError() 931{ 932 var firstError = $('.anp-error:first'); 933 934 if (firstError.length) { 935 scrollToElement(firstError); 936 } 937} 938 939function bookInstallationValidation() 940{ 941 var surveyCheckbox = $('#anp-timeslot-acknowledged'); 942 943 if (surveyCheckbox.is(':visible') && !surveyCheckbox.is(':checked')) { 944 showFormError(surveyCheckbox, 'Please confirm you are happy with a second appointment for installation.'); 945 surveyCheckbox.focus(); 946 return false; 947 } 948 949 return true; 950} 951 952var _scrollToVoipConfirmation = true; 953 954function productSelectionValidation() 955{ 956 if (_scrollToVoipConfirmation) { 957 var voipCheckbox = $('#anp-voip-confirmed'); 958 959 if (voipCheckbox.length && voipCheckbox.is(':visible') && !voipCheckbox.is(':checked')) { 960 if (!isInViewport(voipCheckbox[0])) { 961 scrollToElement($('#anp-voip-additional')); 962 963 var fieldWrapper = voipCheckbox.closest('.anp-field'); 964 965 if (fieldWrapper.length) { 966 var errorWrapper = fieldWrapper.find('.anp-field__error'); 967 968 if (errorWrapper.length) { 969 errorWrapper.text('Please confirm you have an alternative method of contacting emergency services.'); 970 } 971 } 972 973 return false; 974 } 975 } 976 977 _scrollToVoipConfirmation = false; 978 } 979 980 return true; 981} 982 983function validateEmail(email) 984{ 985 email = email.replace(/\+/, '', email); 986 987 var filter = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i 988 return filter.test(email); 989} 990 991function validateTelephone(telephone) 992{ 993 var filter = /^[0+][0-9\-\s()]{5,15}$/i 994 return filter.test(telephone); 995} 996 997/* Product Selection 998---------------------------------------*/ 999 1000function initProductSelection() 1001{ 1002 const products = document.querySelectorAll('.anp-product'); 1003 const noMatches = document.getElementById('anp-no-products'); 1004 1005 document.querySelectorAll('.anp-product-filter').forEach(input => { 1006 input.addEventListener('input', function (event) { 1007 applyProductFilters(); 1008 }, false); 1009 }); 1010 1011 products.forEach(product => { 1012 const button = product.querySelector('.anp-product-button'); 1013 1014 button.addEventListener('click', function (event) { 1015 selectProduct(product, products); 1016 }); 1017 }); 1018 1019 applyProductFilters(); 1020} 1021 1022function applyProductFilters() { 1023 const products = document.querySelectorAll('.anp-product'); 1024 const noMatches = document.getElementById('anp-no-products'); 1025 1026 const categoryValue = document.getElementById('anp-contract-length')?.value ?? ''; 1027 const productLineValue = document.getElementById('anp-product-line')?.value ?? ''; 1028 const productSuffixValue = document.getElementById('anp-product-suffix')?.value ?? ''; 1029 1030 let selector = ''; 1031 1032 if (categoryValue.length) { 1033 selector += '.category--' + categoryValue; 1034 } 1035 1036 if (productLineValue.length) { 1037 selector += '.product-line--' + productLineValue; 1038 } 1039 1040 if (productSuffixValue.length) { 1041 selector += '.product-suffix--' + productSuffixValue; 1042 } 1043 1044 products.forEach(element => { 1045 element.classList.remove('visible'); 1046 toggleProduct(element, false); 1047 onProductSelectionChange(); 1048 }); 1049 1050 if (selector != '') { 1051 const matchingElements = document.querySelectorAll(selector); 1052 1053 if (matchingElements && matchingElements.length) { 1054 noMatches.classList.remove('visible'); 1055 } else { 1056 noMatches.classList.add('visible'); 1057 } 1058 1059 matchingElements.forEach(element => { 1060 element.classList.add('visible'); 1061 }); 1062 } 1063} 1064 1065function selectProduct(product, allProducts) 1066{ 1067 const multiSelect = product.classList.contains('anp-addon'); 1068 const selected = product.classList.contains('selected'); 1069 1070 const isVOIP = product.getAttribute('data-is-voip') == 1; 1071 const isInPorting = product.getAttribute('data-is-voip-porting') == 1; 1072 1073 if (!multiSelect && allProducts) {
1074 allProducts.forEach(product => { 1075 toggleProduct(product, false); 1076 }); 1077 } 1078 1079 1080 if (isVOIP && !isInPorting) { 1081 const otherVOIPs = [...document.querySelectorAll('.anp-product.selected[data-is-voip="1"]')] 1082 .filter(element => element !== product); 1083 1084 if (otherVOIPs.length) { 1085 alert('You can only have one VOIP product. The previously-selected option will be removed.'); 1086 } 1087 1088 otherVOIPs.forEach(element => { 1089 toggleProduct(element, false); 1090 }); 1091 } 1092 1093 const button = product.querySelector('.anp-product-button'); 1094 1095 if (selected) { 1096 toggleProduct(product, false); 1097 } else { 1098 toggleProduct(product, true); 1099 1100 if (!multiSelect) { 1101 scrollToFooter(); 1102 } 1103 } 1104 1105 onProductSelectionChange(); 1106} 1107 1108function toggleProduct(product, selected) 1109{ 1110 const button = product.querySelector('.anp-product-button'); 1111 const selectedLabel = product.getAttribute('data-selected-label'); 1112 const deselectedLabel = product.getAttribute('data-deselected-label'); 1113 1114 if (selected) { 1115 product.classList.add('selected'); 1116 button.innerText = selectedLabel; 1117 } else { 1118 product.classList.remove('selected'); 1119 button.innerText = deselectedLabel; 1120 } 1121} 1122 1123function onProductSelectionChange() 1124{ 1125 const input = document.getElementById('anp-selected-products'); 1126 const ids = []; 1127 let showVoipForm = false; 1128 let showInPortingForm = false; 1129
1130 document.querySelectorAll('.anp-product.selected').forEach(product => { 1131 const productID = product.getAttribute('data-product-id'); 1132 const isVOIP = product.getAttribute('data-is-voip') == 1; 1133 const isInPorting = product.getAttribute('data-is-voip-porting') == 1; 1134 1135 if (isVOIP) { 1136 showVoipForm = true; 1137 } 1138 1139 if (isInPorting) { 1140 showInPortingForm = true; 1141 } 1142 1143 ids.push(productID); 1144 }); 1145 1146 const unselectableClass = 'unselectable'; 1147 const selectedClass = 'selected'; 1148 1149 document.querySelectorAll('.anp-product--child').forEach(product => { 1150 const parentID = product.getAttribute('data-parent-id'); 1151 const childID = product.getAttribute('data-parent-id'); 1152 const index = ids.indexOf(parentID); 1153 const childIndex = ids.indexOf(childID); 1154 1155 if (index >= 0) { 1156 product.classList.remove(unselectableClass); 1157 } else { 1158 product.classList.add(unselectableClass); 1159 product.classList.remove(selectedClass); 1160 ids.splice(index, childIndex); 1161 } 1162 }); 1163 1164 input.value = ids.join(','); 1165 1166 const wrapper = document.getElementById('anp-product-selection'); 1167 const selectedLabel = wrapper.getAttribute('data-selected-next-label'); 1168 const unselectedLabel = wrapper.getAttribute('data-unselected-next-label'); 1169 1170 let buttonLabel = ids.length ? selectedLabel : unselectedLabel; 1171 1172 if (buttonLabel) { 1173 document.querySelectorAll('.anp-skip-button').forEach(element => { 1174 element.querySelector('.anp-button__label').innerText = buttonLabel; 1175 }); 1176 } 1177 1178 const voipForm = document.getElementById('anp-voip-form'); 1179 1180 if (voipForm) { 1181 if (showVoipForm) { 1182 voipForm.classList.add('visible'); 1183 } else { 1184 voipForm.classList.remove('visible'); 1185 } 1186 } 1187 1188 const inPortingForm = document.getElementById('anp-in-porting-form'); 1189 1190 if (inPortingForm) { 1191 if (showInPortingForm) { 1192 inPortingForm.classList.add('visible'); 1193 } else { 1194 inPortingForm.classList.remove('visible'); 1195 } 1196 } 1197} 1198 1199/* Landing Page Products 1200---------------------------------------*/ 1201 1202function initProductCategorySwitchers() 1203{ 1204 var categoryLinks = $('.selection-nav__item'); 1205 1206 categoryLinks.click(function(){ 1207 var activeClass = 'selection-nav__item--active'; 1208 var element = $(this); 1209 1210 categoryLinks.removeClass(activeClass); 1211 element.addClass(activeClass); 1212 1213 var activeCategoryClass ='selection-category--active'; 1214 var categoryID = element.data('category'); 1215 $('.selection-category').removeClass(activeCategoryClass); 1216 $('.selection-category--id-' + categoryID).addClass(activeCategoryClass); 1217 1218 1219 return false; 1220 }); 1221} 1222 1223function initProductShowcaseCarousels() 1224{ 1225 document.querySelectorAll('.anp-showcase-carousel').forEach(wrapperNode => { 1226 const viewportNode = wrapperNode.querySelector('.anp-showcase-carousel__viewport'); 1227 const prevButtonNode = wrapperNode.querySelector('.anp-showcase-carousel__prev'); 1228 const nextButtonNode = wrapperNode.querySelector('.anp-showcase-carousel__next'); 1229 const dotNodes = wrapperNode.querySelectorAll('.anp-showcase-carousel__dot') 1230 1231 if (prevButtonNode && nextButtonNode) { 1232 const emblaApi = EmblaCarousel(viewportNode, { loop: true }); 1233 1234 const nextSlide = () => { 1235 let nextIndex = parseInt(wrapperNode.getAttribute('data-index')); 1236 let maxIndex = parseInt(wrapperNode.getAttribute('data-max')); 1237 1238 nextIndex++; 1239 1240 if (nextIndex >= maxIndex) { 1241 nextIndex = 0; 1242 } 1243 1244 gotoSlide(nextIndex); 1245 }; 1246 1247 const prevSlide = () => { 1248 let nextIndex = parseInt(wrapperNode.getAttribute('data-index')); 1249 let maxIndex = parseInt(wrapperNode.getAttribute('data-max')); 1250 nextIndex--; 1251 1252 if (nextIndex < 0) { 1253 nextIndex = maxIndex - 1; 1254 } 1255 1256 gotoSlide(nextIndex); 1257 }; 1258 1259 const gotoSlide = (slide) => { 1260 wrapperNode.setAttribute('data-index', slide); 1261 emblaApi.scrollTo(slide); 1262 1263 dotNodes.forEach(el => { 1264 el.classList.remove('active'); 1265 }); 1266 1267 const dot = wrapperNode.querySelector('.anp-showcase-carousel__dot--' + slide); 1268 1269 if (dot) { 1270 dot.classList.add('active'); 1271 } 1272 } 1273 1274 prevButtonNode.addEventListener('click', () => prevSlide(), false); 1275 nextButtonNode.addEventListener('click', () => nextSlide(), false); 1276
1277 dotNodes.forEach(dot => { 1278 dot.addEventListener('click', (e) => { 1279 const index = dot.getAttribute('data-slide'); 1280 gotoSlide(index); 1281 e.preventDefault(); 1282 }, false); 1283 }); 1284 } 1285 }); 1286} 1287 1288/* Booking Calendar 1289---------------------------------------*/ 1290 1291var _bookingTimeslots = {}; 1292var _bookingTimeslotsLoaded = false; 1293var _timeslotsView = 'selected'; 1294var _bookingSurveyRequester; 1295var _bookingMonthSwitcher; 1296var _useEarliestSlot = true; 1297 1298function initCalendar() 1299{ 1300 var date = new Date(); 1301 var month = date.getMonth() + 1; 1302 var year = date.getFullYear(); 1303 var calendar = _bookingCalendar; 1304 var container = $('#anp-book-timeslot'); 1305 1306 calendar.find('.anp-cal-reselect-trigger').click(function(){ 1307 _useEarliestSlot = false; 1308 loadCalendarTimeslots(); 1309 return false; 1310 }); 1311 1312 if (!container.hasClass('anp-cal-success')) { 1313 container.hide(); 1314 loadCalendarTimeslots(); 1315 } else { 1316 switchCalendarView('selected'); 1317 container.show(); 1318 } 1319 1320 _bookingSurveyRequester = $('#anp-timeslot-survey-requested'); 1321 1322 _bookingSurveyRequester.change(function(){ 1323 loadCalendarTimeslots(null, null, surveyRequested()); 1324 }); 1325 1326 $('#anp-timeslot-reselect').click(function(){ 1327 1328 if (!_bookingTimeslotsLoaded) { 1329 loadCalendarTimeslots(); 1330 } 1331 1332 switchCalendarView('reselect'); 1333 toggleBackNextNavigation(false); 1334 toggleBookingReselectControls(false); 1335 return false; 1336 }); 1337 1338 _bookingMonthSwitcher = $('#anp-booking-calendar-switch-month'); 1339 1340 _bookingMonthSwitcher.change(function(){ 1341 var value = $(this).val(); 1342 var tmp = value.split('-'); 1343 var month = parseInt(tmp[1]) - 1; 1344 loadCalendarTimeslots(month, tmp[0], surveyRequested()); 1345 }); 1346} 1347 1348function surveyRequested() 1349{ 1350 return _bookingSurveyRequester.is(':checked'); 1351} 1352 1353function toggleBookingReselectControls(active) 1354{ 1355 var controls = $('.anp-timeslot-reselect-hide'); 1356 1357 if (active) { 1358 controls.show(); 1359 } else { 1360 controls.hide(); 1361 } 1362} 1363 1364function loadCalendarTimeslots(month, year, requestSurvey) 1365{ 1366 toggleSpinner(true); 1367 1368 if (typeof month != 'undefined') { 1369 month = month + 1; 1370 } 1371 1372 var data = { action: 'anp_get_timeslots', month: month, year: year }; 1373 1374 if (typeof requestSurvey != 'undefined') { 1375 data['request_survey'] = requestSurvey ? 1 : 0; 1376 } 1377 1378 $.ajax({ 1379 type: 'post', 1380 url: anp_settings.ajax_url, 1381 dataType: 'json', 1382 data: data, 1383 complete: function(response){ 1384 toggleSpinner(false); 1385 var json = response.responseJSON; 1386 onCalendarTimeSlotsLoaded(json); 1387 } 1388 }); 1389} 1390 1391function onCalendarTimeSlotsLoaded(response) 1392{ 1393 var copydeck = response.copydeck; 1394 1395 _bookingTimeslots = response ? response.slots : {}; 1396 _bookingTimeslotsLoaded = true; 1397 1398 1399 1400 $('.obj-intro__headline').text(copydeck.title); 1401 $('.obj-intro__strapline').html(copydeck.subheading); 1402 $('.obj-timeslot-instructions').html(copydeck.instructions); 1403 1404 var readMore = copydeck.instructions_read_more; 1405 var hasReadMore = readMore && readMore.length > 10; 1406 1407 if (hasReadMore) { 1408 $('.obj-timeslot-instructions-more').show(); 1409 $('.obj-timeslot-instructions-more-copy').html(readMore); 1410 } else { 1411 $('.obj-timeslot-instructions-more').hide(); 1412 } 1413 1414 $('#anp-calendar-form').show(); 1415 1416 const dateString = response.start_date; 1417 const dateObject = new Date(dateString); 1418 1419 const formatted = dateObject.toLocaleDateString("en-GB", { 1420 month: "long", 1421 year: "numeric" 1422 }); 1423 1424 document.querySelectorAll('.anp-calendar-title').forEach(element => { 1425 element.innerText = formatted; 1426 }); 1427 1428 var slots = response.slots; 1429 1430 if (typeof slots == 'undefined') { 1431 $('#anp-book-timeslot').show(); 1432 return; 1433 } 1434 1435 var d = 0; 1436 var initialDateElement = $('#anp-calendar-initial-date'); 1437 1438 for (var date in slots) { 1439 var day = slots[date]; 1440 1441 if (d == 0) { 1442 var index = 0; 1443 var firstSlot = day[index]; 1444 populateSelectedDate(initialDateElement, 'Earliest date available', firstSlot.formatted_date_short, firstSlot.label); 1445 1446 if (_useEarliestSlot) { 1447 populateBookingInputs(date, index); 1448 } 1449 } 1450 1451 d++; 1452 } 1453 1454 switchCalendarView(_timeslotsView); 1455 toggleTimeslotCheckboxes(response.type, response.survey_requested); 1456 $('#anp-book-timeslot').show(); 1457 1458 var hasSlots = slots && Object.keys(slots).length; 1459 1460 if (!hasSlots) { 1461 $('#anp-timeslots-selected, #anp-timeslots-footer, #anp-timeslot-checkbox-survey').hide(); 1462 //return; 1463 } 1464 1465 var setTo = response.set_calendar_to; 1466 setCalendarTo(setTo.month - 1, setTo.year); 1467 1468 var prevNav = _bookingCalendar.find('.anp-calendar__prev'); 1469 var nextNav = _bookingCalendar.find('.anp-calendar__next'); 1470 1471 if (response.allow_nav_back) { 1472 prevNav.show(); 1473 } else { 1474 prevNav.hide(); 1475 } 1476 1477 if (response.allow_nav_next) { 1478 nextNav.show(); 1479 } else { 1480 nextNav.hide(); 1481 } 1482} 1483 1484function populateSelectedDate(element, title, date, times) 1485{ 1486 element.find('.anp-date-title').text(title); 1487 element.find('.anp-date-date').text(date); 1488 element.find('.anp-date-times').text(times); 1489} 1490 1491function switchCalendarView(id) 1492{ 1493 $('.anp-timeslots__view').hide(); 1494 $('#anp-timeslots-' + id).show(); 1495 _timeslotsView = id; 1496} 1497 1498function toggleTimeslotCheckboxes(type, surveyRequested) 1499{ 1500 $('.anp-timeslot-checkbox').hide(); 1501 1502 if (type) { 1503 $('#anp-timeslot-checkbox-' + type).show(); 1504 } 1505 1506 if (surveyRequested == 1) { 1507 $('#anp-timeslot-checkbox-installation').show(); 1508 } 1509} 1510 1511function setCalendarTo(month, year) 1512{ 1513 var calendar = _bookingCalendar; 1514 var startDate = new Date(year, month, 1); 1515 var startDay = startDate.getDay(); 1516 startDay = (startDay === 0) ? 7 : startDay; 1517 1518 var cells = calendar.find('.anp-cal-td'); 1519 cells.removeClass('inactive'); 1520 cells.removeClass('active'); 1521 cells.removeClass('preferred'); 1522 1523 var d = 1; 1524 var lastDayNumber = 0; 1525 1526 cells.each(function () { 1527 var cell = $(this); 1528 var dayLabel = ''; 1529 1530 var dayLink = cell.find('.dday'); 1531 dayLink.removeClass('available'); 1532 dayLink.removeClass('selected'); 1533 1534 var dateLabel = cell.find('.mlabel'); 1535 dateLabel.text(''); 1536 1537 if (d >= startDay) { 1538 1539 var dateString = startDate.toString(); 1540 var tmp = dateString.split(' '); 1541 1542 cell.addClass('active'); 1543 1544 if ( !(d > 28 && tmp[2] <= 5) ) { 1545 startDate.setDate(startDate.getDate() + 1); 1546 } 1547 1548 var monthString = (month + 1).toString(); 1549 1550 if (monthString.length == 1) { 1551 monthString = '0' + monthString; 1552 } 1553 1554 var dayNumber = parseInt(tmp[2]); 1555 1556 if (dayNumber > lastDayNumber) { 1557 dayLabel = tmp[2]; 1558 lastDayNumber = dayNumber; 1559 } 1560 1561 var dateString = [year, monthString, tmp[2]].join('-'); 1562 var config = _bookingTimeslots[dateString]; 1563 1564 if (config && dayLabel != '') { 1565 1566 dayLink.addClass('available'); 1567 dateLabel.text(config[0].formatted_date_short); 1568 1569 for (var _c in config) { 1570 if (config[_c].preferred) { 1571 cell.addClass('preferred'); 1572 } 1573 } 1574 } 1575 1576 cell.data('date', dateString); 1577 } 1578 1579 dayLink.text(dayLabel); 1580 d++; 1581 }); 1582 1583 1584 var surveyRequestInput = $('#anp-timeslot-survey-requested'); 1585 var surveyRequested = surveyRequestInput.is(':checked'); 1586 1587 calendar.find('.anp-calendar__prev').off().click(function(){ 1588 month--; 1589 1590 if (month < 0) {
1591 month = 11; 1592 year--; 1593 } 1594 1595 loadCalendarTimeslots(month, year, surveyRequested); 1596 1597 return false; 1598 }); 1599 1600 calendar.find('.anp-calendar__next').off().click(function(){ 1601 month++; 1602 1603 if (month > 11) { 1604 month = 0; 1605 year++ 1606 } 1607 1608 loadCalendarTimeslots(month, year, surveyRequested); 1609 1610 return false; 1611 }); 1612 1613 $('.anp-cal-a').off(); 1614 $('.anp-cal-td').removeClass('selected'); 1615 //onBookingDateSelected(); 1616 1617 calendar.find('.anp-cal-a').click(function () { 1618 1619 var element = $(this); 1620 1621 if (element.hasClass('available')) { 1622 var parent = element.parent(); 1623 $('.anp-cal-td').removeClass('selected'); 1624 parent.addClass('selected'); 1625 onBookingDateSelected(); 1626 1627 $('#anp-timeslot-timepickers').show(); 1628 } 1629 1630 return false; 1631 }); 1632 1633 _bookingMonthSwitcher.val(year + '-' + (month + 1) ); 1634} 1635 1636function onBookingDateSelected() 1637{ 1638 var config = getSelectedBookingDateConfig(); 1639 var timeInputs = $('.anp-time'); 1640 1641 timeInputs.removeClass('active'); 1642 timeInputs.removeClass('selected'); 1643 1644 toggleBookingReselectControls(false); 1645 toggleBackNextNavigation(false); 1646 1647 for (var i=0;i<config.length;i++) { 1648 var period = config[i]['period']; 1649 populateTimeSelector(i, period, config[i]); 1650 } 1651 1652 timeInputs.off().click(function () { 1653 $('.anp-time').removeClass('selected'); 1654 $(this).addClass('selected'); 1655 onBookingTimeSelected(); 1656 return false; 1657 }); 1658 1659 populateBookingSummary(); 1660} 1661 1662function onBookingTimeSelected() 1663{ 1664 populateBookingSummary(); 1665 toggleBookingReselectControls(true); 1666 toggleBackNextNavigation(true); 1667} 1668 1669function getSelectedBookingDateConfig() 1670{ 1671 var date = getSelectedBookingDate(); 1672 1673 if (date) { 1674 return _bookingTimeslots[date]; 1675 } 1676 1677 return false; 1678} 1679 1680function getSelectedBookingDate() 1681{ 1682 var selected = $('.anp-cal-td.selected'); 1683 1684 if (selected.length) { 1685 return selected.data('date'); 1686 } 1687 1688 return false; 1689} 1690 1691function populateTimeSelector(index, period, config) 1692{ 1693 period = period.toLowerCase(); 1694 var element = $('#anp-period-select-' + period); 1695 element.data('index', index); 1696 element.find('.anp-time__date').text(config['formatted_date']); 1697 element.find('.anp-time__time').text(config['label']); 1698 element.addClass('active'); 1699} 1700 1701function populateBookingSummary() 1702{ 1703 var config = getSelectedBookingDateConfig(); 1704 1705 if (!config) { 1706 return false; 1707 } 1708 1709 var date = getSelectedBookingDate(); 1710 var displayElement = $('#anp-calendar-selected-date'); 1711 var timeSelector = $('.anp-time.selected'); 1712 var timeLabel = 'Please select a time'; 1713 1714 var selectedDate = config[0].formatted_date; 1715 1716 if (timeSelector.length) { 1717 var index = timeSelector.data('index'); 1718 var timeConfig = config[index]; 1719 1720 timeLabel = 'Arrival time: ' + timeConfig.label; 1721 populateBookingInputs(date, index); 1722 } 1723 1724 populateSelectedDate(displayElement, '', selectedDate, timeLabel); 1725} 1726 1727function populateBookingInputs(date, index) 1728{ 1729 var config = _bookingTimeslots[date]; 1730 var timeConfig = config[index]; 1731 var selectedTime = timeConfig.label.toUpperCase(); 1732 var selectedPeriod = timeConfig.period.toUpperCase(); 1733 var selectedDescription = timeConfig.description_short; 1734 1735 $('#anp-timeslot-date').val(date); 1736 $('#anp-timeslot-times').val(selectedTime); 1737 $('#anp-timeslot-period').val(selectedPeriod); 1738 $('#anp-timeslot-text').val(selectedDescription); 1739} 1740 1741/* Survey 1742---------------------------------------*/ 1743 1744function initSurveys() 1745{ 1746 $('.anp-survey').each(function () { 1747 var survey = $(this); 1748 var inputSection = survey.find('.anp-survey__other'); 1749 var sessionUID = survey.data('session'); 1750 1751 survey.find('.anp-tickbox').change(function(){ 1752 var input = $(this); 1753 var checked = input.is(':checked'); 1754 1755 if (input.hasClass('anp-survey-user-input') && checked) { 1756 inputSection.show(); 1757 } else { 1758 inputSection.find('input').val(''); 1759 inputSection.hide(); 1760 } 1761 1762 }); 1763 1764 survey.find('.anp-tickbox.anp-survey-standalone').change(function(){ 1765 var value = $(this).val(); 1766 1767 var data = { 1768 action: 'anp_thanks_survey', 1769 value: value, 1770 session: sessionUID 1771 } 1772 1773 toggleSpinner(true); 1774 1775 $.ajax({ 1776 type: 'post', 1777 url: anp_settings.ajax_url, 1778 dataType: 'json', 1779 data: data, 1780 complete: function () { 1781 survey.hide(200); 1782 toggleSpinner(false); 1783 } 1784 }) 1785 1786 }); 1787 }); 1788} 1789 1790/* Loading Spinner 1791---------------------------------------*/ 1792 1793function toggleSpinner(active) 1794{ 1795 var element = jQuery('#anp-spinner'); 1796 1797 if (active) { 1798 element.fadeIn(); 1799 } else { 1800 element.fadeOut(); 1801 } 1802} 1803 1804/* Loading Spinner 1805---------------------------------------*/ 1806 1807var _progressInterval; 1808var _progressBar; 1809 1810function showProgressBar(label, seconds, onComplete) 1811{ 1812 var element = jQuery('#anp-progress'); 1813 var labelElement = element.find('.anp-progress__label'); 1814 1815 _progressBar = element.find('.anp-progress__value'); 1816 labelElement.text(label); 1817 element.fadeIn(); 1818 1819 var elapsedSeconds = 0; 1820 var percent = 0; 1821 1822 _progressBar.width(0); 1823 1824 clearInterval(_progressInterval); 1825 1826 _progressInterval = setInterval(function(){ 1827 1828 elapsedSeconds += 0.1; 1829 1830 percent = (elapsedSeconds / seconds) * 100; 1831 1832 if (percent >= 100) { 1833 percent = 100; 1834 completeProgressBar(); 1835 if (onComplete) { 1836 onComplete(); 1837 } 1838 } 1839 1840 _progressBar.width(percent + '%'); 1841 }, 100); 1842} 1843 1844function completeProgressBar() 1845{ 1846 1847 if (typeof _progressBar == 'undefined') { 1848 return; 1849 } 1850 1851 clearInterval(_progressInterval); 1852 _progressBar.width('100%'); 1853 1854 setTimeout(function (){ 1855 jQuery('#anp-progress').fadeOut(function(){ 1856 _progressBar.width(0); 1857 1858 }); 1859 }, 500); 1860} 1861 1862/* Tracking 1863---------------------------------------*/ 1864 1865function initTracking() 1866{ 1867 // 1868} 1869 1870function trackNewLeadEvent(postcode, productLine, type, action, splitTest, callback) 1871{ 1872 postcode = normalisePostcode(postcode); 1873 1874 var data = { 1875 event: 'lead', 1876 postcode: postcode, 1877 product_line: productLine, 1878 type: type, 1879 action: action, 1880 journey_split: splitTest, 1881 }; 1882 1883 pushToDataLayer(data, callback); 1884} 1885 1886function pushToDataLayer(data, callback) 1887{ 1888 window.dataLayer = window.dataLayer || []; 1889 1890 // Assisted journeys are kept out of the data layer so they aren't attributed as web orders. 1891 var suppress = (typeof anp_settings !== 'undefined' && '1' === anp_settings.suppress_tracking); 1892 1893 console.log(suppress ? 'Suppressing datalayer push (assisted journey)' : 'Pushing to datalayer'); 1894 console.log(data); 1895 1896 if (callback) { 1897 setTimeout(function(){ 1898 callback(); 1899 console.log('Executing datalayer callback'); 1900 }, 100); 1901 } 1902 1903 if (suppress) { 1904 return; 1905 } 1906 1907 dataLayer.push(data); 1908} 1909 1910/* One Touch Switch 1911---------------------------------------*/ 1912 1913var _otsErrorBox; 1914var _otsErrorDefault; 1915var _otsErrorCustom; 1916var _otsCallToActionWrapper; 1917var _otsCallToActions; 1918var _otsPortingNumber; 1919var _otsOpIn; 1920 1921function initOneTouchSwitch() 1922{ 1923 _otsErrorBox = $('#anp-ots-error-box'); 1924 _otsErrorDefault = $('#anp-ots-error-default'); 1925 _otsErrorCustom = $('#anp-ots-error-custom'); 1926 _otsOpIn = $('#anp-ots-opt-in'); 1927 _otsOpOut = $('#anp-ots-opt-out'); 1928 _otsCallToActionWrapper = $('#anp-ots-error-ctas'); 1929 _otsCallToActions = $('.anp-ots-next-action'); 1930 _otsPortingNumber = $('#anp-ots-porting-number'); 1931 1932 $('#anp-ots-optin-wrapper').show(); 1933 1934 _otsOpIn.change(function(){ 1935 var element = $(this); 1936 var toggleable = $('.anp-ots-hidden'); 1937 1938 if (element.is(':checked')) { 1939 toggleable.show(); 1940 toggleOneTouchSwitchFooter(true); 1941 } else { 1942 toggleable.hide(); 1943 hideOneTouchSwitchError(); 1944 } 1945 }); 1946 1947 _otsOpOut.change(function(){ 1948 var element = $(this); 1949 var toggleable = $('.anp-ots-hidden'); 1950 1951 if (!element.is(':checked') && _otsOpIn.is(':checked')) { 1952 toggleable.show(); 1953 toggleOneTouchSwitchFooter(true); 1954 } else { 1955 toggleable.hide(); 1956 hideOneTouchSwitchError(); 1957 } 1958 }); 1959 1960 var validates = false;
1961 1962 $('#anp-checkout-ots-trigger').click(function(){ 1963 1964 validates = validateCheckoutForm(); 1965 1966 if (validates) { 1967 submitOneTouchSwitch(); 1968 } 1969 1970 return false; 1971 }); 1972 1973 _otsCallToActions.click(function(){ 1974 1975 var action = $(this).data('action'); 1976 var confirmed = true; 1977 1978 if ('continue' == action) { 1979 confirmed = confirm("Are you sure?\n\nYou will need to contact your current provider to cancel the services you have with them."); 1980 } else if ('cancel' == action) { 1981 confirmed = confirm("Are you sure?\n\nThis will cancel the ordering process for now."); 1982 } 1983 1984 if (confirmed) { 1985 submitOneTouchSwitchNextAction(action); 1986 } 1987 1988 return false; 1989 }); 1990} 1991 1992function submitOneTouchSwitch() 1993{ 1994 var data = getFormData(_checkoutForm); 1995 var task = data.ots_task; 1996 1997 clearFormErrors(_checkoutForm); 1998 1999 if ('match' == task) { 2000 submitOneTouchSwitchLookup(); 2001 } else if ('options' == task) { 2002 submitOneTouchSwitchOptions(); 2003 } else if ('voip_porting' == task) { 2004 submitOneTouchSwitchVoipPorting(); 2005 } 2006} 2007 2008function submitOneTouchSwitchLookup() 2009{ 2010 var data = getFormData(_checkoutForm); 2011 var otsEligible = data.ots_eligible; 2012 var otsOptIn = _otsOpIn.is(':checked'); 2013 2014 if (1 != otsEligible ) { 2015 toggleSpinner(true); 2016 _checkoutForm.submit(); 2017 return false; 2018 } 2019 2020 hideOneTouchSwitchError(); 2021 toggleOneTouchSwitchFooter(false); 2022 2023 data['ots_opt_in'] = otsOptIn ? 1 : 0; 2024 data['action'] = 'anp_ots_match'; 2025 delete data._wpnonce; 2026 2027 $.ajax({ 2028 type: 'POST', 2029 url: anp_settings.ajax_url, 2030 dataType: 'json', 2031 data: data, 2032 complete: function(response){ 2033 completeProgressBar(); 2034 onOneTouchSwitchMatchComplete(response.responseJSON); 2035 } 2036 }); 2037 2038 if (otsOptIn) { 2039 showProgressBar('Verifying your information - this may take a moment', 65, function(){ 2040 showOneTouchSwitchError({ action: 'retry_or_continue' }); 2041 }); 2042 } 2043} 2044 2045function onOneTouchSwitchMatchComplete(response) 2046{ 2047 var success = response.success; 2048 var action = response.action; 2049 2050 if (!success) { 2051 showOneTouchSwitchError(response); 2052 $('#anp-ots-optin-wrapper').hide(); 2053 scrollToOTSTop(); 2054 } else { 2055 toggleSpinner(true); 2056 redirectToJourneyStart(); 2057 } 2058} 2059 2060function showOneTouchSwitchError(response) 2061{ 2062 var message = response.user_message; 2063 var customMessage = typeof message != 'undefined'; 2064 2065 if (customMessage) { 2066 _otsErrorDefault.hide(); 2067 _otsErrorCustom.show(); 2068 2069 _otsErrorCustom.html(message); 2070 } else { 2071 _otsErrorDefault.show(); 2072 _otsErrorCustom.hide(); 2073 } 2074 2075 var nextAction = response.action; 2076 2077 _otsCallToActions.hide(); 2078 _otsCallToActionWrapper.show(); 2079 2080 $('#anp-ots-form').hide(); 2081 2082 var ctas = _otsCallToActions.filter('.anp-ots-next-action--' + nextAction); 2083 2084 ctas.show(); 2085 2086 _otsErrorBox.show(); 2087 2088 2089 scrollToOTSTop(); 2090} 2091 2092function submitOneTouchSwitchNextAction(nextAction) 2093{ 2094 var data = { 2095 action: 'anp_ots_match_next_action', 2096 next_action: nextAction, 2097 }; 2098 2099 toggleSpinner(true); 2100 2101 $.ajax({ 2102 type: 'POST', 2103 url: anp_settings.ajax_url, 2104 dataType: 'json', 2105 data: data, 2106 complete: function(response){ 2107 redirectToJourneyStart(); 2108 } 2109 }) 2110} 2111 2112function submitOneTouchSwitchVoipPorting() 2113{ 2114 var formData = getFormData(_checkoutForm); 2115 2116 toggleSpinner(true); 2117 2118 $.ajax({ 2119 type: 'POST', 2120 url: anp_settings.ajax_url, 2121 dataType: 'json', 2122 data: { 2123 action: 'anp_ots_voip_porting', 2124 ots_voip_port_provider_identity: formData.ots_voip_port_provider_identity, 2125 ots_voip_port_number: formData.ots_voip_port_number 2126 }, 2127 complete: function(response){ 2128 var result = response.responseJSON; 2129 2130 if (!result.success) { 2131 toggleSpinner(false); 2132 showFormErrors(result.errors); 2133 } else { 2134 redirectToJourneyStart(); 2135 } 2136 2137 } 2138 }); 2139} 2140 2141function hideOneTouchSwitchError() 2142{ 2143 _otsErrorBox.hide(function(){ 2144 _otsCallToActionWrapper.hide(); 2145 }); 2146} 2147 2148function submitOneTouchSwitchOptions() 2149{ 2150 var formData = getFormData(_checkoutForm); 2151 var reference = formData.switch_order_reference; 2152 2153 if (!reference) { 2154 scrollToElement($('#anp-ots-options')); 2155 return false; 2156 } 2157 2158 toggleSpinner(true); 2159 2160 $.ajax({ 2161 type: 'POST', 2162 url: anp_settings.ajax_url, 2163 dataType: 'json', 2164 data: { 2165 action: 'anp_ots_options', 2166 order_reference: reference, 2167 }, 2168 complete: function(response){ 2169 onOneTouchSwitchOptionsComplete(response.responseJSON); 2170 } 2171 }); 2172} 2173 2174function onOneTouchSwitchOptionsComplete(response) 2175{ 2176 var success = response.success; 2177 2178 if (success) { 2179 redirectToJourneyStart(); 2180 } 2181} 2182 2183function toggleOneTouchSwitchFooter(active) 2184{ 2185 //active = true; 2186 2187 var element = jQuery('#anp-ots-footer'); 2188 2189 if (active) { 2190 element.show(); 2191 } else { 2192 element.hide(); 2193 } 2194} 2195 2196function retryOneTouchSwitch() 2197{ 2198 hideOneTouchSwitchError(); 2199 toggleOneTouchSwitchFooter(true); 2200} 2201 2202function scrollToOTSTop() 2203{ 2204 scrollToElement($('#ots-top')); 2205} 2206 2207 2208/* Payment Details 2209---------------------------------------*/ 2210 2211var _paymentBillingWrapper; 2212var _paymentChangeBillingTriggers; 2213 2214const debouncedBillingAddressLookup = debounce(submitBillingAddressSearch, 400); 2215 2216function initPaymentDetails() 2217{ 2218 _paymentBillingWrapper = $('#anp-payment-billing-address'); 2219 _paymentChangeBillingTriggers = $('.anp-change-billing'); 2220 2221 if (!_paymentBillingWrapper.length) { 2222 return; 2223 } 2224 2225 _paymentChangeBillingTriggers.click(function(){ 2226 toggleBillingWrapper(true); 2227 setCustomBillingAddress(true); 2228 return false;
2229 }); 2230 2231 $('.anp-billing-address-reset-trigger').click(function(){ 2232 toggleBillingWrapper(false); 2233 setCustomBillingAddress(false); 2234 2235 $('#anp-billing-address-display').text( 2236 $('#anp-installation-address-display').text() 2237 ); 2238 return false; 2239 }); 2240 2241 _addressSelectElement = $('#anp-billing-addresses'); 2242 2243 _addressSelectElement.change(onBillingAddressSelectChange); 2244 2245 const input = document.getElementById('anp-billing-partial-address'); 2246 2247 2248 2249 let lastLookupValue = ''; 2250 2251 input.addEventListener('input', function (e) { 2252 const el = e.target; 2253 let cleaned = el.value.replace(/[^a-z0-9]/gi, ''); 2254 2255 cleaned = cleaned.slice(0, 7); 2256 2257 if (cleaned !== el.value) { 2258 el.value = cleaned; 2259 } 2260 2261 if (cleaned !== lastLookupValue) { 2262 if (cleaned.length > 5) { 2263 debouncedBillingAddressLookup(); 2264 } 2265 2266 lastLookupValue = cleaned; 2267 } 2268 }); 2269} 2270 2271function setCustomBillingAddress(active) 2272{ 2273 $('#anp-custom-billing').val(active ? 1 : 0); 2274} 2275 2276function submitBillingAddressSearch() { 2277 2278 const address = $('#anp-billing-partial-address').val(); 2279 2280 billingAddressApiSearch( address, _addressSearchPage ); 2281} 2282 2283function billingAddressApiSearch( address, page, callback ) { 2284 2285 if (_addressesLoading) { 2286 return false; 2287 } 2288 2289 if (!address.length) { 2290 return false 2291 } 2292 2293 submitAddressSearchRequest(address, page, true, onBillingAddressSearchComplete); 2294} 2295 2296function onBillingAddressSearchComplete(json) 2297{ 2298 if (!json['success']) { 2299 alert('An error occurred. Please try again shortly.'); 2300 return; 2301 } 2302 2303 _addressSearchResults = json.data; 2304 2305 showBillingAddressSearchResults(); 2306 toggleSpinner(false); 2307} 2308 2309function showBillingAddressSearchResults() { 2310 _addressSelectElement.empty(); 2311 2312 addSearchSelectOption('', 'Select an address'); 2313 2314 var addresses = _addressSearchResults; 2315 2316 if (addresses && addresses.length) { 2317 for (var a in addresses) { 2318 var address = addresses[a]; 2319 addSearchSelectOption(a, address['summaryline'], false); 2320 } 2321 } else { 2322 _addressSelectElement.empty(); 2323 addSearchSelectOption('null', 'No addresses found'); 2324 $('.anp-billing-field').val(''); 2325 toggleBillingManualAddress(true); 2326 } 2327} 2328 2329function onBillingAddressSelectChange() { 2330 var selected = _addressSelectElement.val(); 2331 2332 if ( typeof _addressSearchResults[selected] != 'undefined' ) { 2333 populateBillingAddress(_addressSearchResults[selected]); 2334 } 2335} 2336 2337function populateBillingAddress(address) 2338{ 2339 toggleBillingManualAddress(true); 2340 2341 $('#anp-billing-address-line-1').val(address.address1); 2342 $('#anp-billing-address-line-2').val(address.address2); 2343 $('#anp-billing-city').val(address.posttown); 2344 $('#anp-billing-postcode').val(address.postcode); 2345} 2346 2347function toggleBillingManualAddress(active) 2348{ 2349 if (active) { 2350 $('#anp-payment-billing-fields').show(); 2351 } else { 2352 $('#anp-payment-billing-fields').hide(); 2353 } 2354} 2355 2356function toggleBillingWrapper(active) 2357{ 2358 if (active) { 2359 _paymentBillingWrapper.show(); 2360 _paymentChangeBillingTriggers.hide(); 2361 } else { 2362 _paymentBillingWrapper.hide(); 2363 _paymentChangeBillingTriggers.show(); 2364 } 2365} 2366 2367/* Coupons 2368---------------------------------------*/ 2369 2370function initCoupons() 2371{ 2372 $('.anp-coupon-submit-trigger').click(function(){ 2373 var couponInput = $(this).closest('.anp-coupons').find('.anp-coupon-code'); 2374 var couponCode = couponInput.val(); 2375 applyCoupon(couponCode); 2376 2377 return false; 2378 }); 2379 2380 $('.anp-coupon-change-trigger').click(function(){ 2381 applyCoupon(''); 2382 return false; 2383 }); 2384} 2385 2386function applyCoupon(couponCode) { 2387 toggleSpinner(true); 2388 2389 $.ajax({ 2390 type: 'post', 2391 url: anp_settings.ajax_url, 2392 dataType: 'json', 2393 data: { coupon_code: couponCode, action: 'anp_apply_coupon' }, 2394 complete: function(response){ 2395 toggleSpinner(false); 2396 var json = response.responseJSON; 2397 var code = json.coupon.code ?? ''; 2398 2399 if (json.errors['coupon_code']) { 2400 alert(json.errors['coupon_code']) 2401 } 2402 2403 if (!code) { 2404 $('.anp-coupon-info').removeClass('active'); 2405 } else { 2406 $('.anp-coupon-info').addClass('active'); 2407 } 2408 2409 var description = json.coupon.description ?? ''; 2410 var terms = json.coupon.small_print ?? ''; 2411 2412 2413 $('.anp-input.anp-coupon-code').val(code); 2414 $('.anp-coupon-description').text(description) 2415 $('.anp-coupon-terms').text(terms); 2416 } 2417 }); 2418} 2419 2420/* Kickoffs 2421---------------------------------------*/ 2422 2423function initInputPlaceholders() 2424{ 2425 const mq = window.matchMedia('(max-width: 500px)'); 2426 2427 function updatePlaceholders(e) { 2428 $('[data-placeholder-mobile]').each(function () { 2429 const $el = $(this); 2430 2431 $el.attr( 2432 'placeholder', 2433 e.matches 2434 ? $el.data('placeholder-mobile') 2435 : $el.data('placeholder-desktop') 2436 ); 2437 }); 2438 } 2439 2440 updatePlaceholders(mq); 2441 2442 mq.addEventListener 2443 ? mq.addEventListener('change', updatePlaceholders) 2444 : mq.addListener(updatePlaceholders); 2445} 2446 2447/* Utilities 2448---------------------------------------*/ 2449 2450function normalisePostcode(postcode) 2451{ 2452 if (postcode == null) { 2453 return ''; 2454 } 2455 2456 return postcode.replace(/[^a-z|0-9]/ig, '').toUpperCase(); 2457} 2458 2459function formatBillingSortCode(sortCode) 2460{ 2461 sortCode = sortCode.replace(/[^0-9]/g, ''); 2462 var formatted = (String(sortCode).match(/.{1,2}/g) || []).join('-'); 2463 return formatted.substring(0, 8); 2464} 2465 2466function toggleBackNextNavigation(active) 2467{ 2468 const element = document.getElementById('anp-obj-back-next'); 2469 element.style.display = active ? 'block' : 'none'; 2470} 2471 2472function scrollToElement(element, offset, speed) 2473{ 2474 if (!element.length) { 2475 return; 2476 } 2477 2478 offset = offset ? offset : -200; 2479 speed = speed ? speed : .5; 2480 2481 var scrollTop = element.offset().top + offset; 2482 2483 $('html,body').animate({ scrollTop: scrollTop }, 1000 * speed); 2484} 2485 2486function scrollToFooter() 2487{ 2488 scrollToElement($('#obj-footer')); 2489} 2490 2491function redirectToJourneyStart() 2492{ 2493 document.location.href = anp_settings.buy_url; 2494} 2495 2496function debounce(fn, delay) 2497{ 2498 var timer; 2499 return function (...args) { 2500 clearTimeout(timer); 2501 timer = setTimeout(() => fn.apply(this, args), delay); 2502 }; 2503} 2504 2505function isInViewport(el) 2506{ 2507 const rect = el.getBoundingClientRect(); 2508 return ( 2509 rect.top >= 0 && 2510 rect.left >= 0 && 2511 rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && 2512 rect.right <= (window.innerWidth || document.documentElement.clientWidth) 2513 ); 2514} 2515 2516}( window.altnetOrderJourney = window.altnetOrderJourney || {}, jQuery )); 2517
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.