1class SmartPhoneFieldFree { 2 constructor(options) { 3 this.options = options; 4 this.init(); 5 } 6 7 init() { 8 this.initSmartPhoneFieldFree(); 9 } 10 11 initSmartPhoneFieldFree() { 12 if (typeof intlTelInput === 'undefined') { 13 return; 14 } 15 const input = document.querySelector(this.options.inputId); 16 17 if (!input) { 18 console.warn(`Input element not found: ${this.options.inputId}`); 19 return; 20 } 21 22 const iti = window.intlTelInput(input, this.configuration()); 23 24 input.addEventListener('keypress', function (e) { 25 const charCode = e.which ? e.which : e.keyCode; 26 if (String.fromCharCode(charCode).match(/[^0-9+]/g)) { 27 e.preventDefault(); 28 } 29 }); 30 31 this.addCountryCodeInputHandler(input, iti); 32 33 input.addEventListener('blur', (e) => { 34 this.validateNumber(input, iti); 35 }); 36 37 input.addEventListener('keyup', (e) => { 38 this.formatValidation(input, iti); 39 }); 40 } 41 42 configuration() { 43 const field_id = `input_${this.options.fieldId}`; 44 45 let config = { 46 initialCountry: this.options.defaultCountry, 47 formatOnDisplay: false, 48 formatAsYouType: false, 49 fixDropdownWidth: true, 50 hiddenInput: function (telInputName) { 51 return { 52 phone: field_id 53 }; 54 }, 55 useFullscreenPopup: false 56 }; 57 58 if (this.options.countrySearch) { 59 config.countrySearch = true; 60 } 61 62 if (this.options.flag === "flagcode") { 63 config.nationalMode = false; 64 config.autoHideDialCode = false; 65 } else if (this.options.flag === "flagdial" || this.options.flag === "flagwithcode") { 66 config.nationalMode = false; 67 config.separateDialCode = true; 68 } else { 69 config.nationalMode = true; 70 } 71 72 if (this.options.exIn === 'ex_only') { 73 config.onlyCountries = this.options.countries.split(','); 74 } 75 76 if (this.options.exIn === 'pre_only') { 77 config.excludeCountries = this.options.countries.split(','); 78 } 79 80 if (this.options.autoIp) { 81 this.detectIPAddress(config); 82 } 83 84 if (this.options.placeholder) { 85 config.autoPlaceholder = 'off'; 86 } 87 88 config = gform.applyFilters('gform_spf_options_pre_init', config, this.options.formId, this.options.fieldId); 89 90 return config; 91 } 92 93 detectIPAddress(config) { 94 const api_url = "https://ipinfo.io/json"; 95 config.initialCountry = "auto"; 96 config.geoIpLookup = function (callback) { 97 fetch(api_url) 98 .then(r => r.json()) 99 .then(data => { 100 const country = (data && data.country) ? data.country.toLowerCase() : 'us'; 101 callback(country); 102 }) 103 .catch(() => callback('us')); 104 }; 105 } 106 107 validateNumber(input, iti) { 108 const isValid = iti.isValidNumber(); 109 const errorMsg = input.parentNode?.parentNode?.querySelector(".error-msg"); 110 const validMsg = input.parentNode?.parentNode?.querySelector(".valid-msg"); 111 112 if (!errorMsg || !validMsg) { 113 console.warn('Error or valid message elements not found'); 114 return; 115 } 116 117 if (input.value) { 118 if (isValid) { 119 errorMsg.classList.add('hide'); 120 validMsg.classList.remove('hide'); 121 } else { 122 validMsg.classList.add('hide'); 123 errorMsg.classList.remove('hide'); 124 } 125 } else { 126 validMsg.classList.add('hide'); 127 errorMsg.classList.add('hide'); 128 } 129 } 130 131 formatValidation(input, iti) { 132 const isValid = iti.isValidNumber(); 133 const errorMsg = input.parentNode?.parentNode?.querySelector(".error-msg"); 134 const validMsg = input.parentNode?.parentNode?.querySelector(".valid-msg"); 135 136 if (!errorMsg || !validMsg) {
137 console.warn('Error or valid message elements not found'); 138 return; 139 } 140 141 if (input.value) { 142 if (isValid) { 143 errorMsg.classList.add('hide'); 144 validMsg.classList.remove('hide'); 145 } else { 146 validMsg.classList.add('hide'); 147 errorMsg.classList.add('hide'); 148 } 149 } else { 150 validMsg.classList.add('hide'); 151 errorMsg.classList.add('hide'); 152 } 153 } 154 155 addCountryCodeInputHandler(inputElement, iti) { 156 if (this.options.flag !== 'flagcode') { 157 return; 158 } 159 160 const handleCountryChange = (event) => { 161 const currentCountryData = iti.getSelectedCountryData(); 162 const currentCode = `+${currentCountryData.dialCode}`; 163 this.updateCountryCodeHandler(event.currentTarget, currentCode); 164 }; 165 166 inputElement.addEventListener('keydown', handleCountryChange); 167 inputElement.addEventListener('input', handleCountryChange); 168 inputElement.addEventListener('countrychange', handleCountryChange); 169 } 170 171 updateCountryCodeHandler(input, currentCode) { 172 let value = input.value; 173 174 if (!currentCode || currentCode === '+undefined' || ['', '+'].includes(value)) { 175 return; 176 } 177 178 if (!value.startsWith(currentCode)) { 179 value = value.replace(/\+/g, ''); 180 input.value = currentCode + value; 181 } 182 } 183}
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.