PageSourceSearch

https://ru.navettaitalia.com/assets/front3/intl-tel-input-14.0.0/build/js/intlTelInput.js?700

js navettaitalia.com collected 2026-10-06 17:00:31 UTC 80,973 bytes, 1,217 lines download raw bytes

1/*
2 * International Telephone Input v14.0.0
3 * https://github.com/jackocnr/intl-tel-input.git
4 * Licensed under the MIT license
5 */
6 
7 window.allCountries = [ [ "Russia (Россия)", "ru", "7", 0 ], [ "Ukraine (Україна)", "ua", "380" ], [ "Israel (‫ישראל‬‎)", "il", "972" ], [ "United States", "us", "1", 0 ], [ "Afghanistan (‫افغانستان‬‎)", "af", "93" ], [ "Albania (Shqipëri)", "al", "355" ], [ "Algeria (‫الجزائر‬‎)", "dz", "213" ], [ "American Samoa", "as", "1684" ], [ "Andorra", "ad", "376" ], [ "Angola", "ao", "244" ], [ "Anguilla", "ai", "1264" ], [ "Antigua and Barbuda", "ag", "1268" ], [ "Argentina", "ar", "54" ], [ "Armenia (Հայաստան)", "am", "374" ], [ "Aruba", "aw", "297" ], [ "Australia", "au", "61", 0 ], [ "Austria (Österreich)", "at", "43" ], [ "Azerbaijan (Azərbaycan)", "az", "994" ], [ "Bahamas", "bs", "1242" ], [ "Bahrain (‫البحرين‬‎)", "bh", "973" ], [ "Bangladesh (বাংলাদেশ)", "bd", "880" ], [ "Barbados", "bb", "1246" ], [ "Belarus (Беларусь)", "by", "375" ], [ "Belgium (België)", "be", "32" ], [ "Belize", "bz", "501" ], [ "Benin (Bénin)", "bj", "229" ], [ "Bermuda", "bm", "1441" ], [ "Bhutan (འབྲུག)", "bt", "975" ], [ "Bolivia", "bo", "591" ], [ "Bosnia and Herzegovina (Босна и Херцеговина)", "ba", "387" ], [ "Botswana", "bw", "267" ], [ "Brazil (Brasil)", "br", "55" ], [ "British Indian Ocean Territory", "io", "246" ], [ "British Virgin Islands", "vg", "1284" ], [ "Brunei", "bn", "673" ], [ "Bulgaria (България)", "bg", "359" ], [ "Burkina Faso", "bf", "226" ], [ "Burundi (Uburundi)", "bi", "257" ], [ "Cambodia (កម្ពុជា)", "kh", "855" ], [ "Cameroon (Cameroun)", "cm", "237" ], [ "Canada", "ca", "1", 1, [ "204", "226", "236", "249", "250", "289", "306", "343", "365", "387", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "672", "705", "709", "742", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905" ] ], [ "Cape Verde (Kabu Verdi)", "cv", "238" ], [ "Caribbean Netherlands", "bq", "599", 1 ], [ "Cayman Islands", "ky", "1345" ], [ "Central African Republic (République centrafricaine)", "cf", "236" ], [ "Chad (Tchad)", "td", "235" ], [ "Chile", "cl", "56" ], [ "China (中国)", "cn", "86" ], [ "Christmas Island", "cx", "61", 2 ], [ "Cocos (Keeling) Islands", "cc", "61", 1 ], [ "Colombia", "co", "57" ], [ "Comoros (‫جزر القمر‬‎)", "km", "269" ], [ "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)", "cd", "243" ], [ "Congo (Republic) (Congo-Brazzaville)", "cg", "242" ], [ "Cook Islands", "ck", "682" ], [ "Costa Rica", "cr", "506" ], [ "Côte d’Ivoire", "ci", "225" ], [ "Croatia (Hrvatska)", "hr", "385" ], [ "Cuba", "cu", "53" ], [ "Curaçao", "cw", "599", 0 ], [ "Cyprus (Κύπρος)", "cy", "357" ], [ "Czech Republic (Česká republika)", "cz", "420" ], [ "Denmark (Danmark)", "dk", "45" ], [ "Djibouti", "dj", "253" ], [ "Dominica", "dm", "1767" ], [ "Dominican Republic (República Dominicana)", "do", "1", 2, [ "809", "829", "849" ] ], [ "Ecuador", "ec", "593" ], [ "Egypt (‫مصر‬‎)", "eg", "20" ], [ "El Salvador", "sv", "503" ], [ "Equatorial Guinea (Guinea Ecuatorial)", "gq", "240" ], [ "Eritrea", "er", "291" ], [ "Estonia (Eesti)", "ee", "372" ], [ "Ethiopia", "et", "251" ], [ "Falkland Islands (Islas Malvinas)", "fk", "500" ], [ "Faroe Islands (Føroyar)", "fo", "298" ], [ "Fiji", "fj", "679" ], [ "Finland (Suomi)", "fi", "358", 0 ], [ "France", "fr", "33" ], [ "French Guiana (Guyane française)", "gf", "594" ], [ "French Polynesia (Polynésie française)", "pf", "689" ], [ "Gabon", "ga", "241" ], [ "Gambia", "gm", "220" ], [ "Georgia (საქართველო)", "ge", "995" ], [ "Germany (Deutschland)", "de", "49" ], [ "Ghana (Gaana)", "gh", "233" ], [ "Gibraltar", "gi", "350" ], [ "Greece (Ελλάδα)", "gr", "30" ], [ "Greenland (Kalaallit Nunaat)", "gl", "299" ], [ "Grenada", "gd", "1473" ], [ "Guadeloupe", "gp", "590", 0 ], [ "Guam", "gu", "1671" ], [ "Guatemala", "gt", "502" ], [ "Guer
7nsey", "gg", "44", 1 ], [ "Guinea (Guinée)", "gn", "224" ], [ "Guinea-Bissau (Guiné Bissau)", "gw", "245" ], [ "Guyana", "gy", "592" ], [ "Haiti", "ht", "509" ], [ "Honduras", "hn", "504" ], [ "Hong Kong (香港)", "hk", "852" ], [ "Hungary (Magyarország)", "hu", "36" ], [ "Iceland (Ísland)", "is", "354" ], [ "India (भारत)", "in", "91" ], [ "Indonesia", "id", "62" ], [ "Iran (‫ایران‬‎)", "ir", "98" ], [ "Iraq (‫العراق‬‎)", "iq", "964" ], [ "Ireland", "ie", "353" ], [ "Isle of Man", "im", "44", 2 ],  [ "Italy (Italia)", "it", "39", 0 ], [ "Jamaica", "jm", "1", 4, [ "876", "658" ] ], [ "Japan (日本)", "jp", "81" ], [ "Jersey", "je", "44", 3 ], [ "Jordan (‫الأردن‬‎)", "jo", "962" ], [ "Kazakhstan (Казахстан)", "kz", "7", 1 ], [ "Kenya", "ke", "254" ], [ "Kiribati", "ki", "686" ], [ "Kosovo", "xk", "383" ], [ "Kuwait (‫الكويت‬‎)", "kw", "965" ], [ "Kyrgyzstan (Кыргызстан)", "kg", "996" ], [ "Laos (ລາວ)", "la", "856" ], [ "Latvia (Latvija)", "lv", "371" ], [ "Lebanon (‫لبنان‬‎)", "lb", "961" ], [ "Lesotho", "ls", "266" ], [ "Liberia", "lr", "231" ], [ "Libya (‫ليبيا‬‎)", "ly", "218" ], [ "Liechtenstein", "li", "423" ], [ "Lithuania (Lietuva)", "lt", "370" ], [ "Luxembourg", "lu", "352" ], [ "Macau (澳門)", "mo", "853" ], [ "Macedonia (FYROM) (Македонија)", "mk", "389" ], [ "Madagascar (Madagasikara)", "mg", "261" ], [ "Malawi", "mw", "265" ], [ "Malaysia", "my", "60" ], [ "Maldives", "mv", "960" ], [ "Mali", "ml", "223" ], [ "Malta", "mt", "356" ], [ "Marshall Islands", "mh", "692" ], [ "Martinique", "mq", "596" ], [ "Mauritania (‫موريتانيا‬‎)", "mr", "222" ], [ "Mauritius (Moris)", "mu", "230" ], [ "Mayotte", "yt", "262", 1 ], [ "Mexico (México)", "mx", "52" ], [ "Micronesia", "fm", "691" ], [ "Moldova (Republica Moldova)", "md", "373" ], [ "Monaco", "mc", "377" ], [ "Mongolia (Монгол)", "mn", "976" ], [ "Montenegro (Crna Gora)", "me", "382" ], [ "Montserrat", "ms", "1664" ], [ "Morocco (‫المغرب‬‎)", "ma", "212", 0 ], [ "Mozambique (Moçambique)", "mz", "258" ], [ "Myanmar (Burma) (မြန်မာ)", "mm", "95" ], [ "Namibia (Namibië)", "na", "264" ], [ "Nauru", "nr", "674" ], [ "Nepal (नेपाल)", "np", "977" ], [ "Netherlands (Nederland)", "nl", "31" ], [ "New Caledonia (Nouvelle-Calédonie)", "nc", "687" ], [ "New Zealand", "nz", "64" ], [ "Nicaragua", "ni", "505" ], [ "Niger (Nijar)", "ne", "227" ], [ "Nigeria", "ng", "234" ], [ "Niue", "nu", "683" ], [ "Norfolk Island", "nf", "672" ], [ "North Korea (조선 민주주의 인민 공화국)", "kp", "850" ], [ "Northern Mariana Islands", "mp", "1670" ], [ "Norway (Norge)", "no", "47", 0 ], [ "Oman (‫عُمان‬‎)", "om", "968" ], [ "Pakistan (‫پاکستان‬‎)", "pk", "92" ], [ "Palau", "pw", "680" ], [ "Palestine (‫فلسطين‬‎)", "ps", "970" ], [ "Panama (Panamá)", "pa", "507" ], [ "Papua New Guinea", "pg", "675" ], [ "Paraguay", "py", "595" ], [ "Peru (Perú)", "pe", "51" ], [ "Philippines", "ph", "63" ], [ "Poland (Polska)", "pl", "48" ], [ "Portugal", "pt", "351" ], [ "Puerto Rico", "pr", "1", 3, [ "787", "939" ] ], [ "Qatar (‫قطر‬‎)", "qa", "974" ], [ "Réunion (La Réunion)", "re", "262", 0 ], [ "Romania (România)", "ro", "40" ],  [ "Rwanda", "rw", "250" ], [ "Saint Barthélemy", "bl", "590", 1 ], [ "Saint Helena", "sh", "290" ], [ "Saint Kitts and Nevis", "kn", "1869" ], [ "Saint Lucia", "lc", "1758" ], [ "Saint Martin (Saint-Martin (partie française))", "mf", "590", 2 ], [ "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)", "pm", "508" ], [ "Saint Vincent and the Grenadines", "vc", "1784" ], [ "Samoa", "ws", "685" ], [ "San Marino", "sm", "378" ], [ "São Tomé and Príncipe (São Tomé e Príncipe)", "st", "239" ], [ "Saudi Arabia (‫المملكة العربية السعودية‬‎)", "sa", "966" ], [ "Senegal (Sénégal)", "sn", "221" ], [ "Serbia (Србија)", "rs", "381" ], [ "Seychelles", "sc", "248" ], [ "Sierra Leone", "sl", "232" ], [ "Singapore", "sg", "65" ], [ "Sint Maarten", "sx", "1721" ], [ "Slovakia (Slovensko)", "sk", "421" ], [ "Slovenia (Slovenija)", "si", "386" ], [ "Solomon Islands", "sb", "677" ], [ "Somalia (Soomaaliya)", "so", "252" ], [ "South Africa", "za", "27" ], [ "South Korea (대한민국)", "kr", "82" ], [ "South Sudan (‫جنوب السودان‬‎)", "ss", "211" ], [ "Spain (España)", "es", "34" ], [ "Sri Lanka (ශ්‍රී ලංකාව)", "lk", "94" ], [ "Sudan (‫السودان‬‎)", "sd", "249" ], [ "Suriname", "sr", "597" ], [ "Svalbard and Jan Mayen", "sj", "47", 1 ], [ "Swaziland", "sz", "268" ], [ "Sweden (Sverige)", "se", "46" ], [ "Switzerland (Schweiz)", "ch", "41" ], [ "Syria (‫سوريا‬‎)", "sy", "963" ], [ "Taiwan (台灣)", "tw", "886" ], [ "Tajikistan", "tj", "992" ], [ "Tanzania", "tz", "255" ], [ "Thailand (ไทย)", "th", "66" ], [ "Timor-Leste", "tl", "670" ], [ "Togo", "tg", "228" ], [ "Tokelau", "tk", "690" ], [ "Tonga", "to", "676" ], [ "Trinidad and Tobago", "tt", "1868" ], [ "Tunisia (‫تونس‬‎)", "tn", "216" ], [ "Turkey (Türkiye)", "tr", "90" ], [ "Turkmenistan", "tm", "993" ], [ "Turks and Caicos Islands", "tc", "1649" ], [ "Tuvalu", "tv", "688" ], [ "U.S. Virgin Islands", "vi", "1340" ], [ "Uganda", "ug", "256" ],  [ "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)", "ae", "971" ], [ "United Kingdom", "gb", "44", 0 ],  [ "Uruguay", "uy", "598" ], [ "Uzbekistan (Oʻzbekiston)", "uz", "998" ], [ "Vanuatu", "vu", "678" ], [ "Vatican City (Città del Vaticano)", "va", "39", 1 ], [ "Venezuela", "ve", "58" ], [ "Vietnam (Việt Nam)", "vn", "84" ], [ "Wallis and Futuna (Wallis-et-Futuna)", "wf", "681" ], [ "Western Sahara (‫الصحراء الغربية‬‎)", "eh", "212", 1 ], [ "Yemen (‫اليمن‬‎)", "ye", "967" ], [ "Zambia", "zm", "260" ], [ "Zimbabwe", "zw", "263" ], [ "Åland Islands", "ax", "358", 1 ] ];
8
9// wrap in UMD
10(function(factory) {
11    var intlTelInput = factory(window, document);
12    if (typeof module === "object" && module.exports) module.exports = intlTelInput; else window.intlTelInput = intlTelInput;
13})(function(window, document, undefined) {
14    "use strict";
15    return function() {
16        // Array of country objects for the flag dropdown.
17        // Here is the criteria for the plugin to support a given country/territory
18        // - It has an iso2 code: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
19        // - It has it's own country calling code (it is not a sub-region of another country): https://en.wikipedia.org/wiki/List_of_country_calling_codes
20        // - It has a flag in the region-flags project: https://github.com/behdad/region-flags/tree/gh-pages/png
21        // - It is supported by libphonenumber (it must be listed on this page): https://github.com/googlei18n/libphonenumber/blob/master/resources/ShortNumberMetadata.xml
22        // Each country array has the following information:
23        // [
24        //    Country name,
25        //    iso2 code,
26        //    International dial code,
27        //    Order (if >1 country with same dial code),
28        //    Area codes
29        // ]
30        var allCountries = window.allCountries;
31        // loop over all of the countries above, restructuring the data to be objects with named keys
32        for (var i = 0; i < allCountries.length; i++) {
33            var c = allCountries[i];
34            allCountries[i] = {
35                name: c[0],
36                iso2: c[1],
37                dialCode: c[2],
38                priority: c[3] || 0,
39                areaCodes: c[4] || null
40            };
41        }
42        window.intlTelInputGlobals = {
43            instances: {}
44        };
45        // these vars persist through all instances of the plugin
46        var id = 0, defaults = {
47            // whether or not to allow the dropdown
48            allowDropdown: true,
49            // if there is just a dial code in the input: remove it on blur, and re-add it on focus
50            autoHideDialCode: true,
51            // add a placeholder in the input with an example number for the selected country
52            autoPlaceholder: "polite",
53            // modify the auto placeholder
54            customPlaceholder: null,
55            // append menu to specified element
56            dropdownContainer: null,
57            // don't display these countries
58            excludeCountries: [],
59            // format the input value during initialisation and on setNumber
60            formatOnDisplay: true,
61            // geoIp lookup function
62            geoIpLookup: null,
63            // inject a hidden input with this name, and on submit, populate it with the result of getNumber
64            hiddenInput: "",
65            // initial country
66            initialCountry: "",
67            // localized country names e.g. { 'de': 'Deutschland' }
68            localizedCountries: null,
69            // don't insert international dial codes
70            nationalMode: true,
71            // display only these countries
72            onlyCountries: [],
73            // number type to use for placeholders
74            placeholderNumberType: "MOBILE",
75            // the countries at the top of the list. defaults to united states and united kingdom
76            preferredCountries: [ "us", "gb" ],
77            // display the country dial code next to the selected flag so it's not part of the typed number
78            separateDialCode: false,
79            // specify the path to the libphonenumber script to enable validation/formatting
80            utilsScript: ""
81        }, // https://en.wikipedia.org/wiki/List_of_North_American_Numbering_Plan_area_codes#Non-geographic_area_codes
82        regionlessNanpNumbers = [ "800", "822", "833", "844", "855", "866", "877", "880", "881", "882", "883", "884", "885", "886", "887", "888", "889" ];
83        // keep track of if the window.load event has fired as impossible to check after the fact
84        window.addEventListener("load", function() {
85            // UPDATE: use a public static field so we can fudge it in the tests
86            window.intlTelInputGlobals.windowLoaded = true;
87        });
88        // utility function to iterate over an object. can't use Object.entries or native forEac
88h because of IE11
89        var forEachProp = function(obj, callback) {
90            var keys = Object.keys(obj);
91            for (var i = 0; i < keys.length; i++) {
92                callback(keys[i], obj[keys[i]]);
93            }
94        };
95        // run a method on each instance of the plugin
96        var forEachInstance = function(method) {
97            forEachProp(window.intlTelInputGlobals.instances, function(key, value) {
98                window.intlTelInputGlobals.instances[key][method]();
99            });
100        };
101        // this is our plugin class that we will create an instance of
102        var Iti = function(input, options) {
103            var that = this;
104            this.id = id++;
105            this.telInput = input;
106            // process specified options / defaults
107            // alternative to Object.assign, which isn't supported by IE11
108            var customOptions = options || {};
109            this.options = {};
110            forEachProp(defaults, function(key, value) {
111                that.options[key] = customOptions.hasOwnProperty(key) ? customOptions[key] : value;
112            });
113            this.hadInitialPlaceholder = Boolean(input.getAttribute("placeholder"));
114        };
115        // define our class methods on the prototype
116        Iti.prototype = {
117            _init: function() {
118                var that = this;
119                // if in nationalMode, disable options relating to dial codes
120                if (this.options.nationalMode) {
121                    this.options.autoHideDialCode = false;
122                }
123                // if separateDialCode then doesn't make sense to A) insert dial code into input (autoHideDialCode), and B) display national numbers (because we're displaying the country dial code next to them)
124                if (this.options.separateDialCode) {
125                    this.options.autoHideDialCode = this.options.nationalMode = false;
126                }
127                // we cannot just test screen size as some smartphones/website meta tags will report desktop resolutions
128                // Note: for some reason jasmine breaks if you put this in the main Plugin function with the rest of these declarations
129                // Note: to target Android Mobiles (and not Tablets), we must find "Android" and "Mobile"
130                this.isMobile = /Android.+Mobile|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
131                if (this.isMobile) {
132                    // trigger the mobile dropdown css
133                    document.body.classList.add("iti-mobile");
134                    // on mobile, we want a full screen dropdown, so we must append it to the body
135                    if (!this.options.dropdownContainer) {
136                        this.options.dropdownContainer = document.body;
137                    }
138                }
139                // these promises get resolved when their individual requests complete
140                // this way the dev can do something like iti.promise.then(...) to know when all requests are complete
141                if (typeof Promise !== "undefined") {
142                    var autoCountryPromise = new Promise(function(resolve, reject) {
143                        that.resolveAutoCountryPromise = resolve;
144                        that.rejectAutoCountryPromise = reject;
145                    });
146                    var utilsScriptPromise = new Promise(function(resolve, reject) {
147                        that.resolveUtilsScriptPromise = resolve;
148                        that.rejectUtilsScriptPromise = reject;
149                    });
150                    this.promise = Promise.all([ autoCountryPromise, utilsScriptPromise ]);
151                } else {
152                    // prevent errors when Promise doesn't exist
153                    this.resolveAutoCountryPromise = this.rejectAutoCountryPromise = this.resolveUtilsScriptPromise = this.rejectUtilsScriptPromise = function() {};
154                }
155                // in various situations there could be no country selected initially, but we need to be able to assume this variable exists
156                this.selectedCountryData = {};
157                // process all the data: onlyCountries, excludeCountries, preferredCountries etc
158                this._processCountryData();
159                // generate the markup
160                this._generateMarkup();
161                // set the initial state of the input value and the selected flag
162                this._setInitialState();
163                // start all of the event listeners: autoHideDialCode, input keydown, selectedFlag click
164                this._initListeners();
165                // utils script, and auto country
166                this._initRequests();
167            },
168            /********************
169   *  PRIVATE METHODS
170   ********************/
171            // prepare all of the country data, including onlyCountries, excludeCountries and preferredCountries options
172            _processCountryData: function() {
173                // process onlyCountries or excludeCountries array if present
174                this._processAllCountries();
175                // process the countryCodes map
176                this._processCountryCodes();
177                // process the preferredCountries
178                this._processPreferredCountries();
179                // translate countries according to localizedCountries option
180                if (this.options.localizedCountries) {
181                    this._translateCountriesByLocale();
182                }
183                // sort countries by name
184                if (this.options.onlyCountries.length || this.options.localizedCountries) {
185                    this.countries.sort(this._countryNameSort);
186                }
187            },
188            // add a country code to this.countryCodes
189            _addCountryCode: function(iso2, dialCode, priority) {
190                if (!this.countryCodes.hasOwnProperty(dialCode)) {
191                    this.countryCodes[dialCode] = [];
192                }
193                var index = priority || 0;
194                this.countryCodes[dialCode][index] = iso2;
195            },
196            // process onlyCountries or excludeCountries array if present
197            _processAllCountries: function() {
198                if (this.options.onlyCountries.length) {
199                    var lowerCaseOnlyCountries = this.options.onlyCountries.map(function(country) {
200                        return country.toLowerCase();
201                    });
202                    this.countries = allCountries.filter(function(country) {
203                        return lowerCaseOnlyCountries.indexOf(country.iso2) > -1;
204                    });
205                } else if (this.options.excludeCountries.length) {
206                    var lowerCaseExcludeCountries = this.options.excludeCountries.map(function(country) {
207                        return country.toLowerCase();
208                    });
209                    this.countries = allCountries.filter(function(country) {
210                        return lowerCaseExcludeCountries.indexOf(country.iso2) === -1;
211                    });
212                } else {
213                    this.countries = allCountries;
214                }
215            },
216            // Translate Countries by object literal provided on config
217            _translateCountriesByLocale: function() {
218                for (var i = 0; i < this.countries.length; i++) {
219                    var iso = this.countries[i].iso2.toLowerCase();
220                    if (this.options.localizedCountries.hasOwnProperty(iso)) {
221                        this.countries[i].name = this.options.localizedCountries[iso];
222                    }
223                }
224            },
225            // sort by country name
226            _countryNameSort: function(a, b) {
227                return a.name.localeCompare(b.name);
228            },
229            // process the countryCodes map
230            _processCountryCodes: function() {
231                this.countryCodes = {};
232                for (var i = 0; i < this.countries.length; i++) {
233                    var c = this.countries[i];
234                    this._addCountryCode(c.iso2, c.dialCode, c.priority);
235                    // area codes
236                    if (c.areaCodes) {
237                        for (var j = 0; j < c.areaCodes.length; j++) {
238                            // full dial code is country code + dial code
239                            this._addCountryCode(c.iso2, c.dialCode + c.areaCodes[j]);
240                        }
241                    }
242                }
243            },
244            // process preferred countries - iterate through the preferences, fetching the country data for each one
245            _processPreferredCountries: function() {
246                this.preferredCountries = [];
247                for (var i = 0; i < this.options.preferredCountries.length; i++) {
248                    var countryCode = this.options.preferredCountries[i].toLowerCase(), countryData = this._getCountryData(countryCode, false, true);
249                    if (countryData) {
250                        this.preferredCountries.push(countryData);
251                    }
252                }
253            },
254            // create a DOM element
255            _createEl: function(name, attrs, container) {
256                var el = document.createElement(name);
257                if (attrs) {
258                    forEachProp(attrs, function(key, value) {
259                        el.setAttribute(key, value);
260                    });
261                }
262                if (container) container.appendChild(el);
263                return el;
264            },
265            // generate all of the markup for the plugin: the selected flag overlay, and the dropdown
266            _generateMarkup: function() {
267                // prevent autocomplete as there's no safe, cross-browser event we can react to, so it can easily put the plugin in an inconsistent state e.g. the wrong flag selected for the autocompleted number, which on submit could mean the wrong number is saved (esp in nationalMode)
268                this.telInput.setAttribute("autocomplete", "off");
269                // containers (mostly for positioning)
270                var parentClass = "intl-tel-input";
271                if (this.options.allowDropdown) {
272                    parentClass += " allow-dropdown";
273                }
274                if (this.options.separateDialCode) {
275                    parentClass += " separate-dial-code";
276                }
277                var wrapper = this._createEl("div", {
278                    "class": parentClass
279                });
280                this.telInput.parentNode.insertBefore(wrapper, this.telInput);
281                this.flagsContainer = this._createEl("div", {
282                    "class": "flag-container"
283                }, wrapper);
284                wrapper.appendChild(this.telInput);
285                // selected flag (displayed to left of input)
286                this.selectedFlag = this._createEl("div", {
287                    "class": "selected-flag",
288                    role: "combobox",
289                    "aria-owns": "country-listbox"
290                }, this.flagsContainer);
291                this.selectedFlagInner = this._createEl("div", {
292                    "class": "iti-flag"
293                }, this.selectedFlag);
294                if (this.options.separateDialCode) {
295                    this.selectedDialCode = this._createEl("div", {
296                        "class": "selected-dial-code"
297                    }, this.selectedFlag);
298                }
299                if (this.options.allowDropdown) {
300                    // make element focusable and tab navigable
301                    this.selectedFlag.setAttribute("tabindex", "0");
302                    this.dropdownArrow = this._createEl("div", {
303                        "class": "iti-arrow"
304                    }, this.selectedFlag);
305                    // country dropdown: preferred countries, then divider, then all countries
306                    this.countryList = this._createEl("ul", {
307                        "class": "country-list hide",
308                        id: "country-listbox",
309                        "aria-expanded": "false",
310                        role: "listbox"
311                    });
312                    if (this.preferredCountries.length) {
313                        this._appendListItems(this.preferredCountries, "preferred");
314                        this._createEl("li", {
315                            "class": "divider",
316                            role: "separator",
317                            "aria-disabled": "true"
318                        }, this.countryList);
319                    }
320                    this._appendListItems(this.countries, "standard");
321                    // create dropdownContainer markup
322                    if (this.options.dropdownContainer) {
323                        this.dropdown = this._createEl("div", {
324                            "class": "intl-tel-input iti-container"
325                        });
326                        this.dropdown.appendChild(this.countryList);
327                    } else {
328                        this.flagsContainer.appendChild(this.countryList);
329                    }
330                }
331                if (this.options.hiddenInput) {
332                    var hiddenInputName = this.options.hiddenInput;
333                    var name = this.telInput.getAttribute("name");
334                    if (name) {
335                        var i = name.lastIndexOf("[");
336                        // if input name contains square brackets, then give the hidden input the same name,
337                        // replacing the contents of the last set of brackets with the given hiddenInput name
338                        if (i !== -1) hiddenInputName = name.substr(0, i) + "[" + hiddenInputName + "]";
339                    }
340                    this.hiddenInput = this._createEl("input", {
341                        type: "hidden",
342                        name: hiddenInputName
343                    });
344                    wrapper.appendChild(this.hiddenInput);
345                }
346            },
347            // add a country <li> to the countryList <ul> container
348            _appendListItems: function(countries, className) {
349                // we create so many DOM elements, it is faster to build a temp string
350                // and then add everything to the DOM in one go at the end
351                var tmp = "";
352                // for each country
353                for (var i = 0; i < countries.length; i++) {
354                    var c = countries[i];
355                    // open the list item
356                    tmp += "<li class='country " + className + "' id='iti-item-" + c.iso2 + "' role='option' data-dial-code='" + c.dialCode + "' data-country-code='" + c.iso2 + "'>";
357                    // add the flag
358                    tmp += "<div class='flag-box'><div class='iti-flag " + c.iso2 + "'></div></div>";
359                    // and the country name and dial code
360                    tmp += "<span class='country-name'>" + c.name + "</span>";
361                    tmp += "<span class='dial-code'>+" + c.dialCode + "</span>";
362                    // close the list item
363                    tmp += "</li>";
364                }
365                this.countryList.insertAdjacentHTML("beforeend", tmp);
366            },
367            // set the initial state of the input value and the selected flag by:
368            // 1. extracting a dial code from the given number
369            // 2. using explicit initialCountry
370            // 3. picking the first preferred country
371            // 4. picking the first country
372            _setInitialState: function() {
373                var val = this.telInput.value;
374                var dialCode = this._getDialCode(val);
375                var isRegionlessNanp = this._isRegionlessNanp(val);
376                // if we already have a dial code, and it's not a regi
376onlessNanp, we can go ahead and set the flag, else fall back to the default country
377                if (dialCode && !isRegionlessNanp) {
378                    this._updateFlagFromNumber(val);
379                } else if (this.options.initialCountry !== "auto") {
380                    // see if we should select a flag
381                    if (this.options.initialCountry) {
382                        this._setFlag(this.options.initialCountry.toLowerCase());
383                    } else {
384                        if (dialCode && isRegionlessNanp) {
385                            // has intl dial code, is regionless nanp, and no initialCountry, so default to US
386                            this._setFlag("us");
387                        } else {
388                            // no dial code and no initialCountry, so default to first in list
389                            this.defaultCountry = this.preferredCountries.length ? this.preferredCountries[0].iso2 : this.countries[0].iso2;
390                            if (!val) {
391                                this._setFlag(this.defaultCountry);
392                            }
393                        }
394                    }
395                    // if empty and no nationalMode and no autoHideDialCode then insert the default dial code
396                    if (!val && !this.options.nationalMode && !this.options.autoHideDialCode && !this.options.separateDialCode) {
397                        this.telInput.value = "+" + this.selectedCountryData.dialCode;
398                    }
399                }
400                // NOTE: if initialCountry is set to auto, that will be handled separately
401                // format
402                if (val) {
403                    // this wont be run after _updateDialCode as that's only called 
403if no val
404                    this._updateValFromNumber(val);
405                }
406            },
407            // initialise the main event listeners: input keyup, and click selected flag
408            _initListeners: function() {
409                this._initKeyListeners();
410                if (this.options.autoHideDialCode) {
411                    this._initFocusListeners();
412                }
413                if (this.options.allowDropdown) {
414                    this._initDropdownListeners();
415                }
416                if (this.hiddenInput) {
417                    this._initHiddenInputListener();
418                }
419            },
420            // update hidden input on form submit
421            _initHiddenInputListener: function() {
422                var that = this;
423                this._handleHiddenInputSubmit = function() {
424                    that.hiddenInput.value = that.getNumber();
425                };
426                var form = this.telInput.form;
427                if (form) form.addEventListener("submit", this._handleHiddenInputSubmit);
428            },
429            // iterate through parent nodes to find the closest label ancestor, if it exists
430            _getClosestLabel: function() {
431                var el = this.telInput;
432                while (el && el.tagName !== "LABEL") el = el.parentNode;
433                return el;
434            },
435            // initialise the dropdown listeners
436            _initDropdownListeners: function() {
437                var that = this;
438                // hack for input nested inside label (which is valid markup): clicking the selected-flag to open the dropdown would then automatically trigger a 2nd click on the input which would close it again
439                this._handleLabelClick = function(e) {
440                    // if the dropdown is closed, then focus the input, else ignore the click
441                    if (that.countryList.classList.contains("hide")) {
442                        that.telInput.focus();
443                    } else {
444                        e.preventDefault();
445                    }
446                };
447                var label = this._getClosestLabel();
448                if (label) label.addEventListener("click", this._handleLabelClick);
449                // toggle country dropdown on click
450                this._handleClickSelectedFlag = function() {
451                    // only intercept this event if we're opening the dropdown
452                    // else let it bubble up to the top ("click-off-to-close" listener)
453                    // we cannot just stopPropagation as it may be needed to close another instance
454                    if (that.countryList.classList.contains("hide") && !that.telInput.disabled && !that.telInput.readOnly) {
455                        that._showDropdown();
456                    }
457                };
458                this.selectedFlag.addEventListener("click", this._handleClickSelectedFlag);
459                // open dropdown list if currently focused
460                this._handleFlagsContainerKeydown = function(e) {
461                    var isDropdownHidden = that.countryList.classList.contains("hide");
462                    if (isDropdownHidden && [ "ArrowUp", "ArrowDown", " ", "Enter" ].indexOf(e.key) !== -1) {
463                        // prevent form from being submitted if "ENTER" was pressed
464                        e.preventDefault();
465                        // prevent event from being handled again by document
466                        e.stopPropagation();
467                        that._showDropdown();
468                    }
469                    // allow navigation from dropdown to input on TAB
470                    if (e.key === "Tab") that._closeDropdown();
471                };
472                this.flagsContainer.addEventListener("keydown", this._handleFlagsContainerKeydown);
473            },
474            // init many requests: utils script / geo ip lookup
475            _initRequests: function() {
476                var that = this;
477                // if the user has specified the path to the utils script, fetch it on window.load, else resolve
478                if (this.options.utilsScript && !window.intlTelInputUtils) {
479                    // if the plugin is being initialised after the window.load event has already been fired
480                    if (window.intlTelInputGlobals.windowLoaded) {
481                        window.intlTelInputGlobals.loadUtils(this.options.utilsScript);
482                    } else {
483                        // wait until the load event so we don't block any other requests e.g. the flags image
484                        window.addEventListener("load", function() {
485                            window.intlTelInputGlobals.loadUtils(that.options.utilsScript);
486                        });
487                    }
488                } else {
489                    this.resolveUtilsScriptPromise();
490                }
491                if (this.options.initialCountry === "auto") {
492                    this._loadAutoCountry();
493                } else {
494                    this.resolveAutoCountryPromise();
495                }
496            },
497            // perform the geo ip lookup
498            _loadAutoCountry: function() {
499                var that = this;
500                // 3 options:
501                // 1) already loaded (we're done)
502                // 2) not already started loading (start)
503                // 3) already started loading (do nothing - just wait for loading callback to fire)
504                if (window.intlTelInputGlobals.autoCountry) {
505                    this.handleAutoCountry();
506                } else if (!window.intlTelInputGlobals.startedLoadingAutoCountry) {
507                    // don't do this twice!
508                    window.intlTelInputGlobals.startedLoadingAutoCountry = true;
509                    if (typeof this.options.geoIpLookup === "function") {
510                        this.options.geoIpLookup(function(countryCode) {
511                            window.intlTelInputGlobals.autoCountry = countryCode.toLowerCase();
512                            // tell all instances the auto country is ready
513                            // TODO: this should just be the current instances
514                            // UPDATE: use setTimeout in case their geoIpLookup function calls this callback straight away (e.g. if they have already done the geo ip lookup somewhere else). Using setTimeout means that the current thread of execution will finish before executing this, which allows the plugin to finish initialising.
515                            setTimeout(function() {
516                                forEachInstance("handleAutoCountry");
517                            });
518                        }, function() {
519                            forEachInstance("rejectAutoCountryPromise");
520                        });
521                    }
522                }
523            },
524            // initialize any key listeners
525            _initKeyListeners: function() {
526                var that = this;
527                // update flag on keyup
528                this._handleKeyupEvent = function() {
529                    if (that._updateFlagFromNumber(that.telInput.value)) {
530                        that._triggerCountryChange();
531                    }
532                };
533                this.telInput.addEventListener("keyup", this._handleKeyupEvent);
534                // update flag on cut/paste events (now supported in all major browsers)
535                this._handleClipboardEvent = function() {
536                    // hack because "paste" event is fired before input is updated
537                    setTimeout(that._handleKeyupEvent);
538                };
539                this.telInput.addEventListener("cut", this._handleClipboardEvent);
540                this.telInput.addEventListener("paste", this._handleClipboardEvent);
541            },
542            // adhere to the input's maxlength attr
543            _cap: function(number) {
544                var max = this.telInput.getAttribute("maxlength");
545                return max && number.length > max ? number.substr(0, max) : number;
546            },
547            // listen for mousedown, focus and blur (for autoHideDialCode feature)
548            _initFocusListeners: function() {
549                var that = this;
550                // mousedown decides where the cursor goes, so if we're focusing we must preventDefault as we'll be inserting the dial code, and we want the cursor to be at the end no matter where they click
551                this._handleMousedownFocusEvent = function(e) {
552                    if (that.telInput !== document.activeElement && !that.telInput.value) {
553                        e.preventDefault();
554                        // but this also cancels the focus, so we must trigger that manually
555                        that.telInput.focus();
556                    }
557                };
558                this.telInput.addEventListener("mousedown", this._handleMousedownFocusEvent);
559                this._handleKeypressPlusEvent = function(e) {
560                    if (e.key === "+") that.telInput.value = "";
561                };
562                // on focus: if empty, insert the dial code for the currently selected flag
563                this._handleFocusEvent = function(e) {
564                    if (!that.telInput.value && !that.telInput.readOnly && that.selectedCountryData.dialCode) {
565                        // insert the dial code
566                        that.telInput.value = "+" + that.selectedCountryData.dialCode;
567                        // after auto-inserting a dial code, if the first key they hit is '+' then assume they are entering a new number, so remove the dial code. use keypress instead of keydown because keydown gets triggered for the shift key (required to hit the + key), and instead of keyup because that shows the new '+' before removing the old one
568                        that.telInput.addEventListener("keypress", that._handleKeypressPlusEvent);
569                        // after tabbing in, make sure the cursor is at the end we must use setTimeout to get outside of the focus handler as it seems the selection happens after that
570                        setTimeout(function() {
571                            var len = that.telInput.value.length;
572                            that.telInput.setSelectionRange(len, len);
573                        });
574                    }
575                };
576                this.telInput.addEventListener("focus", this._handleFocusEvent);
577                // on blur or form submit: if just a dial code then remove it
578                this._handleSubmitOrBlurEvent = function() {
579                    that._removeEmptyDialCode();
580                };
581                var form = this.telInput.form;
582                if (form) form.addEventListener("submit", this._handleSubmitOrBlurEvent);
583                this.telInput.addEventListener("blur", this._handleSubmitOrBlurEvent);
584            },
585            _removeEmptyDialCode: function() {
586                var startsPlus = this.telInput.value.charAt(0) === "+";
587                if (startsPlus) {
588                    var numeric = this._getNumeric(this.telInput.value);
589                    // if just a plus, or if just a dial code
590                    if (!numeric || this.selectedCountryData.dialCode == numeric) {
591                        this.telInput.value = "";
592                    }
593                }
594                // remove the keypress listener we added on focus
595                this.telInput.removeEventListener("keypress", this._handleKeypressPlusEvent);
596            },
597            // extract the numeric digits from the given string
598            _getNumeric: function(s) {
599                return s.replace(/\D/g, "");
600            },
601            // trigger a custom event on the input
602            _trigger: function(name) {
603                // have to use old school document.createEvent as IE11 doesn't support `new Event()` syntax
604                var e = document.createEvent("Event");
605                e.initEvent(name, true, true);
606                //can bubble, and is cancellable
607                this.telInput.dispatchEvent(e);
608            },
609            // show the dropdown
610            _showDropdown: function() {
611                this.countryList.classList.remove("hide");
612                this.countryList.setAttribute("aria-expanded", "true");
613                this._setDropdownPosition();
614                // update highlighting and scroll to active list item
615                var activeItem = this.countryList.querySelector(".active");
616                if (activeItem) {
617                    this._highlightListItem(activeItem);
618                    this._scrollTo(activeItem);
619                }
620                // bind all the dropdown-related listeners: mouseover, click, click-off, keydown
621                this._bindDropdownListeners();
622                // update the arrow
623                this.dropdownArrow.classList.add("up");
624                this._trigger("open:countrydropdown");
625            },
626            // make sure the el has the className or not, depending on the value of shouldHaveClass
627            _toggleClass: function(el, className, shouldHaveClass) {
628                if (shouldHaveClass && !el.classList.contains(className)) el.classList.add(className); else if (!shouldHaveClass && el.classList.contains(className)) el.classList.remove(className);
629            },
630            // decide where to position dropdown (depends on position within viewport, and scroll)
631            _setDropdownPosition: function() {
632                var that = this;
633                if (this.options.dropdownContainer) {
634                    this.options.dropdownContainer.appendChild(this.dropdown);
635                }
636                if (!this.isMobile) {
637                    var pos = this.telInput.getBoundingClientRect(), // windowTop from https://stackoverflow.com/a/14384091/217866
638                    windowTop = window.pageYOffset || document.documentElement.scrollTop, inputTop = pos.top + windowTop, dropdownHeight = this.countryList.offsetHeight, // dropdownFitsBelow = (dropdownBottom < windowBottom)
639                    dropdownFitsBelow = inputTop + this.telInput.offsetHeight + dropdownHeight < windowTop + window.innerHeight, dropdownFitsAbove = inputTop - dropdownHeight > windowTop;
640                    // by default, the dropdown will be below the input. If we want to position it above the input, we add the dropup class.
641                    this._toggleClass(this.countryList, "dropup", !dropdownFitsBelow && dropdownFitsAbove);
642                    // if dropdownContainer is enabled, calculate postion
643                    if (this.options.dropdownContainer) {
644                        // by default the dropdown will be directly over the input because it's not in the flow. If we want to position it below, we need to add some extra top value.
645                        var extraTop = !dropdownFitsBelow && dropdownFitsAbove ? 0 : this.telInput.offsetHeight;
646                        // calculate placement
647                        this.dropdown.style.top = "" + (inputTop + extraTop) + "px";
648                        this.dropdown.style.left = "" + (pos.left + document.body.scrollLeft) + "px";
649                        // close menu on window scroll
650                        this._handleWindowScroll = function() {
651                            that._closeDropdown();
652                        };
653                        window.addEventListener("scroll", this._handleWindowScroll);
654                    }
655                }
656            },
657            // iterate through parent nodes to find the closest list item
658            _getClosestListItem: function(target) {
659                var el = target;
660                while (el && el !== this.countryList && !el.classList.contains("country")) el = el.parentNode;
661                // if we reached the countryList element, then return null
662                return el === this.countryList ? null : el;
663            },
664            // we only bind dropdown listeners when the dropdown is open
665            _bindDropdownListeners: function() {
666                var that = this;
667                // when mouse over a list item, just highlight that one
668                // we add the class "highlight", so if they hit "enter" we know 
668which one to select
669                this._handleMouseoverCountryList = function(e) {
670                    // handle event delegation, as we're listening for this event on the countryList
671                    var listItem = that._getClosestListItem(e.target);
672                    if (listItem) that._highlightListItem(listItem);
673                };
674                this.countryList.addEventListener("mouseover", this._handleMouseoverCountryList);
675                // listen for country selection
676                this._handleClickCountryList = function(e) {
677                    var listItem = that._getClosestListItem(e.target);
678                    if (listItem) that._selectListItem(listItem);
679                };
680                this.countryList.addEventListener("click", this._handleClickCountryList);
681                // click off to close
682                // (except when this initial opening click is bubbling up)
683                // we cannot just stopPropagation as it may be needed to close another instance
684                var isOpening = true;
685                this._handleClickOffToClose = function() {
686                    if (!isOpening) that._closeDropdown();
687                    isOpening = false;
688                };
689                document.documentElement.addEventListener("click", this._handleClickOffToClose);
690                // listen for up/down scrolling, enter to select, or letters to jump to country name.
691                // use keydown as keypress doesn't fire for non-char keys and we want to catch if they
692                // just hit down and hold it to scroll down (no keyup event).
693                // listen on the document because that's where key events are triggered if no input has focus
694                var query = "", queryTimer = null;
695                this._handleKeydownOnDropdown = function(e) {
696                    // prevent down key from scrolling the whole page,
697                    // and enter key from submitting a form etc
698                    e.preventDefault();
699                    // up and down to navigate
700                    if (e.key === "ArrowUp" || e.key === "ArrowDown") that._handleUpDownKey(e.key); else if (e.key === "Enter") that._handleEnterKey(); else if (e.key === "Escape") that._closeDropdown(); else if (/^[a-zA-ZÀ-ÿ ]$/.test(e.key)) {
701                        // jump to countries that start with the query string
702                        if (queryTimer) clearTimeout(queryTimer);
703                        query += e.key.toLowerCase();
704                        that._searchForCountry(query);
705                        // if the timer hits 1 second, reset the query
706                        queryTimer = setTimeout(function() {
707                            query = "";
708                        }, 1e3);
709                    }
710                };
711                document.addEventListener("keydown", this._handleKeydownOnDropdown);
712            },
713            // highlight the next/prev item in the list (and ensure it is visible)
714            _handleUpDownKey: function(key) {
715                var current = this.countryList.querySelector(".country.highlight");
716                var next = key === "ArrowUp" ? current.previousElementSibling : current.nextElementSibling;
717                if (next) {
718                    // skip the divider
719                    if (next.classList.contains("divider")) {
720                        next = key === "ArrowUp" ? next.previousElementSibling : next.nextElementSibling;
721                    }
722                    this._highlightListItem(next);
723                    this._scrollTo(next);
724                }
725            },
726            // select the currently highlighted item
727            _handleEnterKey: function() {
728                var currentCountry = this.countryList.querySelector(".country.highlight");
729                if (currentCountry) {
730                    this._selectListItem(currentCountry);
731                }
732            },
733            // find the first list item whose name starts with the query string
734            _searchForCountry: function(query) {
735                for (var i = 0; i < this.countries.length; i++) {
736                    if (this._startsWith(this.countries[i].name, query)) {
737                        var listItem = this.countryList.querySelector("#iti-item-" + this.countries[i].iso2);
738                        // update highlighting and scroll
739                        this._highlightListItem(listItem);
740                        this._scrollTo(listItem, true);
741                        break;
742                    }
743                }
744            },
745            // check if string a starts with string b
746            _startsWith: function(a, b) {
747                return a.substr(0, b.length).toLowerCase() == b;
748            },
749            // update the input's value to the given val (format first if possible)
750            // NOTE: this is called from _setInitialState, handleUtils and setNumber
751            _updateValFromNumber: function(number) {
752                if (this.options.formatOnDisplay && window.intlTelInputUtils && this.selectedCountryData) {
753                    var format = !this.options.separateDialCode && (this.options.nationalMode || number.charAt(0) != "+") ? intlTelInputUtils.numberFormat.NATIONAL : intlTelInputUtils.numberFormat.INTERNATIONAL;
754                    number = intlTelInputUtils.formatNumber(number, this.selectedCountryData.iso2, format);
755                }
756                number = this._beforeSetNumber(number);
757                this.telInput.value = number;
758            },
759            // check if need to select a new flag based on the given number
760            // Note: called from _setInitialState, keyup handler, setNumber
761            _updateFlagFromNumber: function(number) {
762                // if we're in nationalMode and we already have US/Canada selected, make sure the number starts with a +1 so _getDialCode will be able to extract the area code
763                // update: if we dont yet have selectedCountryData, but we're here (trying to update the flag from the number), that means we're initialising the plugin with a number that already has a dial code, so fine to ignore this bit
764                if (number && this.options.nationalMode && this.selectedCountryData.dialCode == "1" && number.charAt(0) != "+") {
765                    if (number.charAt(0) != "1") {
766                        number = "1" + number;
767                    }
768                    number = "+" + number;
769                }
770                // try and extract valid dial code from input
771                var dialCode = this._getDialCode(number), countryCode = null, numeric = this._getNumeric(number);
772                if (dialCode) {
773                    // check if one of the matching countries is already selected
774                    var countryCodes = this.countryCodes[this._getNumeric(dialCode)], alreadySelected = countryCodes.indexOf(this.selectedCountryData.iso2) !== -1, // check if the given number contains a NANP area code i.e. the only dialCode that could be extracted was +1 (instead of say +1204) and the actual number's length is >=4
775                    isNanpAreaCode = dialCode == "+1" && numeric.length >= 4, nanpSelected = this.selectedCountryData.dialCode == "1";
776                    // only update the flag if:
777                    // A) NOT (we currently have a NANP flag selected, and the number is a regionlessNanp)
778                    // AND
779                    // B) either a matching country is not already selected OR the number contains a NANP area code (ensure the flag is set to the first matching country)
780                    if (!(nanpSelected && this._isRegionlessNanp(numeric)) && (!alreadySelected || isNanpAreaCode)) {
781                        // if using onlyCountries option, countryCodes[0] may be empty, so we must find the first non-empty index
782                        for (var j = 0; j < countryCodes.length; j++) {
783                            if (countryCodes[j]) {
784                                countryCode = countryCodes[j];
785                                break;
786                            }
787                        }
788                    }
789                } else if (number.charAt(0) == "+" && numeric.length) {
790                    // invalid dial code, so empty
791                    // Note: use getNumeric here because the number has not been formatted yet, so could contain bad chars
792                    countryCode = "";
793                } else if (!number || number == "+") {
794                    // empty, or just a plus, so default
795                    countryCode = this.defaultCountry;
796                }
797                if (countryCode !== null) {
798                    return this._setFlag(countryCode);
799                }
800                return false;
801            },
802            // check if the given number is a regionless NANP number (expects the number to contain an international dial code)
803            _isRegionlessNanp: function(number) {
804                var numeric = this._getNumeric(number);
805                if (numeric.charAt(0) == "1") {
806                    var areaCode = numeric.substr(1, 3);
807                    return regionlessNanpNumbers.indexOf(areaCode) !== -1;
808                }
809                return false;
810            },
811            // remove highlighting from other list items and highlight the given item
812            _highlightListItem: function(listItem) {
813                var prevItem = this.countryList.querySelector(".country.highlight");
814                if (prevItem) prevItem.classList.remove("highlight");
815                listItem.classList.add("highlight");
816            },
817            // find the country data for the given country code
818            // the ignoreOnlyCountriesOption is only used during init() while parsing the onlyCountries array
819            _getCountryData: function(countryCode, ignoreOnlyCountriesOption, allowFail) {
820                var countryList = ignoreOnlyCountriesOption ? allCountries : this.countries;
821                for (var i = 0; i < countryList.length; i++) {
822                    if (countryList[i].iso2 == countryCode) {
823                        return countryList[i];
824                    }
825                }
826                if (allowFail) {
827                    return null;
828                } else {
829                    throw new Error("No country data for '" + countryCode + "'");
830                }
831            },
832            // select the given flag, update the placeholder and the active list item
833            // Note: called from _setInitialState, _updateFlagFromNumber, _selectListItem, setCountry
834            _setFlag: function(countryCode) {
835                var prevCountry = this.selectedCountryData.iso2 ? this.selectedCountryData : {};
836                // do this first as it will throw an error and stop if countryCode is invalid
837                this.selectedCountryData = countryCode ? this._getCountryData(countryCode, false, false) : {};
838                // update the defaultCountry - we only need the iso2 from now on, so just store that
839                if (this.selectedCountryData.iso2) {
840                    this.defaultCountry = this.selectedCountryData.iso2;
841                }
842                this.selectedFlagInner.setAttribute("class", "iti-flag " + countryCode);
843                // update the selected country's title attribute
844                var title = countryCode ? this.selectedCountryData.name + ": +" + this.selectedCountryData.dialCode : "Unknown";
845                this.selectedFlag.setAttribute("title", title);
846                if (this.options.separateDialCode) {
847                    var dialCode = this.selectedCountryData.dialCode ? "+" + this.selectedCountryData.dialCode : "", parent = this.telInput.parentNode;
848                    if (prevCountry.dialCode) {
849                        parent.classList.remove("iti-sdc-" + (prevCountry.dialCode.length + 1));
850                    }
851                    if (dialCode) {
852                        parent.classList.add("iti-sdc-" + dialCode.length);
853                    }
854                    var textNode = document.createTextNode(dialCode);
855                    this.selectedDialCode.appendChild(textNode);
856                }
857                // and the input's placeholder
858                this._updatePlaceholder();
859                // update the active list item
860                if (this.options.allowDropdown) {
861                    var prevItem = this.countryList.querySelector(".country.active");
862                    if (prevItem) {
863                        prevItem.classList.remove("active");
864                        prevItem.setAttribute("aria-selected", "false");
865                    }
866                    if (countryCode) {
867                        var nextItem = this.countryList.querySelector("#iti-item-" + countryCode);
868                        nextItem.classList.add("active");
869                        nextItem.setAttribute("aria-selected", "true");
870                        this.countryList.setAttribute("aria-activedescendant", nextItem.getAttribute("id"));
871                    }
872                }
873                // return if the flag has changed or not
874                return prevCountry.iso2 !== countryCode;
875            },
876            // update the input placeholder to an example number from the currently selected country
877            _updatePlaceholder: function() {
878                var shouldSetPlaceholder = this.options.autoPlaceholder === "aggressive" || !this.hadInitialPlaceholder && this.options.autoPlaceholder === "polite";
879                if (window.intlTelInputUtils && shouldSetPlaceholder) {
880                    var numberType = intlTelInputUtils.numberType[this.options.placeholderNumberType], placeholder = this.selectedCountryData.iso2 ? intlTelInputUtils.getExampleNumber(this.selectedCountryData.iso2, this.options.nationalMode, numberType) : "";
881                    placeholder = this._beforeSetNumber(placeholder);
882                    if (typeof this.options.customPlaceholder === "function") {
883                        placeholder = this.options.customPlaceholder(placeholder, this.selectedCountryData);
884                    }
885                    this.telInput.setAttribute("placeholder", placeholder);
886                }
887            },
888            // called when the user selects a list item from the dropdown
889            _selectListItem: function(listItem) {
890                // update selected flag and active list item
891                var flagChanged = this._setFlag(listItem.getAttribute("data-country-code"));
892                this._closeDropdown();
893                this._updateDialCode(listItem.getAttribute("data-dial-code"), true);
894                // focus the input
895                this.telInput.focus();
896                // put cursor at end - this fix is required for FF and IE11 (with nationalMode=false i.e. auto inserting dial code), who try to put the cursor at the beginning the first time
897                var len = this.telInput.value.length;
898                this.telInput.setSelectionRange(len, len);
899                if (flagChanged) {
900                    this._triggerCountryChange();
901                }
902            },
903            // close the dropdown and unbind any listeners
904            _closeDropdown: function() {
905                this.countryList.classList.add("hide");
906                this.countryList.setAttribute("aria-expanded", "false");
907                // update the arrow
908                this.dropdownArrow.classList.remove("up");
909                // unbind key events
910                document.removeEventListener("keydown", this._handleKeydownOnDropdown);
911                document.documentElement.removeEventListener("click", this._handleClickOffToClose);
912                this.countryList.removeEventListener("mouseover", this._handleMouseoverCountryList);
913                this.countryList.removeEventListener("click", this._handleClickCountryList);
914                // remove menu from container
915                if (this.options.dropdownContainer) {
916                    if (!this.isMobile) window.removeEventListener("scroll", this._handleWindowScroll);
917                    if (this.dropdown.parentNode) this.dropdown.parentNode.removeChild(this.dropdown);
918                }
919                this._trigger("close:countrydropdown");
920            },
921            // check if an element is visible within it's container, else scroll until it is
922            _scrollTo: function(element, middle) {
923                var container = this.countryList, // windowTop from https://stackoverflow.com/a/14384091/2
92317866
924                windowTop = window.pageYOffset || document.documentElement.scrollTop, containerHeight = container.offsetHeight, containerTop = container.getBoundingClientRect().top + windowTop, containerBottom = containerTop + containerHeight, elementHeight = element.offsetHeight, elementTop = element.getBoundingClientRect().top + windowTop, elementBottom = elementTop + elementHeight, newScrollTop = elementTop - containerTop + container.scrollTop, middleOffset = containerHeight / 2 - elementHeight / 2;
925                if (elementTop < containerTop) {
926                    // scroll up
927                    if (middle) {
928                        newScrollTop -= middleOffset;
929                    }
930                    container.scrollTop = newScrollTop;
931                } else if (elementBottom > containerBottom) {
932                    // scroll down
933                    if (middle) {
934                        newScrollTop += middleOffset;
935                    }
936                    var heightDifference = containerHeight - elementHeight;
937                    container.scrollTop = newScrollTop - heightDifference;
938                }
939            },
940            // replace any existing dial code with the new one
941            // Note: called from _selectListItem and setCountry
942            _updateDialCode: function(newDialCode, hasSelectedListItem) {
943                var inputVal = this.telInput.value, newNumber;
944                // save having to pass this every time
945                newDialCode = "+" + newDialCode;
946                if (inputVal.charAt(0) == "+") {
947                    // there's a plus so we're dealing with a replacement (doesn't matter if nationalMode or not)
948                    var prevDialCode = this._getDialCode(inputVal);
949                    if (prevDialCode) {
950                        // current number contains a valid dial code, so replace it
951                        newNumber = inputVal.replace(prevDialCode, newDialCode);
952                    } else {
953                        // current number contains an invalid dial code, so ditch it
954                        // (no way to determine where the invalid dial code ends and the rest of the number begins)
955                        newNumber = newDialCode;
956                    }
957                } else if (this.options.nationalMode || this.options.separateDialCode) {
958                    // don't do anything
959                    return;
960                } else {
961                    // nationalMode is disabled
962                    if (inputVal) {
963                        // there is an existing value with no dial code: prefix the new dial code
964                        newNumber = newDialCode + inputVal;
965                    } else if (hasSelectedListItem || !this.options.autoHideDialCode) {
966                        // no existing value and either they've just selected a list item, or autoHideDialCode is disabled: insert new dial code
967                        newNumber = newDialCode;
968                    } else {
969                        return;
970                    }
971                }
972                this.telInput.value = newNumber;
973            },
974            // try and extract a valid international dial code from a full telephone number
975            // Note: returns the raw string inc plus character and any whitespace/dots etc
976            _getDialCode: function(number) {
977                var dialCode = "";
978                // only interested in international numbers (starting with a plus)
979                if (number.charAt(0) == "+") {
980                    var numericChars = "";
981                    // iterate over chars
982                    for (var i = 0; i < number.length; i++) {
983                        var c = number.charAt(i);
984                        // if char is number (https://stackoverflow.com/a/8935649/217866)
985                        if (!isNaN(parseInt(c, 10))) {
986                            numericChars += c;
987                            // if current numericChars make a valid dial code
988                            if (this.countryCodes[numericChars]) {
989                                // store the actual raw string (useful for matching later)
990                                dialCode = number.substr(0, i + 1);
991                            }
992                            // longest dial code is 4 chars
993                            if (numericChars.length == 4) {
994                                break;
995                            }
996                        }
997                    }
998                }
999                return dialCode;
1000            },
1001            // get the input val, adding the dial code if separateDialCode is enabled
1002            _getFullNumber: function() {
1003                var val = this.telInput.value.trim(), dialCode = this.selectedCountryData.dialCode, prefix, numericVal = this._getNumeric(val), // normalized means ensure starts with a 1, so we can match against the full dial code
1004                normalizedVal = numericVal.charAt(0) == "1" ? numericVal : "1" + numericVal;
1005                if (this.options.separateDialCode) {
1006                    // when using separateDialCode, it is visible so is effectively part of the typed number
1007                    prefix = "+" + dialCode;
1008                } else if (val && val.charAt(0) != "+" && val.charAt(0) != "1" && dialCode && dialCode.charAt(0) == "1" && dialCode.length == 4 && dialCode != normalizedVal.substr(0, 4)) {
1009                    // ensure national NANP numbers contain the area code
1010                    prefix = dialCode.substr(1);
1011                } else {
1012                    prefix = "";
1013                }
1014                return prefix + val;
1015            },
1016            // remove the dial code if separateDialCode is enabled
1017            // also cap the length if the input has a maxlength attribute
1018            _beforeSetNumber: function(number) {
1019                if (this.options.separateDialCode) {
1020                    var dialCode = this._getDialCode(number);
1021                    if (dialCode) {
1022                        // US dialCode is "+1", which is what we want
1023                        // CA dialCode is "+1 123", which is wrong - should be "+1" (as it has multiple area codes)
1024                        // AS dialCode is "+1 684", which is what we want (as it doesn't have area codes)
1025                        // Solution: if the country has area codes, then revert to just the dial code
1026                        if (this.selectedCountryData.areaCodes !== null) {
1027                            dialCode = "+" + this.selectedCountryData.dialCode;
1028                        }
1029                        // a lot of numbers will have a space separating the dial code and the main number, and some NANP numbers will have a hyphen e.g. +1 684-733-1234 - in both cases we want to get rid of it
1030                        // NOTE: don't just trim all non-numerics as may want to preserve an open parenthesis etc
1031                        var start = number[dialCode.length] === " " || number[dialCode.length] === "-" ? dialCode.length + 1 : dialCode.length;
1032                        number = number.substr(start);
1033                    }
1034                }
1035                return this._cap(number);
1036            },
1037            // trigger the 'countrychange' event
1038            _triggerCountryChange: function() {
1039                this._trigger("countrychange");
1040            },
1041            /**************************
1042   *  SECRET PUBLIC METHODS
1043   **************************/
1044            // this is called when the geoip call returns
1045            handleAutoCountry: function() {
1046                if (this.options.initialCountry === "auto") {
1047                    // we must set this even if there is an initial val in the input: in case the initial val is invali
1047d and they delete it - they should see their auto country
1048                    this.defaultCountry = window.intlTelInputGlobals.autoCountry;
1049                    // if there's no initial value in the input, then update the flag
1050                    if (!this.telInput.value) {
1051                        this.setCountry(this.defaultCountry);
1052                    }
1053                    this.resolveAutoCountryPromise();
1054                }
1055            },
1056            // this is called when the utils request completes
1057            handleUtils: function() {
1058                // if the request was successful
1059                if (window.intlTelInputUtils) {
1060                    // if there's an initial value in the input, then format it
1061                    if (this.telInput.value) {
1062                        this._updateValFromNumber(this.telInput.value);
1063                    }
1064                    this._updatePlaceholder();
1065                }
1066                this.resolveUtilsScriptPromise();
1067            },
1068            /********************
1069   *  PUBLIC METHODS
1070   ********************/
1071            // remove plugin
1072            destroy: function() {
1073                var form = this.telInput.form;
1074                if (this.options.allowDropdown) {
1075                    // make sure the dropdown is closed (and unbind listeners)
1076                    this._closeDropdown();
1077                    this.selectedFlag.removeEventListener("click", this._handleClickSelectedFlag);
1078                    this.flagsContainer.removeEventListener("keydown", this._handleFlagsContainerKeydown);
1079                    // label click hack
1080                    var label = this._getClosestLabel();
1081                    if (label) label.removeEventListener("click", this._handleLabelClick);
1082                }
1083                // unbind hiddenInput listeners
1084                if (this.hiddenInput && form) form.removeEventListener("submit", this._handleHiddenInputSubmit);
1085                // unbind autoHideDialCode listeners
1086                if (this.options.autoHideDialCode) {
1087                    this.telInput.removeEventListener("mousedown", this._handleMousedownFocusEvent);
1088                    this.telInput.removeEventListener("focus", this._handleFocusEvent);
1089                    if (form) form.removeEventListener("submit", this._handleSubmitOrBlurEvent);
1090                    this.telInput.removeEventListener("blur", this._handleSubmitOrBlurEvent);
1091                }
1092                // unbind all events: key events, and focus/blur events if autoHideDialCode=true
1093                this.telInput.removeEventListener("keyup", this._handleKeyupEvent);
1094                this.telInput.removeEventListener("cut", this._handleClipboardEvent);
1095                this.telInput.removeEventListener("paste", this._handleClipboardEvent);
1096                // remove markup (but leave the original input)
1097                var wrapper = this.telInput.parentNode;
1098                wrapper.parentNode.insertBefore(this.telInput, wrapper);
1099                wrapper.parentNode.removeChild(wrapper);
1100                delete window.intlTelInputGlobals.instances[this.id];
1101            },
1102            // get the extension from the current number
1103            getExtension: function() {
1104                if (window.intlTelInputUtils) {
1105                    return intlTelInputUtils.getExtension(this._getFullNumber(), this.selectedCountryData.iso2);
1106                }
1107                return "";
1108            },
1109            // format the number to the given format
1110            getNumber: function(format) {
1111                if (window.intlTelInputUtils) {
1112                    return intlTelInputUtils.formatNumber(this._getFullNumber(), this.selectedCountryData.iso2, format);
1113                }
1114                return "";
1115            },
1116            // get the type of the entered number e.g. landline/mobile
1117            getNumberType: function() {
1118                if (window.intlTelInputUtils) {
1119                    return intlTelInputUtils.getNumberType(this._getFullNumber(), this.selectedCountryData.iso2);
1120                }
1121                return -99;
1122            },
1123            // get the country data for the currently selected flag
1124            getSelectedCountryData: function() {
1125                return this.selectedCountryData;
1126            },
1127            // get the validation error
1128            getValidationError: function() {
1129                if (window.intlTelInputUtils) {
1130                    return intlTelInputUtils.getValidationError(this._getFullNumber(), this.selectedCountryData.iso2);
1131                }
1132                return -99;
1133            },
1134            // validate the input val - assumes the global function isValidNumber (from utilsScript)
1135            isValidNumber: function() {
1136                var val = this._getFullNumber().trim(), countryCode = this.options.nationalMode ? this.selectedCountryData.iso2 : "";
1137                return window.intlTelInputUtils ? intlTelInputUtils.isValidNumber(val, countryCode) : null;
1138            },
1139            // update the selected flag, and update the input val accordingly
1140            setCountry: function(countryCode) {
1141                countryCode = countryCode.toLowerCase();
1142                // check if already selected
1143                if (!this.selectedFlagInner.classList.contains(countryCode)) {
1144                    this._setFlag(countryCode);
1145                    this._updateDialCode(this.selectedCountryData.dialCode, false);
1146                    this._triggerCountryChange();
1147                }
1148            },
1149            // set the input value and update the flag
1150            setNumber: function(number) {
1151                // we must update the flag first, which updates this.selectedCountryData, which is used for formatting the number before displaying it
1152                var flagChanged = this._updateFlagFromNumber(number);
1153                this._updateValFromNumber(number);
1154                if (flagChanged) {
1155                    this._triggerCountryChange();
1156                }
1157            },
1158            // set the placeholder number typ
1159            setPlaceholderNumberType: function(type) {
1160                this.options.placeholderNumberType = type;
1161                this._updatePlaceholder();
1162            }
1163        };
1164        /********************
1165 *  STATIC METHODS
1166 ********************/
1167        // get the country data object
1168        window.intlTelInputGlobals.getCountryData = function() {
1169            return allCountries;
1170        };
1171        // inject a <script> element to load utils.js
1172        var injectScript = function(path, handleSuccess, handleFailure) {
1173            // inject a new script element into the page
1174            var script = document.createElement("script");
1175            script.onload = function() {
1176                forEachInstance("handleUtils");
1177                if (handleSuccess) handleSuccess();
1178            };
1179            script.onerror = function() {
1180                forEachInstance("rejectUtilsScriptPromise");
1181                if (handleFailure) handleFailure();
1182            };
1183            script.className = "iti-load-utils";
1184            script.async = true;
1185            script.src = path;
1186            document.body.appendChild(script);
1187        };
1188        // load the utils script
1189        window.intlTelInputGlobals.loadUtils = function(path) {
1190            // 2 options:
1191            // 1) not already started loading (start)
1192            // 2) already started loading (do nothing - just wait for the onload callback to fire, which will trigger handleUtils on all instances, invoking each of their resolveUtilsScriptPromise functions)
1193            if (!window.intlTelInputUtils && !window.intlTelInputGlobals.startedLoadingUtilsScript) {
1194                // only do this once
1195                window.intlTelInputGlobals.startedLoadingUtilsScript = true;
1196                // if we have promises, then return a promise
1197                if (typeof Promise !== "undefined") {
1198                    return new Promise(function(resolve, reject) {
1199                        injectScript(path, resolve, reject);
1200                    });
1201                } else injectScript(path);
1202            }
1203            return null;
1204        };
1205        // default options
1206        window.intlTelInputGlobals.defaults = defaults;
1207        // version
1208        window.intlTelInputGlobals.version = "14.0.0";
1209        // convenience wrapper
1210        return function(input, options) {
1211            var iti = new Iti(input, options);
1212            iti._init();
1213            window.intlTelInputGlobals.instances[iti.id] = iti;
1214            return iti;
1215        };
1216    }();
1217});

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.