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