ros.grant.common 2.0.1584 → 2.0.1585

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1574 +1,1147 @@
1
1
  /*
2
- * International Telephone Input v18.1.8
2
+ * International Telephone Input v12.3.0
3
3
  * https://github.com/jackocnr/intl-tel-input.git
4
4
  * Licensed under the MIT license
5
5
  */
6
6
 
7
- // wrap in UMD
8
- (function(factory) {
9
- if (typeof module === "object" && module.exports) {
10
- module.exports = factory(require("jquery"));
11
- } else if (typeof define === "function" && define.amd) {
12
- define([ "jquery" ], function($) {
13
- factory($);
7
+ // wrap in UMD - see https://github.com/umdjs/umd/blob/master/jqueryPluginCommonjs.js
8
+ (function (factory) {
9
+ if (typeof define === "function" && define.amd) {
10
+ define(["jquery"], function ($) {
11
+ factory($, window, document);
14
12
  });
15
- } else factory(jQuery);
16
- })(function($, undefined) {
17
- "use strict";
18
- // Array of country objects for the flag dropdown.
19
- // Here is the criteria for the plugin to support a given country/territory
20
- // - It has an iso2 code: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
21
- // - 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
22
- // - It has a flag in the region-flags project: https://github.com/behdad/region-flags/tree/gh-pages/png
23
- // - It is supported by libphonenumber (it must be listed on this page): https://github.com/googlei18n/libphonenumber/blob/master/resources/ShortNumberMetadata.xml
24
- // Each country array has the following information:
25
- // [
26
- // Country name,
27
- // iso2 code,
28
- // International dial code,
29
- // Order (if >1 country with same dial code),
30
- // Area codes
31
- // ]
32
- var allCountries = [ [ "Afghanistan (‫افغانستان‬‎)", "af", "93" ], [ "Albania (Shqipëri)", "al", "355" ], [ "Algeria (‫الجزائر‬‎)", "dz", "213" ], [ "American Samoa", "as", "1", 5, [ "684" ] ], [ "Andorra", "ad", "376" ], [ "Angola", "ao", "244" ], [ "Anguilla", "ai", "1", 6, [ "264" ] ], [ "Antigua and Barbuda", "ag", "1", 7, [ "268" ] ], [ "Argentina", "ar", "54" ], [ "Armenia (Հայաստան)", "am", "374" ], [ "Aruba", "aw", "297" ], [ "Ascension Island", "ac", "247" ], [ "Australia", "au", "61", 0 ], [ "Austria (Österreich)", "at", "43" ], [ "Azerbaijan (Azərbaycan)", "az", "994" ], [ "Bahamas", "bs", "1", 8, [ "242" ] ], [ "Bahrain (‫البحرين‬‎)", "bh", "973" ], [ "Bangladesh (বাংলাদেশ)", "bd", "880" ], [ "Barbados", "bb", "1", 9, [ "246" ] ], [ "Belarus (Беларусь)", "by", "375" ], [ "Belgium (België)", "be", "32" ], [ "Belize", "bz", "501" ], [ "Benin (Bénin)", "bj", "229" ], [ "Bermuda", "bm", "1", 10, [ "441" ] ], [ "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", "1", 11, [ "284" ] ], [ "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", "263", "289", "306", "343", "354", "365", "367", "368", "382", "387", "403", "416", "418", "428", "431", "437", "438", "450", "584", "468", "474", "506", "514", "519", "548", "579", "581", "584", "587", "604", "613", "639", "647", "672", "683", "705", "709", "742", "753", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905" ] ], [ "Cape Verde (Kabu Verdi)", "cv", "238" ], [ "Caribbean Netherlands", "bq", "599", 1, [ "3", "4", "7" ] ], [ "Cayman Islands", "ky", "1", 12, [ "345" ] ], [ "Central African Republic (République centrafricaine)", "cf", "236" ], [ "Chad (Tchad)", "td", "235" ], [ "Chile", "cl", "56" ], [ "China (中国)", "cn", "86" ], [ "Christmas Island", "cx", "61", 2, [ "89164" ] ], [ "Cocos (Keeling) Islands", "cc", "61", 1, [ "89162" ] ], [ "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", "1", 13, [ "767" ] ], [ "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" ], [ "Eswatini", "sz", "268" ], [ "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", "1", 14, [ "473" ] ], [ "Guadeloupe", "gp", "590", 0 ], [ "Guam", "gu", "1", 15, [ "671" ] ], [ "Guatemala", "gt", "502" ], [ "Guernsey", "gg", "44", 1, [ "1481", "7781", "7839", "7911" ] ], [ "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, [ "1624", "74576", "7524", "7924", "7624" ] ], [ "Israel (‫ישראל‬‎)", "il", "972" ], [ "Italy (Italia)", "it", "39", 0 ], [ "Jamaica", "jm", "1", 4, [ "876", "658" ] ], [ "Japan (日本)", "jp", "81" ], [ "Jersey", "je", "44", 3, [ "1534", "7509", "7700", "7797", "7829", "7937" ] ], [ "Jordan (‫الأردن‬‎)", "jo", "962" ], [ "Kazakhstan (Казахстан)", "kz", "7", 1, [ "33", "7" ] ], [ "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" ], [ "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, [ "269", "639" ] ], [ "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", "1", 16, [ "664" ] ], [ "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" ], [ "North Macedonia (Северна Македонија)", "mk", "389" ], [ "Northern Mariana Islands", "mp", "1", 17, [ "670" ] ], [ "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" ], [ "Russia (Россия)", "ru", "7", 0 ], [ "Rwanda", "rw", "250" ], [ "Saint Barthélemy", "bl", "590", 1 ], [ "Saint Helena", "sh", "290" ], [ "Saint Kitts and Nevis", "kn", "1", 18, [ "869" ] ], [ "Saint Lucia", "lc", "1", 19, [ "758" ] ], [ "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", "1", 20, [ "784" ] ], [ "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", "1", 21, [ "721" ] ], [ "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, [ "79" ] ], [ "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", "1", 22, [ "868" ] ], [ "Tunisia (‫تونس‬‎)", "tn", "216" ], [ "Turkey (Türkiye)", "tr", "90" ], [ "Turkmenistan", "tm", "993" ], [ "Turks and Caicos Islands", "tc", "1", 23, [ "649" ] ], [ "Tuvalu", "tv", "688" ], [ "U.S. Virgin Islands", "vi", "1", 24, [ "340" ] ], [ "Uganda", "ug", "256" ], [ "Ukraine (Україна)", "ua", "380" ], [ "United Arab Emirates (‫الإمارات العربية المتحدة‬‎)", "ae", "971" ], [ "United Kingdom", "gb", "44", 0 ], [ "United States", "us", "1", 0 ], [ "Uruguay", "uy", "598" ], [ "Uzbekistan (Oʻzbekiston)", "uz", "998" ], [ "Vanuatu", "vu", "678" ], [ "Vatican City (Città del Vaticano)", "va", "39", 1, [ "06698" ] ], [ "Venezuela", "ve", "58" ], [ "Vietnam (Việt Nam)", "vn", "84" ], [ "Wallis and Futuna (Wallis-et-Futuna)", "wf", "681" ], [ "Western Sahara (‫الصحراء الغربية‬‎)", "eh", "212", 1, [ "5288", "5289" ] ], [ "Yemen (‫اليمن‬‎)", "ye", "967" ], [ "Zambia", "zm", "260" ], [ "Zimbabwe", "zw", "263" ], [ "Åland Islands", "ax", "358", 1, [ "18" ] ] ];
33
- // loop over all of the countries above, restructuring the data to be objects with named keys
34
- for (var i = 0; i < allCountries.length; i++) {
35
- var c = allCountries[i];
36
- allCountries[i] = {
37
- name: c[0],
38
- iso2: c[1],
39
- dialCode: c[2],
40
- priority: c[3] || 0,
41
- areaCodes: c[4] || null
42
- };
13
+ } else if (typeof module === "object" && module.exports) {
14
+ module.exports = factory(require("jquery"), window, document);
15
+ } else {
16
+ factory(jQuery, window, document);
43
17
  }
18
+ })(function ($, window, document, undefined) {
44
19
  "use strict";
45
- function _objectSpread(target) {
46
- for (var i = 1; i < arguments.length; i++) {
47
- var source = arguments[i] != null ? Object(arguments[i]) : {};
48
- var ownKeys = Object.keys(source);
49
- if (typeof Object.getOwnPropertySymbols === "function") {
50
- ownKeys.push.apply(ownKeys, Object.getOwnPropertySymbols(source).filter(function(sym) {
51
- return Object.getOwnPropertyDescriptor(source, sym).enumerable;
52
- }));
53
- }
54
- ownKeys.forEach(function(key) {
55
- _defineProperty(target, key, source[key]);
56
- });
57
- }
58
- return target;
59
- }
60
- function _defineProperty(obj, key, value) {
61
- key = _toPropertyKey(key);
62
- if (key in obj) {
63
- Object.defineProperty(obj, key, {
64
- value: value,
65
- enumerable: true,
66
- configurable: true,
67
- writable: true
68
- });
69
- } else {
70
- obj[key] = value;
71
- }
72
- return obj;
73
- }
74
- function _classCallCheck(instance, Constructor) {
75
- if (!(instance instanceof Constructor)) {
76
- throw new TypeError("Cannot call a class as a function");
77
- }
78
- }
79
- function _defineProperties(target, props) {
80
- for (var i = 0; i < props.length; i++) {
81
- var descriptor = props[i];
82
- descriptor.enumerable = descriptor.enumerable || false;
83
- descriptor.configurable = true;
84
- if ("value" in descriptor) descriptor.writable = true;
85
- Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
86
- }
87
- }
88
- function _createClass(Constructor, protoProps, staticProps) {
89
- if (protoProps) _defineProperties(Constructor.prototype, protoProps);
90
- if (staticProps) _defineProperties(Constructor, staticProps);
91
- Object.defineProperty(Constructor, "prototype", {
92
- writable: false
93
- });
94
- return Constructor;
95
- }
96
- function _toPropertyKey(arg) {
97
- var key = _toPrimitive(arg, "string");
98
- return typeof key === "symbol" ? key : String(key);
99
- }
100
- function _toPrimitive(input, hint) {
101
- if (typeof input !== "object" || input === null) return input;
102
- var prim = input[Symbol.toPrimitive];
103
- if (prim !== undefined) {
104
- var res = prim.call(input, hint || "default");
105
- if (typeof res !== "object") return res;
106
- throw new TypeError("@@toPrimitive must return a primitive value.");
107
- }
108
- return (hint === "string" ? String : Number)(input);
20
+ // these vars persist through all instances of the plugin
21
+ var pluginName = "intlTelInput", id = 1, // give each instance it's own id for namespaced event handling
22
+ defaults = {
23
+ // whether or not to allow the dropdown
24
+ allowDropdown: true,
25
+ // if there is just a dial code in the input: remove it on blur, and re-add it on focus
26
+ autoHideDialCode: true,
27
+ // add a placeholder in the input with an example number for the selected country
28
+ autoPlaceholder: "polite",
29
+ // modify the auto placeholder
30
+ customPlaceholder: null,
31
+ // append menu to a specific element
32
+ dropdownContainer: "",
33
+ // don't display these countries
34
+ excludeCountries: [],
35
+ // format the input value during initialisation and on setNumber
36
+ formatOnDisplay: true,
37
+ // geoIp lookup function
38
+ geoIpLookup: null,
39
+ // inject a hidden input with this name, and on submit, populate it with the result of getNumber
40
+ hiddenInput: "",
41
+ // initial country
42
+ initialCountry: "",
43
+ // don't insert international dial codes
44
+ nationalMode: true,
45
+ // display only these countries
46
+ onlyCountries: [],
47
+ // number type to use for placeholders
48
+ placeholderNumberType: "MOBILE",
49
+ // the countries at the top of the list. defaults to united states and united kingdom
50
+ preferredCountries: ["us", "gb"],
51
+ // display the country dial code next to the selected flag so it's not part of the typed number
52
+ separateDialCode: false,
53
+ // specify the path to the libphonenumber script to enable validation/formatting
54
+ utilsScript: ""
55
+ }, keys = {
56
+ UP: 38,
57
+ DOWN: 40,
58
+ ENTER: 13,
59
+ ESC: 27,
60
+ PLUS: 43,
61
+ A: 65,
62
+ Z: 90,
63
+ SPACE: 32,
64
+ TAB: 9
65
+ }, // https://en.wikipedia.org/wiki/List_of_North_American_Numbering_Plan_area_codes#Non-geographic_area_codes
66
+ regionlessNanpNumbers = ["800", "822", "833", "844", "855", "866", "877", "880", "881", "882", "883", "884", "885", "886", "887", "888", "889"];
67
+ // keep track of if the window.load event has fired as impossible to check after the fact
68
+ $(window).on("load", function () {
69
+ // UPDATE: use a public static field so we can fudge it in the tests
70
+ $.fn[pluginName].windowLoaded = true;
71
+ });
72
+ function Plugin(element, options) {
73
+ this.telInput = $(element);
74
+ this.options = $.extend({}, defaults, options);
75
+ // event namespace
76
+ this.ns = "." + pluginName + id++;
77
+ // Chrome, FF, Safari, IE9+
78
+ this.isGoodBrowser = Boolean(element.setSelectionRange);
79
+ this.hadInitialPlaceholder = Boolean($(element).attr("placeholder"));
109
80
  }
110
- var intlTelInputGlobals = {
111
- getInstance: function getInstance(input) {
112
- var id = input.getAttribute("data-intl-tel-input-id");
113
- return window.intlTelInputGlobals.instances[id];
81
+ Plugin.prototype = {
82
+ _init: function () {
83
+ // if in nationalMode, disable options relating to dial codes
84
+ if (this.options.nationalMode) {
85
+ this.options.autoHideDialCode = false;
86
+ }
87
+ // 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)
88
+ if (this.options.separateDialCode) {
89
+ this.options.autoHideDialCode = this.options.nationalMode = false;
90
+ }
91
+ // we cannot just test screen size as some smartphones/website meta tags will report desktop resolutions
92
+ // Note: for some reason jasmine breaks if you put this in the main Plugin function with the rest of these declarations
93
+ // Note: to target Android Mobiles (and not Tablets), we must find "Android" and "Mobile"
94
+ this.isMobile = /Android.+Mobile|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
95
+ if (this.isMobile) {
96
+ // trigger the mobile dropdown css
97
+ $("body").addClass("iti-mobile");
98
+ // on mobile, we want a full screen dropdown, so we must append it to the body
99
+ if (!this.options.dropdownContainer) {
100
+ this.options.dropdownContainer = "body";
101
+ }
102
+ }
103
+ // we return these deferred objects from the _init() call so they can be watched, and then we resolve them when each specific request returns
104
+ // Note: again, jasmine breaks when I put these in the Plugin function
105
+ this.autoCountryDeferred = new $.Deferred();
106
+ this.utilsScriptDeferred = new $.Deferred();
107
+ // in various situations there could be no country selected initially, but we need to be able to assume this variable exists
108
+ this.selectedCountryData = {};
109
+ // process all the data: onlyCountries, excludeCountries, preferredCountries etc
110
+ this._processCountryData();
111
+ // generate the markup
112
+ this._generateMarkup();
113
+ // set the initial state of the input value and the selected flag
114
+ this._setInitialState();
115
+ // start all of the event listeners: autoHideDialCode, input keydown, selectedFlag click
116
+ this._initListeners();
117
+ // utils script, and auto country
118
+ this._initRequests();
119
+ // return the deferreds
120
+ return [this.autoCountryDeferred, this.utilsScriptDeferred];
114
121
  },
115
- instances: {},
116
- // using a global like this allows us to mock it in the tests
117
- documentReady: function documentReady() {
118
- return document.readyState === "complete";
119
- }
120
- };
121
- if (typeof window === "object") {
122
- window.intlTelInputGlobals = intlTelInputGlobals;
123
- }
124
- // these vars persist through all instances of the plugin
125
- var id = 0;
126
- var defaults = {
127
- // whether or not to allow the dropdown
128
- allowDropdown: true,
129
- // auto insert dial code (A) on init, (B) on user selecting a country, (C) on calling setCountry
130
- // also listen for blur/submit and auto remove dial code if that's all there is
131
- autoInsertDialCode: false,
132
- // add a placeholder in the input with an example number for the selected country
133
- autoPlaceholder: "polite",
134
- // modify the parentClass
135
- customContainer: "",
136
- // modify the auto placeholder
137
- customPlaceholder: null,
138
- // append menu to specified element
139
- dropdownContainer: null,
140
- // don't display these countries
141
- excludeCountries: [],
142
- // format the input value during initialisation and on setNumber
143
- formatOnDisplay: true,
144
- // geoIp lookup function
145
- geoIpLookup: null,
146
- // inject a hidden input with this name, and on submit, populate it with the result of getNumber
147
- hiddenInput: "",
148
- // initial country
149
- initialCountry: "",
150
- // localized country names e.g. { 'de': 'Deutschland' }
151
- localizedCountries: null,
152
- // national vs international formatting for numbers e.g. placeholders and displaying existing numbers
153
- nationalMode: true,
154
- // display only these countries
155
- onlyCountries: [],
156
- // number type to use for placeholders
157
- placeholderNumberType: "MOBILE",
158
- // the countries at the top of the list. defaults to united states and united kingdom
159
- preferredCountries: [ "us", "gb" ],
160
- // display the country dial code next to the selected flag
161
- separateDialCode: false,
162
- // option to hide the flags - must be used with separateDialCode, or allowDropdown=false
163
- showFlags: true,
164
- // specify the path to the libphonenumber script to enable validation/formatting
165
- utilsScript: ""
166
- };
167
- // https://en.wikipedia.org/wiki/List_of_North_American_Numbering_Plan_area_codes#Non-geographic_area_codes
168
- var regionlessNanpNumbers = [ "800", "822", "833", "844", "855", "866", "877", "880", "881", "882", "883", "884", "885", "886", "887", "888", "889" ];
169
- // utility function to iterate over an object. can't use Object.entries or native forEach because
170
- // of IE11
171
- var forEachProp = function forEachProp(obj, callback) {
172
- var keys = Object.keys(obj);
173
- for (var i = 0; i < keys.length; i++) {
174
- callback(keys[i], obj[keys[i]]);
175
- }
176
- };
177
- // run a method on each instance of the plugin
178
- var forEachInstance = function forEachInstance(method) {
179
- forEachProp(window.intlTelInputGlobals.instances, function(key) {
180
- window.intlTelInputGlobals.instances[key][method]();
181
- });
182
- };
183
- // this is our plugin class that we will create an instance of
184
- // eslint-disable-next-line no-unused-vars
185
- var Iti = /*#__PURE__*/ function() {
186
- function Iti(input, options) {
187
- var _this = this;
188
- _classCallCheck(this, Iti);
189
- this.id = id++;
190
- this.telInput = input;
191
- this.activeItem = null;
192
- this.highlightedItem = null;
193
- // process specified options / defaults
194
- // alternative to Object.assign, which isn't supported by IE11
195
- var customOptions = options || {};
196
- this.options = {};
197
- forEachProp(defaults, function(key, value) {
198
- _this.options[key] = customOptions.hasOwnProperty(key) ? customOptions[key] : value;
199
- });
200
- this.hadInitialPlaceholder = Boolean(input.getAttribute("placeholder"));
201
- }
202
- _createClass(Iti, [ {
203
- key: "_init",
204
- value: function _init() {
205
- var _this2 = this;
206
- // if in nationalMode, do not insert dial codes
207
- if (this.options.nationalMode) {
208
- this.options.autoInsertDialCode = false;
209
- }
210
- // if separateDialCode enabled, do not insert dial codes
211
- if (this.options.separateDialCode) {
212
- this.options.autoInsertDialCode = false;
213
- }
214
- // force showFlags=true if there's a dropdown and we're not displaying the dial code,
215
- // as otherwise you just have a down arrow on it's own which doesn't make sense
216
- var forceShowFlags = this.options.allowDropdown && !this.options.separateDialCode;
217
- if (!this.options.showFlags && forceShowFlags) {
218
- this.options.showFlags = true;
219
- }
220
- // we cannot just test screen size as some smartphones/website meta tags will report desktop
221
- // resolutions
222
- // Note: for some reason jasmine breaks if you put this in the main Plugin function with the
223
- // rest of these declarations
224
- // Note: to target Android Mobiles (and not Tablets), we must find 'Android' and 'Mobile'
225
- this.isMobile = /Android.+Mobile|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
226
- if (this.isMobile) {
227
- // trigger the mobile dropdown css
228
- document.body.classList.add("iti-mobile");
229
- // on mobile, we want a full screen dropdown, so we must append it to the body
230
- if (!this.options.dropdownContainer) {
231
- this.options.dropdownContainer = document.body;
232
- }
233
- }
234
- // check if input has one parent with RTL
235
- this.isRTL = !!this.telInput.closest("[dir=rtl]");
236
- // these promises get resolved when their individual requests complete
237
- // this way the dev can do something like iti.promise.then(...) to know when all requests are
238
- // complete
239
- if (typeof Promise !== "undefined") {
240
- var autoCountryPromise = new Promise(function(resolve, reject) {
241
- _this2.resolveAutoCountryPromise = resolve;
242
- _this2.rejectAutoCountryPromise = reject;
243
- });
244
- var utilsScriptPromise = new Promise(function(resolve, reject) {
245
- _this2.resolveUtilsScriptPromise = resolve;
246
- _this2.rejectUtilsScriptPromise = reject;
247
- });
248
- this.promise = Promise.all([ autoCountryPromise, utilsScriptPromise ]);
249
- } else {
250
- // prevent errors when Promise doesn't exist
251
- this.resolveAutoCountryPromise = this.rejectAutoCountryPromise = function() {};
252
- this.resolveUtilsScriptPromise = this.rejectUtilsScriptPromise = function() {};
253
- }
254
- // in various situations there could be no country selected initially, but we need to be able
255
- // to assume this variable exists
256
- this.selectedCountryData = {};
257
- // process all the data: onlyCountries, excludeCountries, preferredCountries etc
258
- this._processCountryData();
259
- // generate the markup
260
- this._generateMarkup();
261
- // set the initial state of the input value and the selected flag
262
- this._setInitialState();
263
- // start all of the event listeners: autoInsertDialCode, input keydown, selectedFlag click
264
- this._initListeners();
265
- // utils script, and auto country
266
- this._initRequests();
267
- }
268
- }, {
269
- key: "_processCountryData",
270
- value: function _processCountryData() {
271
- // process onlyCountries or excludeCountries array if present
272
- this._processAllCountries();
273
- // process the countryCodes map
274
- this._processCountryCodes();
275
- // process the preferredCountries
276
- this._processPreferredCountries();
277
- // translate countries according to localizedCountries option
278
- if (this.options.localizedCountries) {
279
- this._translateCountriesByLocale();
280
- }
281
- // sort countries by name
282
- if (this.options.onlyCountries.length || this.options.localizedCountries) {
283
- this.countries.sort(this._countryNameSort);
284
- }
285
- }
286
- }, {
287
- key: "_addCountryCode",
288
- value: function _addCountryCode(iso2, countryCode, priority) {
289
- if (countryCode.length > this.countryCodeMaxLen) {
290
- this.countryCodeMaxLen = countryCode.length;
291
- }
292
- if (!this.countryCodes.hasOwnProperty(countryCode)) {
293
- this.countryCodes[countryCode] = [];
294
- }
295
- // bail if we already have this country for this countryCode
296
- for (var i = 0; i < this.countryCodes[countryCode].length; i++) {
297
- if (this.countryCodes[countryCode][i] === iso2) {
298
- return;
299
- }
300
- }
301
- // check for undefined as 0 is falsy
302
- var index = priority !== undefined ? priority : this.countryCodes[countryCode].length;
303
- this.countryCodes[countryCode][index] = iso2;
122
+ /********************
123
+ * PRIVATE METHODS
124
+ ********************/
125
+ // prepare all of the country data, including onlyCountries, excludeCountries and preferredCountries options
126
+ _processCountryData: function () {
127
+ // process onlyCountries or excludeCountries array if present
128
+ this._processAllCountries();
129
+ // process the countryCodes map
130
+ this._processCountryCodes();
131
+ // process the preferredCountries
132
+ this._processPreferredCountries();
133
+ },
134
+ // add a country code to this.countryCodes
135
+ _addCountryCode: function (iso2, dialCode, priority) {
136
+ if (!(dialCode in this.countryCodes)) {
137
+ this.countryCodes[dialCode] = [];
304
138
  }
305
- }, {
306
- key: "_processAllCountries",
307
- value: function _processAllCountries() {
308
- if (this.options.onlyCountries.length) {
309
- var lowerCaseOnlyCountries = this.options.onlyCountries.map(function(country) {
310
- return country.toLowerCase();
311
- });
312
- this.countries = allCountries.filter(function(country) {
313
- return lowerCaseOnlyCountries.indexOf(country.iso2) > -1;
314
- });
315
- } else if (this.options.excludeCountries.length) {
316
- var lowerCaseExcludeCountries = this.options.excludeCountries.map(function(country) {
317
- return country.toLowerCase();
318
- });
319
- this.countries = allCountries.filter(function(country) {
320
- return lowerCaseExcludeCountries.indexOf(country.iso2) === -1;
321
- });
322
- } else {
323
- this.countries = allCountries;
324
- }
139
+ var index = priority || 0;
140
+ this.countryCodes[dialCode][index] = iso2;
141
+ },
142
+ // process onlyCountries or excludeCountries array if present
143
+ _processAllCountries: function () {
144
+ if (this.options.onlyCountries.length) {
145
+ var lowerCaseOnlyCountries = this.options.onlyCountries.map(function (country) {
146
+ return country.toLowerCase();
147
+ });
148
+ this.countries = allCountries.filter(function (country) {
149
+ return lowerCaseOnlyCountries.indexOf(country.iso2) > -1;
150
+ });
151
+ this.countries.sort(this._countryNameSort);
152
+ } else if (this.options.excludeCountries.length) {
153
+ var lowerCaseExcludeCountries = this.options.excludeCountries.map(function (country) {
154
+ return country.toLowerCase();
155
+ });
156
+ this.countries = allCountries.filter(function (country) {
157
+ return lowerCaseExcludeCountries.indexOf(country.iso2) === -1;
158
+ });
159
+ } else {
160
+ this.countries = allCountries;
325
161
  }
326
- }, {
327
- key: "_translateCountriesByLocale",
328
- value: function _translateCountriesByLocale() {
329
- for (var i = 0; i < this.countries.length; i++) {
330
- var iso = this.countries[i].iso2.toLowerCase();
331
- if (this.options.localizedCountries.hasOwnProperty(iso)) {
332
- this.countries[i].name = this.options.localizedCountries[iso];
162
+ },
163
+ // sort by country name
164
+ _countryNameSort: function (a, b) {
165
+ return a.name.localeCompare(b.name);
166
+ },
167
+ // process the countryCodes map
168
+ _processCountryCodes: function () {
169
+ this.countryCodes = {};
170
+ for (var i = 0; i < this.countries.length; i++) {
171
+ var c = this.countries[i];
172
+ this._addCountryCode(c.iso2, c.dialCode, c.priority);
173
+ // area codes
174
+ if (c.areaCodes) {
175
+ for (var j = 0; j < c.areaCodes.length; j++) {
176
+ // full dial code is country code + dial code
177
+ this._addCountryCode(c.iso2, c.dialCode + c.areaCodes[j]);
333
178
  }
334
179
  }
335
180
  }
336
- }, {
337
- key: "_countryNameSort",
338
- value: function _countryNameSort(a, b) {
339
- if (a.name < b.name) {
340
- return -1;
341
- }
342
- if (a.name > b.name) {
343
- return 1;
344
- }
345
- return 0;
346
- }
347
- }, {
348
- key: "_processCountryCodes",
349
- value: function _processCountryCodes() {
350
- this.countryCodeMaxLen = 0;
351
- // here we store just dial codes
352
- this.dialCodes = {};
353
- // here we store "country codes" (both dial codes and their area codes)
354
- this.countryCodes = {};
355
- // first: add dial codes
356
- for (var i = 0; i < this.countries.length; i++) {
357
- var c = this.countries[i];
358
- if (!this.dialCodes[c.dialCode]) {
359
- this.dialCodes[c.dialCode] = true;
360
- }
361
- this._addCountryCode(c.iso2, c.dialCode, c.priority);
362
- }
363
- // next: add area codes
364
- // this is a second loop over countries, to make sure we have all of the "root" countries
365
- // already in the map, so that we can access them, as each time we add an area code substring
366
- // to the map, we also need to include the "root" country's code, as that also matches
367
- for (var _i = 0; _i < this.countries.length; _i++) {
368
- var _c = this.countries[_i];
369
- // area codes
370
- if (_c.areaCodes) {
371
- var rootCountryCode = this.countryCodes[_c.dialCode][0];
372
- // for each area code
373
- for (var j = 0; j < _c.areaCodes.length; j++) {
374
- var areaCode = _c.areaCodes[j];
375
- // for each digit in the area code to add all partial matches as well
376
- for (var k = 1; k < areaCode.length; k++) {
377
- var partialDialCode = _c.dialCode + areaCode.substr(0, k);
378
- // start with the root country, as that also matches this dial code
379
- this._addCountryCode(rootCountryCode, partialDialCode);
380
- this._addCountryCode(_c.iso2, partialDialCode);
381
- }
382
- // add the full area code
383
- this._addCountryCode(_c.iso2, _c.dialCode + areaCode);
384
- }
385
- }
181
+ },
182
+ // process preferred countries - iterate through the preferences, fetching the country data for each one
183
+ _processPreferredCountries: function () {
184
+ this.preferredCountries = [];
185
+ for (var i = 0; i < this.options.preferredCountries.length; i++) {
186
+ var countryCode = this.options.preferredCountries[i].toLowerCase(), countryData = this._getCountryData(countryCode, false, true);
187
+ if (countryData) {
188
+ this.preferredCountries.push(countryData);
386
189
  }
387
190
  }
388
- }, {
389
- key: "_processPreferredCountries",
390
- value: function _processPreferredCountries() {
391
- this.preferredCountries = [];
392
- for (var i = 0; i < this.options.preferredCountries.length; i++) {
393
- var countryCode = this.options.preferredCountries[i].toLowerCase();
394
- var countryData = this._getCountryData(countryCode, false, true);
395
- if (countryData) {
396
- this.preferredCountries.push(countryData);
397
- }
191
+ },
192
+ // generate all of the markup for the plugin: the selected flag overlay, and the dropdown
193
+ _generateMarkup: function () {
194
+ // 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)
195
+ this.telInput.attr("autocomplete", "off");
196
+ // containers (mostly for positioning)
197
+ var parentClass = "intl-tel-input";
198
+ if (this.options.allowDropdown) {
199
+ parentClass += " allow-dropdown";
200
+ }
201
+ if (this.options.separateDialCode) {
202
+ parentClass += " separate-dial-code";
203
+ }
204
+ this.telInput.wrap($("<div>", {
205
+ "class": parentClass
206
+ }));
207
+ this.flagsContainer = $("<div>", {
208
+ "class": "flag-container"
209
+ }).insertBefore(this.telInput);
210
+ // currently selected flag (displayed to left of input)
211
+ var selectedFlag = $("<div>", {
212
+ "class": "selected-flag"
213
+ });
214
+ selectedFlag.appendTo(this.flagsContainer);
215
+ this.selectedFlagInner = $("<div>", {
216
+ "class": "iti-flag"
217
+ }).appendTo(selectedFlag);
218
+ if (this.options.separateDialCode) {
219
+ this.selectedDialCode = $("<div>", {
220
+ "class": "selected-dial-code"
221
+ }).appendTo(selectedFlag);
222
+ }
223
+ if (this.options.allowDropdown) {
224
+ // make element focusable and tab naviagable
225
+ selectedFlag.attr("tabindex", "0");
226
+ // CSS triangle
227
+ $("<div>", {
228
+ "class": "iti-arrow"
229
+ }).appendTo(selectedFlag);
230
+ // country dropdown: preferred countries, then divider, then all countries
231
+ this.countryList = $("<ul>", {
232
+ "class": "country-list hide"
233
+ });
234
+ if (this.preferredCountries.length) {
235
+ this._appendListItems(this.preferredCountries, "preferred");
236
+ $("<li>", {
237
+ "class": "divider"
238
+ }).appendTo(this.countryList);
239
+ }
240
+ this._appendListItems(this.countries, "");
241
+ // this is useful in lots of places
242
+ this.countryListItems = this.countryList.children(".country");
243
+ // create dropdownContainer markup
244
+ if (this.options.dropdownContainer) {
245
+ this.dropdown = $("<div>", {
246
+ "class": "intl-tel-input iti-container"
247
+ }).append(this.countryList);
248
+ } else {
249
+ this.countryList.appendTo(this.flagsContainer);
398
250
  }
251
+ } else {
252
+ // a little hack so we don't break anything
253
+ this.countryListItems = $();
399
254
  }
400
- }, {
401
- key: "_createEl",
402
- value: function _createEl(name, attrs, container) {
403
- var el = document.createElement(name);
404
- if (attrs) {
405
- forEachProp(attrs, function(key, value) {
406
- return el.setAttribute(key, value);
407
- });
408
- }
409
- if (container) {
410
- container.appendChild(el);
411
- }
412
- return el;
255
+ if (this.options.hiddenInput) {
256
+ this.hiddenInput = $("<input>", {
257
+ type: "hidden",
258
+ name: this.options.hiddenInput
259
+ }).insertAfter(this.telInput);
413
260
  }
414
- }, {
415
- key: "_generateMarkup",
416
- value: function _generateMarkup() {
417
- // if autocomplete does not exist on the element and its form, then
418
- // prevent autocomplete as there's no safe, cross-browser event we can react to, so it can
419
- // easily put the plugin in an inconsistent state e.g. the wrong flag selected for the
420
- // autocompleted number, which on submit could mean wrong number is saved
421
- if (!this.telInput.hasAttribute("autocomplete") && !(this.telInput.form && this.telInput.form.hasAttribute("autocomplete"))) {
422
- this.telInput.setAttribute("autocomplete", "off");
423
- }
424
- var _this$options = this.options, allowDropdown = _this$options.allowDropdown, separateDialCode = _this$options.separateDialCode, showFlags = _this$options.showFlags, customContainer = _this$options.customContainer, hiddenInput = _this$options.hiddenInput, dropdownContainer = _this$options.dropdownContainer;
425
- // containers (mostly for positioning)
426
- var parentClass = "iti";
427
- if (allowDropdown) {
428
- parentClass += " iti--allow-dropdown";
429
- }
430
- if (separateDialCode) {
431
- parentClass += " iti--separate-dial-code";
432
- }
433
- if (showFlags) {
434
- parentClass += " iti--show-flags";
435
- }
436
- if (customContainer) {
437
- parentClass += " ".concat(customContainer);
438
- }
439
- var wrapper = this._createEl("div", {
440
- "class": parentClass
441
- });
442
- this.telInput.parentNode.insertBefore(wrapper, this.telInput);
443
- // only hide the flagsContainer if allowDropdown, showFlags and separateDialCode are all false
444
- var showFlagsContainer = allowDropdown || showFlags || separateDialCode;
445
- if (showFlagsContainer) {
446
- this.flagsContainer = this._createEl("div", {
447
- "class": "iti__flag-container"
448
- }, wrapper);
449
- }
450
- wrapper.appendChild(this.telInput);
451
- // selected flag (displayed to left of input)
452
- // using Aria tags for "Select-Only Combobox Example"
453
- // https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/
454
- if (showFlagsContainer) {
455
- this.selectedFlag = this._createEl("div", _objectSpread({
456
- "class": "iti__selected-flag"
457
- }, allowDropdown && {
458
- role: "combobox",
459
- "aria-haspopup": "listbox",
460
- "aria-controls": "iti-".concat(this.id, "__country-listbox"),
461
- "aria-expanded": "false",
462
- "aria-label": "Telephone country code"
463
- }), this.flagsContainer);
464
- }
465
- if (showFlags) {
466
- this.selectedFlagInner = this._createEl("div", {
467
- "class": "iti__flag"
468
- }, this.selectedFlag);
469
- }
470
- if (this.selectedFlag && this.telInput.disabled) {
471
- this.selectedFlag.setAttribute("aria-disabled", "true");
472
- }
473
- if (separateDialCode) {
474
- this.selectedDialCode = this._createEl("div", {
475
- "class": "iti__selected-dial-code"
476
- }, this.selectedFlag);
477
- }
478
- if (allowDropdown) {
479
- if (!this.telInput.disabled) {
480
- // make element focusable and tab navigable
481
- this.selectedFlag.setAttribute("tabindex", "0");
482
- }
483
- this.dropdownArrow = this._createEl("div", {
484
- "class": "iti__arrow"
485
- }, this.selectedFlag);
486
- // country dropdown: preferred countries, then divider, then all countries
487
- this.countryList = this._createEl("ul", {
488
- "class": "iti__country-list iti__hide",
489
- id: "iti-".concat(this.id, "__country-listbox"),
490
- role: "listbox",
491
- "aria-label": "List of countries"
492
- });
493
- if (this.preferredCountries.length) {
494
- this._appendListItems(this.preferredCountries, "iti__preferred", true);
495
- this._createEl("li", {
496
- "class": "iti__divider",
497
- role: "separator",
498
- "aria-disabled": "true"
499
- }, this.countryList);
500
- }
501
- this._appendListItems(this.countries, "iti__standard");
502
- // create dropdownContainer markup
503
- if (dropdownContainer) {
504
- this.dropdown = this._createEl("div", {
505
- "class": "iti iti--container"
506
- });
507
- this.dropdown.appendChild(this.countryList);
508
- } else {
509
- this.flagsContainer.appendChild(this.countryList);
261
+ },
262
+ // add a country <li> to the countryList <ul> container
263
+ _appendListItems: function (countries, className) {
264
+ // we create so many DOM elements, it is faster to build a temp string
265
+ // and then add everything to the DOM in one go at the end
266
+ var tmp = "";
267
+ // for each country
268
+ for (var i = 0; i < countries.length; i++) {
269
+ var c = countries[i];
270
+ // open the list item
271
+ tmp += "<li class='country " + className + "' data-dial-code='" + c.dialCode + "' data-country-code='" + c.iso2 + "'>";
272
+ // add the flag
273
+ tmp += "<div class='flag-box'><div class='iti-flag " + c.iso2 + "'></div></div>";
274
+ // and the country name and dial code
275
+ tmp += "<span class='country-name'>" + c.name + "</span>";
276
+ tmp += "<span class='dial-code'>+" + c.dialCode + "</span>";
277
+ // close the list item
278
+ tmp += "</li>";
279
+ }
280
+ this.countryList.append(tmp);
281
+ },
282
+ // set the initial state of the input value and the selected flag by:
283
+ // 1. extracting a dial code from the given number
284
+ // 2. using explicit initialCountry
285
+ // 3. picking the first preferred country
286
+ // 4. picking the first country
287
+ _setInitialState: function () {
288
+ var val = this.telInput.val();
289
+ // if we already have a dial code, and it's not a regionlessNanp, we can go ahead and set the flag, else fall back to the default country
290
+ // UPDATE: actually we do want to set the flag for a regionlessNanp in one situation: if we're in nationalMode and there's no initialCountry - otherwise we lose the +1 and we're left with an invalid number
291
+ if (this._getDialCode(val) && (!this._isRegionlessNanp(val) || this.options.nationalMode && !this.options.initialCountry)) {
292
+ this._updateFlagFromNumber(val);
293
+ } else if (this.options.initialCountry !== "auto") {
294
+ // see if we should select a flag
295
+ if (this.options.initialCountry) {
296
+ this._setFlag(this.options.initialCountry.toLowerCase());
297
+ } else {
298
+ // no dial code and no initialCountry, so default to first in list
299
+ this.defaultCountry = this.preferredCountries.length ? this.preferredCountries[0].iso2 : this.countries[0].iso2;
300
+ if (!val) {
301
+ this._setFlag(this.defaultCountry);
510
302
  }
511
303
  }
512
- if (hiddenInput) {
513
- var hiddenInputName = hiddenInput;
514
- var name = this.telInput.getAttribute("name");
515
- if (name) {
516
- var i = name.lastIndexOf("[");
517
- // if input name contains square brackets, then give the hidden input the same name,
518
- // replacing the contents of the last set of brackets with the given hiddenInput name
519
- if (i !== -1) {
520
- hiddenInputName = "".concat(name.substr(0, i), "[").concat(hiddenInputName, "]");
521
- }
522
- }
523
- this.hiddenInput = this._createEl("input", {
524
- type: "hidden",
525
- name: hiddenInputName
526
- });
527
- wrapper.appendChild(this.hiddenInput);
304
+ // if empty and no nationalMode and no autoHideDialCode then insert the default dial code
305
+ if (!val && !this.options.nationalMode && !this.options.autoHideDialCode && !this.options.separateDialCode) {
306
+ this.telInput.val("+" + this.selectedCountryData.dialCode);
528
307
  }
529
308
  }
530
- }, {
531
- key: "_appendListItems",
532
- value: function _appendListItems(countries, className, preferred) {
533
- // we create so many DOM elements, it is faster to build a temp string
534
- // and then add everything to the DOM in one go at the end
535
- var tmp = "";
536
- // for each country
537
- for (var i = 0; i < countries.length; i++) {
538
- var c = countries[i];
539
- var idSuffix = preferred ? "-preferred" : "";
540
- // open the list item
541
- tmp += "<li class='iti__country ".concat(className, "' tabIndex='-1' id='iti-").concat(this.id, "__item-").concat(c.iso2).concat(idSuffix, "' role='option' data-dial-code='").concat(c.dialCode, "' data-country-code='").concat(c.iso2, "' aria-selected='false'>");
542
- // add the flag
543
- if (this.options.showFlags) {
544
- tmp += "<div class='iti__flag-box'><div class='iti__flag iti__".concat(c.iso2, "'></div></div>");
545
- }
546
- // and the country name and dial code
547
- tmp += "<span class='iti__country-name'>".concat(c.name, "</span>");
548
- tmp += "<span class='iti__dial-code'>+".concat(c.dialCode, "</span>");
549
- // close the list item
550
- tmp += "</li>";
551
- }
552
- this.countryList.insertAdjacentHTML("beforeend", tmp);
309
+ // NOTE: if initialCountry is set to auto, that will be handled separately
310
+ // format
311
+ if (val) {
312
+ // this wont be run after _updateDialCode as that's only called if no val
313
+ this._updateValFromNumber(val);
553
314
  }
554
- }, {
555
- key: "_setInitialState",
556
- value: function _setInitialState() {
557
- // fix firefox bug: when first load page (with input with value set to number with intl dial
558
- // code) and initialising plugin removes the dial code from the input, then refresh page,
559
- // and we try to init plugin again but this time on number without dial code so get grey flag
560
- var attributeValue = this.telInput.getAttribute("value");
561
- var inputValue = this.telInput.value;
562
- var useAttribute = attributeValue && attributeValue.charAt(0) === "+" && (!inputValue || inputValue.charAt(0) !== "+");
563
- var val = useAttribute ? attributeValue : inputValue;
564
- var dialCode = this._getDialCode(val);
565
- var isRegionlessNanp = this._isRegionlessNanp(val);
566
- var _this$options2 = this.options, initialCountry = _this$options2.initialCountry, autoInsertDialCode = _this$options2.autoInsertDialCode;
567
- // if we already have a dial code, and it's not a regionlessNanp, we can go ahead and set the
568
- // flag, else fall back to the default country
569
- if (dialCode && !isRegionlessNanp) {
570
- this._updateFlagFromNumber(val);
571
- } else if (initialCountry !== "auto") {
572
- // see if we should select a flag
573
- if (initialCountry) {
574
- this._setFlag(initialCountry.toLowerCase());
575
- } else {
576
- if (dialCode && isRegionlessNanp) {
577
- // has intl dial code, is regionless nanp, and no initialCountry, so default to US
578
- this._setFlag("us");
579
- } else {
580
- // no dial code and no initialCountry, so default to first in list
581
- this.defaultCountry = this.preferredCountries.length ? this.preferredCountries[0].iso2 : this.countries[0].iso2;
582
- if (!val) {
583
- this._setFlag(this.defaultCountry);
584
- }
585
- }
586
- }
587
- // if empty and autoInsertDialCode then insert the dial code
588
- if (!val && autoInsertDialCode) {
589
- this.telInput.value = "+".concat(this.selectedCountryData.dialCode);
590
- }
591
- }
592
- // NOTE: if initialCountry is set to auto, that will be handled separately
593
- // format - note this wont be run after _updateDialCode as that's only called if no val
594
- if (val) {
595
- this._updateValFromNumber(val);
596
- }
315
+ },
316
+ // initialise the main event listeners: input keyup, and click selected flag
317
+ _initListeners: function () {
318
+ this._initKeyListeners();
319
+ if (this.options.autoHideDialCode) {
320
+ this._initFocusListeners();
597
321
  }
598
- }, {
599
- key: "_initListeners",
600
- value: function _initListeners() {
601
- this._initKeyListeners();
602
- if (this.options.autoInsertDialCode) {
603
- this._initBlurListeners();
604
- }
605
- if (this.options.allowDropdown) {
606
- this._initDropdownListeners();
607
- }
608
- if (this.hiddenInput) {
609
- this._initHiddenInputListener();
610
- }
322
+ if (this.options.allowDropdown) {
323
+ this._initDropdownListeners();
611
324
  }
612
- }, {
613
- key: "_initHiddenInputListener",
614
- value: function _initHiddenInputListener() {
615
- var _this3 = this;
616
- this._handleHiddenInputSubmit = function() {
617
- _this3.hiddenInput.value = _this3.getNumber();
618
- };
619
- if (this.telInput.form) {
620
- this.telInput.form.addEventListener("submit", this._handleHiddenInputSubmit);
621
- }
325
+ if (this.hiddenInput) {
326
+ this._initHiddenInputListener();
622
327
  }
623
- }, {
624
- key: "_getClosestLabel",
625
- value: function _getClosestLabel() {
626
- var el = this.telInput;
627
- while (el && el.tagName !== "LABEL") {
628
- el = el.parentNode;
629
- }
630
- return el;
328
+ },
329
+ // update hidden input on form submit
330
+ _initHiddenInputListener: function () {
331
+ var that = this;
332
+ var form = this.telInput.closest("form");
333
+ if (form.length) {
334
+ form.submit(function () {
335
+ that.hiddenInput.val(that.getNumber());
336
+ });
631
337
  }
632
- }, {
633
- key: "_initDropdownListeners",
634
- value: function _initDropdownListeners() {
635
- var _this4 = this;
636
- // hack for input nested inside label (which is valid markup): clicking the selected-flag to
637
- // open the dropdown would then automatically trigger a 2nd click on the input which would
638
- // close it again
639
- this._handleLabelClick = function(e) {
338
+ },
339
+ // initialise the dropdown listeners
340
+ _initDropdownListeners: function () {
341
+ var that = this;
342
+ // hack for input nested inside label: clicking the selected-flag to open the dropdown would then automatically trigger a 2nd click on the input which would close it again
343
+ var label = this.telInput.closest("label");
344
+ if (label.length) {
345
+ label.on("click" + this.ns, function (e) {
640
346
  // if the dropdown is closed, then focus the input, else ignore the click
641
- if (_this4.countryList.classList.contains("iti__hide")) {
642
- _this4.telInput.focus();
347
+ if (that.countryList.hasClass("hide")) {
348
+ that.telInput.focus();
643
349
  } else {
644
350
  e.preventDefault();
645
351
  }
646
- };
647
- var label = this._getClosestLabel();
648
- if (label) {
649
- label.addEventListener("click", this._handleLabelClick);
650
- }
651
- // toggle country dropdown on click
652
- this._handleClickSelectedFlag = function() {
653
- // only intercept this event if we're opening the dropdown
654
- // else let it bubble up to the top ("click-off-to-close" listener)
655
- // we cannot just stopPropagation as it may be needed to close another instance
656
- if (_this4.countryList.classList.contains("iti__hide") && !_this4.telInput.disabled && !_this4.telInput.readOnly) {
657
- _this4._showDropdown();
658
- }
659
- };
660
- this.selectedFlag.addEventListener("click", this._handleClickSelectedFlag);
661
- // open dropdown list if currently focused
662
- this._handleFlagsContainerKeydown = function(e) {
663
- var isDropdownHidden = _this4.countryList.classList.contains("iti__hide");
664
- if (isDropdownHidden && [ "ArrowUp", "Up", "ArrowDown", "Down", " ", "Enter" ].indexOf(e.key) !== -1) {
665
- // prevent form from being submitted if "ENTER" was pressed
666
- e.preventDefault();
667
- // prevent event from being handled again by document
668
- e.stopPropagation();
669
- _this4._showDropdown();
670
- }
671
- // allow navigation from dropdown to input on TAB
672
- if (e.key === "Tab") {
673
- _this4._closeDropdown();
674
- }
675
- };
676
- this.flagsContainer.addEventListener("keydown", this._handleFlagsContainerKeydown);
352
+ });
677
353
  }
678
- }, {
679
- key: "_initRequests",
680
- value: function _initRequests() {
681
- var _this5 = this;
682
- // if the user has specified the path to the utils script, fetch it on window.load, else resolve
683
- if (this.options.utilsScript && !window.intlTelInputUtils) {
684
- // if the plugin is being initialised after the window.load event has already been fired
685
- if (window.intlTelInputGlobals.documentReady()) {
686
- window.intlTelInputGlobals.loadUtils(this.options.utilsScript);
687
- } else {
688
- // wait until the load event so we don't block any other requests e.g. the flags image
689
- window.addEventListener("load", function() {
690
- window.intlTelInputGlobals.loadUtils(_this5.options.utilsScript);
691
- });
692
- }
693
- } else {
694
- this.resolveUtilsScriptPromise();
354
+ // toggle country dropdown on click
355
+ var selectedFlag = this.selectedFlagInner.parent();
356
+ selectedFlag.on("click" + this.ns, function (e) {
357
+ // only intercept this event if we're opening the dropdown
358
+ // else let it bubble up to the top ("click-off-to-close" listener)
359
+ // we cannot just stopPropagation as it may be needed to close another instance
360
+ if (that.countryList.hasClass("hide") && !that.telInput.prop("disabled") && !that.telInput.prop("readonly")) {
361
+ that._showDropdown();
362
+ }
363
+ });
364
+ // open dropdown list if currently focused
365
+ this.flagsContainer.on("keydown" + that.ns, function (e) {
366
+ var isDropdownHidden = that.countryList.hasClass("hide");
367
+ if (isDropdownHidden && (e.which == keys.UP || e.which == keys.DOWN || e.which == keys.SPACE || e.which == keys.ENTER)) {
368
+ // prevent form from being submitted if "ENTER" was pressed
369
+ e.preventDefault();
370
+ // prevent event from being handled again by document
371
+ e.stopPropagation();
372
+ that._showDropdown();
373
+ }
374
+ // allow navigation from dropdown to input on TAB
375
+ if (e.which == keys.TAB) {
376
+ that._closeDropdown();
695
377
  }
696
- if (this.options.initialCountry === "auto") {
697
- this._loadAutoCountry();
378
+ });
379
+ },
380
+ // init many requests: utils script / geo ip lookup
381
+ _initRequests: function () {
382
+ var that = this;
383
+ // if the user has specified the path to the utils script, fetch it on window.load, else resolve
384
+ if (this.options.utilsScript) {
385
+ // if the plugin is being initialised after the window.load event has already been fired
386
+ if ($.fn[pluginName].windowLoaded) {
387
+ $.fn[pluginName].loadUtils(this.options.utilsScript, this.utilsScriptDeferred);
698
388
  } else {
699
- this.resolveAutoCountryPromise();
389
+ // wait until the load event so we don't block any other requests e.g. the flags image
390
+ $(window).on("load", function () {
391
+ $.fn[pluginName].loadUtils(that.options.utilsScript, that.utilsScriptDeferred);
392
+ });
700
393
  }
394
+ } else {
395
+ this.utilsScriptDeferred.resolve();
396
+ }
397
+ if (this.options.initialCountry === "auto") {
398
+ this._loadAutoCountry();
399
+ } else {
400
+ this.autoCountryDeferred.resolve();
701
401
  }
702
- }, {
703
- key: "_loadAutoCountry",
704
- value: function _loadAutoCountry() {
705
- // 3 options:
706
- // 1) already loaded (we're done)
707
- // 2) not already started loading (start)
708
- // 3) already started loading (do nothing - just wait for loading callback to fire)
709
- if (window.intlTelInputGlobals.autoCountry) {
710
- this.handleAutoCountry();
711
- } else if (!window.intlTelInputGlobals.startedLoadingAutoCountry) {
712
- // don't do this twice!
713
- window.intlTelInputGlobals.startedLoadingAutoCountry = true;
714
- if (typeof this.options.geoIpLookup === "function") {
715
- this.options.geoIpLookup(function(countryCode) {
716
- window.intlTelInputGlobals.autoCountry = countryCode.toLowerCase();
717
- // tell all instances the auto country is ready
718
- // TODO: this should just be the current instances
719
- // UPDATE: use setTimeout in case their geoIpLookup function calls this callback straight
720
- // away (e.g. if they have already done the geo ip lookup somewhere else). Using
721
- // setTimeout means that the current thread of execution will finish before executing
722
- // this, which allows the plugin to finish initialising.
723
- setTimeout(function() {
724
- return forEachInstance("handleAutoCountry");
725
- });
726
- }, function() {
727
- return forEachInstance("rejectAutoCountryPromise");
402
+ },
403
+ // perform the geo ip lookup
404
+ _loadAutoCountry: function () {
405
+ var that = this;
406
+ // 3 options:
407
+ // 1) already loaded (we're done)
408
+ // 2) not already started loading (start)
409
+ // 3) already started loading (do nothing - just wait for loading callback to fire)
410
+ if ($.fn[pluginName].autoCountry) {
411
+ this.handleAutoCountry();
412
+ } else if (!$.fn[pluginName].startedLoadingAutoCountry) {
413
+ // don't do this twice!
414
+ $.fn[pluginName].startedLoadingAutoCountry = true;
415
+ if (typeof this.options.geoIpLookup === "function") {
416
+ this.options.geoIpLookup(function (countryCode) {
417
+ $.fn[pluginName].autoCountry = countryCode.toLowerCase();
418
+ // tell all instances the auto country is ready
419
+ // TODO: this should just be the current instances
420
+ // 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.
421
+ setTimeout(function () {
422
+ $(".intl-tel-input input").intlTelInput("handleAutoCountry");
728
423
  });
729
- }
424
+ });
730
425
  }
731
426
  }
732
- }, {
733
- key: "_initKeyListeners",
734
- value: function _initKeyListeners() {
735
- var _this6 = this;
736
- // update flag on keyup
737
- this._handleKeyupEvent = function() {
738
- if (_this6._updateFlagFromNumber(_this6.telInput.value)) {
739
- _this6._triggerCountryChange();
740
- }
741
- };
742
- this.telInput.addEventListener("keyup", this._handleKeyupEvent);
743
- // update flag on cut/paste events (now supported in all major browsers)
744
- this._handleClipboardEvent = function() {
745
- // hack because "paste" event is fired before input is updated
746
- setTimeout(_this6._handleKeyupEvent);
747
- };
748
- this.telInput.addEventListener("cut", this._handleClipboardEvent);
749
- this.telInput.addEventListener("paste", this._handleClipboardEvent);
750
- }
751
- }, {
752
- key: "_cap",
753
- value: function _cap(number) {
754
- var max = this.telInput.getAttribute("maxlength");
755
- return max && number.length > max ? number.substr(0, max) : number;
756
- }
757
- }, {
758
- key: "_initBlurListeners",
759
- value: function _initBlurListeners() {
760
- var _this7 = this;
761
- // on blur or form submit: if just a dial code then remove it
762
- this._handleSubmitOrBlurEvent = function() {
763
- _this7._removeEmptyDialCode();
764
- };
765
- if (this.telInput.form) {
766
- this.telInput.form.addEventListener("submit", this._handleSubmitOrBlurEvent);
427
+ },
428
+ // initialize any key listeners
429
+ _initKeyListeners: function () {
430
+ var that = this;
431
+ // update flag on keyup
432
+ // (keep this listener separate otherwise the setTimeout breaks all the tests)
433
+ this.telInput.on("keyup" + this.ns, function () {
434
+ if (that._updateFlagFromNumber(that.telInput.val())) {
435
+ that._triggerCountryChange();
767
436
  }
768
- this.telInput.addEventListener("blur", this._handleSubmitOrBlurEvent);
769
- }
770
- }, {
771
- key: "_removeEmptyDialCode",
772
- value: function _removeEmptyDialCode() {
773
- if (this.telInput.value.charAt(0) === "+") {
774
- var numeric = this._getNumeric(this.telInput.value);
775
- // if just a plus, or if just a dial code
776
- if (!numeric || this.selectedCountryData.dialCode === numeric) {
777
- this.telInput.value = "";
437
+ });
438
+ // update flag on cut/paste events (now supported in all major browsers)
439
+ this.telInput.on("cut" + this.ns + " paste" + this.ns, function () {
440
+ // hack because "paste" event is fired before input is updated
441
+ setTimeout(function () {
442
+ if (that._updateFlagFromNumber(that.telInput.val())) {
443
+ that._triggerCountryChange();
778
444
  }
445
+ });
446
+ });
447
+ },
448
+ // adhere to the input's maxlength attr
449
+ _cap: function (number) {
450
+ var max = this.telInput.attr("maxlength");
451
+ return max && number.length > max ? number.substr(0, max) : number;
452
+ },
453
+ // listen for mousedown, focus and blur
454
+ _initFocusListeners: function () {
455
+ var that = this;
456
+ // 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
457
+ this.telInput.on("mousedown" + this.ns, function (e) {
458
+ if (!that.telInput.is(":focus") && !that.telInput.val()) {
459
+ e.preventDefault();
460
+ // but this also cancels the focus, so we must trigger that manually
461
+ that.telInput.focus();
779
462
  }
780
- }
781
- }, {
782
- key: "_getNumeric",
783
- value: function _getNumeric(s) {
784
- return s.replace(/\D/g, "");
785
- }
786
- }, {
787
- key: "_trigger",
788
- value: function _trigger(name) {
789
- // have to use old school document.createEvent as IE11 doesn't support `new Event()` syntax
790
- var e = document.createEvent("Event");
791
- e.initEvent(name, true, true);
792
- // can bubble, and is cancellable
793
- this.telInput.dispatchEvent(e);
794
- }
795
- }, {
796
- key: "_showDropdown",
797
- value: function _showDropdown() {
798
- this.countryList.classList.remove("iti__hide");
799
- this.selectedFlag.setAttribute("aria-expanded", "true");
800
- this._setDropdownPosition();
801
- // update highlighting and scroll to active list item
802
- if (this.activeItem) {
803
- this._highlightListItem(this.activeItem, false);
804
- this._scrollTo(this.activeItem, true);
463
+ });
464
+ // on focus: if empty, insert the dial code for the currently selected flag
465
+ this.telInput.on("focus" + this.ns, function (e) {
466
+ if (!that.telInput.val() && !that.telInput.prop("readonly") && that.selectedCountryData.dialCode) {
467
+ // insert the dial code
468
+ that.telInput.val("+" + that.selectedCountryData.dialCode);
469
+ // 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
470
+ that.telInput.one("keypress.plus" + that.ns, function (e) {
471
+ if (e.which == keys.PLUS) {
472
+ that.telInput.val("");
473
+ }
474
+ });
475
+ // 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
476
+ setTimeout(function () {
477
+ var input = that.telInput[0];
478
+ if (that.isGoodBrowser) {
479
+ var len = that.telInput.val().length;
480
+ input.setSelectionRange(len, len);
481
+ }
482
+ });
805
483
  }
806
- // bind all the dropdown-related listeners: mouseover, click, click-off, keydown
807
- this._bindDropdownListeners();
808
- // update the arrow
809
- this.dropdownArrow.classList.add("iti__arrow--up");
810
- this._trigger("open:countrydropdown");
484
+ });
485
+ // on blur or form submit: if just a dial code then remove it
486
+ var form = this.telInput.prop("form");
487
+ if (form) {
488
+ $(form).on("submit" + this.ns, function () {
489
+ that._removeEmptyDialCode();
490
+ });
811
491
  }
812
- }, {
813
- key: "_toggleClass",
814
- value: function _toggleClass(el, className, shouldHaveClass) {
815
- if (shouldHaveClass && !el.classList.contains(className)) {
816
- el.classList.add(className);
817
- } else if (!shouldHaveClass && el.classList.contains(className)) {
818
- el.classList.remove(className);
492
+ this.telInput.on("blur" + this.ns, function () {
493
+ that._removeEmptyDialCode();
494
+ });
495
+ },
496
+ _removeEmptyDialCode: function () {
497
+ var value = this.telInput.val(), startsPlus = value.charAt(0) == "+";
498
+ if (startsPlus) {
499
+ var numeric = this._getNumeric(value);
500
+ // if just a plus, or if just a dial code
501
+ if (!numeric || this.selectedCountryData.dialCode == numeric) {
502
+ this.telInput.val("");
819
503
  }
820
504
  }
821
- }, {
822
- key: "_setDropdownPosition",
823
- value: function _setDropdownPosition() {
824
- var _this8 = this;
505
+ // remove the keypress listener we added on focus
506
+ this.telInput.off("keypress.plus" + this.ns);
507
+ },
508
+ // extract the numeric digits from the given string
509
+ _getNumeric: function (s) {
510
+ return s.replace(/\D/g, "");
511
+ },
512
+ // show the dropdown
513
+ _showDropdown: function () {
514
+ this._setDropdownPosition();
515
+ // update highlighting and scroll to active list item
516
+ var activeListItem = this.countryList.children(".active");
517
+ if (activeListItem.length) {
518
+ this._highlightListItem(activeListItem);
519
+ this._scrollTo(activeListItem);
520
+ }
521
+ // bind all the dropdown-related listeners: mouseover, click, click-off, keydown
522
+ this._bindDropdownListeners();
523
+ // update the arrow
524
+ this.selectedFlagInner.children(".iti-arrow").addClass("up");
525
+ this.telInput.trigger("open:countrydropdown");
526
+ },
527
+ // decide where to position dropdown (depends on position within viewport, and scroll)
528
+ _setDropdownPosition: function () {
529
+ var that = this;
530
+ if (this.options.dropdownContainer) {
531
+ this.dropdown.appendTo(this.options.dropdownContainer);
532
+ }
533
+ // show the menu and grab the dropdown height
534
+ this.dropdownHeight = this.countryList.removeClass("hide").outerHeight();
535
+ if (!this.isMobile) {
536
+ var pos = this.telInput.offset(), inputTop = pos.top, windowTop = $(window).scrollTop(), // dropdownFitsBelow = (dropdownBottom < windowBottom)
537
+ dropdownFitsBelow = inputTop + this.telInput.outerHeight() + this.dropdownHeight < windowTop + $(window).height(), dropdownFitsAbove = inputTop - this.dropdownHeight > windowTop;
538
+ // by default, the dropdown will be below the input. If we want to position it above the input, we add the dropup class.
539
+ this.countryList.toggleClass("dropup", !dropdownFitsBelow && dropdownFitsAbove);
540
+ // if dropdownContainer is enabled, calculate postion
825
541
  if (this.options.dropdownContainer) {
826
- this.options.dropdownContainer.appendChild(this.dropdown);
827
- }
828
- if (!this.isMobile) {
829
- var pos = this.telInput.getBoundingClientRect();
830
- // windowTop from https://stackoverflow.com/a/14384091/217866
831
- var windowTop = window.pageYOffset || document.documentElement.scrollTop;
832
- var inputTop = pos.top + windowTop;
833
- var dropdownHeight = this.countryList.offsetHeight;
834
- // dropdownFitsBelow = (dropdownBottom < windowBottom)
835
- var dropdownFitsBelow = inputTop + this.telInput.offsetHeight + dropdownHeight < windowTop + window.innerHeight;
836
- var dropdownFitsAbove = inputTop - dropdownHeight > windowTop;
837
- // by default, the dropdown will be below the input. If we want to position it above the
838
- // input, we add the dropup class.
839
- this._toggleClass(this.countryList, "iti__country-list--dropup", !dropdownFitsBelow && dropdownFitsAbove);
840
- // if dropdownContainer is enabled, calculate postion
841
- if (this.options.dropdownContainer) {
842
- // by default the dropdown will be directly over the input because it's not in the flow.
843
- // If we want to position it below, we need to add some extra top value.
844
- var extraTop = !dropdownFitsBelow && dropdownFitsAbove ? 0 : this.telInput.offsetHeight;
845
- // calculate placement
846
- this.dropdown.style.top = "".concat(inputTop + extraTop, "px");
847
- this.dropdown.style.left = "".concat(pos.left + document.body.scrollLeft, "px");
848
- // close menu on window scroll
849
- this._handleWindowScroll = function() {
850
- return _this8._closeDropdown();
851
- };
852
- window.addEventListener("scroll", this._handleWindowScroll);
853
- }
854
- }
855
- }
856
- }, {
857
- key: "_getClosestListItem",
858
- value: function _getClosestListItem(target) {
859
- var el = target;
860
- while (el && el !== this.countryList && !el.classList.contains("iti__country")) {
861
- el = el.parentNode;
542
+ // 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.
543
+ var extraTop = !dropdownFitsBelow && dropdownFitsAbove ? 0 : this.telInput.innerHeight();
544
+ // calculate placement
545
+ this.dropdown.css({
546
+ top: inputTop + extraTop,
547
+ left: pos.left
548
+ });
549
+ // close menu on window scroll
550
+ $(window).on("scroll" + this.ns, function () {
551
+ that._closeDropdown();
552
+ });
862
553
  }
863
- // if we reached the countryList element, then return null
864
- return el === this.countryList ? null : el;
865
554
  }
866
- }, {
867
- key: "_bindDropdownListeners",
868
- value: function _bindDropdownListeners() {
869
- var _this9 = this;
870
- // when mouse over a list item, just highlight that one
871
- // we add the class "highlight", so if they hit "enter" we know which one to select
872
- this._handleMouseoverCountryList = function(e) {
873
- // handle event delegation, as we're listening for this event on the countryList
874
- var listItem = _this9._getClosestListItem(e.target);
875
- if (listItem) {
876
- _this9._highlightListItem(listItem, false);
877
- }
878
- };
879
- this.countryList.addEventListener("mouseover", this._handleMouseoverCountryList);
880
- // listen for country selection
881
- this._handleClickCountryList = function(e) {
882
- var listItem = _this9._getClosestListItem(e.target);
883
- if (listItem) {
884
- _this9._selectListItem(listItem);
885
- }
886
- };
887
- this.countryList.addEventListener("click", this._handleClickCountryList);
888
- // click off to close
889
- // (except when this initial opening click is bubbling up)
890
- // we cannot just stopPropagation as it may be needed to close another instance
891
- var isOpening = true;
892
- this._handleClickOffToClose = function() {
893
- if (!isOpening) {
894
- _this9._closeDropdown();
895
- }
896
- isOpening = false;
897
- };
898
- document.documentElement.addEventListener("click", this._handleClickOffToClose);
899
- // listen for up/down scrolling, enter to select, or letters to jump to country name.
900
- // use keydown as keypress doesn't fire for non-char keys and we want to catch if they
901
- // just hit down and hold it to scroll down (no keyup event).
902
- // listen on the document because that's where key events are triggered if no input has focus
903
- var query = "";
904
- var queryTimer = null;
905
- this._handleKeydownOnDropdown = function(e) {
906
- // prevent down key from scrolling the whole page,
907
- // and enter key from submitting a form etc
908
- e.preventDefault();
555
+ },
556
+ // we only bind dropdown listeners when the dropdown is open
557
+ _bindDropdownListeners: function () {
558
+ var that = this;
559
+ // when mouse over a list item, just highlight that one
560
+ // we add the class "highlight", so if they hit "enter" we know which one to select
561
+ this.countryList.on("mouseover" + this.ns, ".country", function (e) {
562
+ that._highlightListItem($(this));
563
+ });
564
+ // listen for country selection
565
+ this.countryList.on("click" + this.ns, ".country", function (e) {
566
+ that._selectListItem($(this));
567
+ });
568
+ // click off to close
569
+ // (except when this initial opening click is bubbling up)
570
+ // we cannot just stopPropagation as it may be needed to close another instance
571
+ var isOpening = true;
572
+ $("html").on("click" + this.ns, function (e) {
573
+ if (!isOpening) {
574
+ that._closeDropdown();
575
+ }
576
+ isOpening = false;
577
+ });
578
+ // listen for up/down scrolling, enter to select, or letters to jump to country name.
579
+ // use keydown as keypress doesn't fire for non-char keys and we want to catch if they
580
+ // just hit down and hold it to scroll down (no keyup event).
581
+ // listen on the document because that's where key events are triggered if no input has focus
582
+ var query = "", queryTimer = null;
583
+ $(document).on("keydown" + this.ns, function (e) {
584
+ // prevent down key from scrolling the whole page,
585
+ // and enter key from submitting a form etc
586
+ e.preventDefault();
587
+ if (e.which == keys.UP || e.which == keys.DOWN) {
909
588
  // up and down to navigate
910
- if (e.key === "ArrowUp" || e.key === "Up" || e.key === "ArrowDown" || e.key === "Down") {
911
- _this9._handleUpDownKey(e.key);
912
- } else if (e.key === "Enter") {
913
- _this9._handleEnterKey();
914
- } else if (e.key === "Escape") {
915
- _this9._closeDropdown();
916
- } else if (/^[a-zA-ZÀ-ÿа-яА-Я ]$/.test(e.key)) {
917
- // jump to countries that start with the query string
918
- if (queryTimer) {
919
- clearTimeout(queryTimer);
920
- }
921
- query += e.key.toLowerCase();
922
- _this9._searchForCountry(query);
923
- // if the timer hits 1 second, reset the query
924
- queryTimer = setTimeout(function() {
925
- query = "";
926
- }, 1e3);
927
- }
928
- };
929
- document.addEventListener("keydown", this._handleKeydownOnDropdown);
930
- }
931
- }, {
932
- key: "_handleUpDownKey",
933
- value: function _handleUpDownKey(key) {
934
- var next = key === "ArrowUp" || key === "Up" ? this.highlightedItem.previousElementSibling : this.highlightedItem.nextElementSibling;
935
- if (next) {
936
- // skip the divider
937
- if (next.classList.contains("iti__divider")) {
938
- next = key === "ArrowUp" || key === "Up" ? next.previousElementSibling : next.nextElementSibling;
939
- }
940
- this._highlightListItem(next, true);
941
- }
942
- }
943
- }, {
944
- key: "_handleEnterKey",
945
- value: function _handleEnterKey() {
946
- if (this.highlightedItem) {
947
- this._selectListItem(this.highlightedItem);
948
- }
949
- }
950
- }, {
951
- key: "_searchForCountry",
952
- value: function _searchForCountry(query) {
953
- for (var i = 0; i < this.countries.length; i++) {
954
- if (this._startsWith(this.countries[i].name, query)) {
955
- var listItem = this.countryList.querySelector("#iti-".concat(this.id, "__item-").concat(this.countries[i].iso2));
956
- // update highlighting and scroll
957
- this._highlightListItem(listItem, false);
958
- this._scrollTo(listItem, true);
959
- break;
589
+ that._handleUpDownKey(e.which);
590
+ } else if (e.which == keys.ENTER) {
591
+ // enter to select
592
+ that._handleEnterKey();
593
+ } else if (e.which == keys.ESC) {
594
+ // esc to close
595
+ that._closeDropdown();
596
+ } else if (e.which >= keys.A && e.which <= keys.Z || e.which == keys.SPACE) {
597
+ // upper case letters (note: keyup/keydown only return upper case letters)
598
+ // jump to countries that start with the query string
599
+ if (queryTimer) {
600
+ clearTimeout(queryTimer);
960
601
  }
602
+ query += String.fromCharCode(e.which);
603
+ that._searchForCountry(query);
604
+ // if the timer hits 1 second, reset the query
605
+ queryTimer = setTimeout(function () {
606
+ query = "";
607
+ }, 1e3);
961
608
  }
609
+ });
610
+ },
611
+ // highlight the next/prev item in the list (and ensure it is visible)
612
+ _handleUpDownKey: function (key) {
613
+ var current = this.countryList.children(".highlight").first();
614
+ var next = key == keys.UP ? current.prev() : current.next();
615
+ if (next.length) {
616
+ // skip the divider
617
+ if (next.hasClass("divider")) {
618
+ next = key == keys.UP ? next.prev() : next.next();
619
+ }
620
+ this._highlightListItem(next);
621
+ this._scrollTo(next);
962
622
  }
963
- }, {
964
- key: "_startsWith",
965
- value: function _startsWith(a, b) {
966
- return a.substr(0, b.length).toLowerCase() === b;
623
+ },
624
+ // select the currently highlighted item
625
+ _handleEnterKey: function () {
626
+ var currentCountry = this.countryList.children(".highlight").first();
627
+ if (currentCountry.length) {
628
+ this._selectListItem(currentCountry);
967
629
  }
968
- }, {
969
- key: "_updateValFromNumber",
970
- value: function _updateValFromNumber(originalNumber) {
971
- var number = originalNumber;
972
- if (this.options.formatOnDisplay && window.intlTelInputUtils && this.selectedCountryData) {
973
- var useNational = this.options.nationalMode || number.charAt(0) !== "+" && !this.options.separateDialCode;
974
- var _intlTelInputUtils$nu = intlTelInputUtils.numberFormat, NATIONAL = _intlTelInputUtils$nu.NATIONAL, INTERNATIONAL = _intlTelInputUtils$nu.INTERNATIONAL;
975
- var format = useNational ? NATIONAL : INTERNATIONAL;
976
- number = intlTelInputUtils.formatNumber(number, this.selectedCountryData.iso2, format);
630
+ },
631
+ // find the first list item whose name starts with the query string
632
+ _searchForCountry: function (query) {
633
+ for (var i = 0; i < this.countries.length; i++) {
634
+ if (this._startsWith(this.countries[i].name, query)) {
635
+ var listItem = this.countryList.children("[data-country-code=" + this.countries[i].iso2 + "]").not(".preferred");
636
+ // update highlighting and scroll
637
+ this._highlightListItem(listItem);
638
+ this._scrollTo(listItem, true);
639
+ break;
977
640
  }
978
- number = this._beforeSetNumber(number);
979
- this.telInput.value = number;
980
641
  }
981
- }, {
982
- key: "_updateFlagFromNumber",
983
- value: function _updateFlagFromNumber(originalNumber) {
984
- // if we already have US/Canada selected, make sure the number starts
985
- // with a +1 so _getDialCode will be able to extract the area code
986
- // update: if we dont yet have selectedCountryData, but we're here (trying to update the flag
987
- // from the number), that means we're initialising the plugin with a number that already has a
988
- // dial code, so fine to ignore this bit
989
- var number = originalNumber;
990
- var selectedDialCode = this.selectedCountryData.dialCode;
991
- var isNanp = selectedDialCode === "1";
992
- if (number && isNanp && number.charAt(0) !== "+") {
993
- if (number.charAt(0) !== "1") {
994
- number = "1".concat(number);
995
- }
996
- number = "+".concat(number);
997
- }
998
- // if separateDialCode enabled, then consider the selected dial code to be part of the number
999
- if (this.options.separateDialCode && selectedDialCode && number.charAt(0) !== "+") {
1000
- number = "+".concat(selectedDialCode).concat(number);
1001
- }
1002
- // try and extract valid dial code from input
1003
- var dialCode = this._getDialCode(number, true);
1004
- var numeric = this._getNumeric(number);
1005
- var countryCode = null;
1006
- if (dialCode) {
1007
- var countryCodes = this.countryCodes[this._getNumeric(dialCode)];
1008
- // check if the right country is already selected. this should be false if the number is
1009
- // longer than the matched dial code because in this case we need to make sure that if
1010
- // there are multiple country matches, that the first one is selected (note: we could
1011
- // just check that here, but it requires the same loop that we already have later)
1012
- var alreadySelected = countryCodes.indexOf(this.selectedCountryData.iso2) !== -1 && numeric.length <= dialCode.length - 1;
1013
- var isRegionlessNanpNumber = selectedDialCode === "1" && this._isRegionlessNanp(numeric);
1014
- // only update the flag if:
1015
- // A) NOT (we currently have a NANP flag selected, and the number is a regionlessNanp)
1016
- // AND
1017
- // B) the right country is not already selected
1018
- if (!isRegionlessNanpNumber && !alreadySelected) {
1019
- // if using onlyCountries option, countryCodes[0] may be empty, so we must find the first
1020
- // non-empty index
1021
- for (var j = 0; j < countryCodes.length; j++) {
1022
- if (countryCodes[j]) {
1023
- countryCode = countryCodes[j];
1024
- break;
1025
- }
642
+ },
643
+ // check if (uppercase) string a starts with string b
644
+ _startsWith: function (a, b) {
645
+ return a.substr(0, b.length).toUpperCase() == b;
646
+ },
647
+ // update the input's value to the given val (format first if possible)
648
+ // NOTE: this is called from _setInitialState, handleUtils and setNumber
649
+ _updateValFromNumber: function (number) {
650
+ if (this.options.formatOnDisplay && window.intlTelInputUtils && this.selectedCountryData) {
651
+ var format = !this.options.separateDialCode && (this.options.nationalMode || number.charAt(0) != "+") ? intlTelInputUtils.numberFormat.NATIONAL : intlTelInputUtils.numberFormat.INTERNATIONAL;
652
+ number = intlTelInputUtils.formatNumber(number, this.selectedCountryData.iso2, format);
653
+ }
654
+ number = this._beforeSetNumber(number);
655
+ this.telInput.val(number);
656
+ },
657
+ // check if need to select a new flag based on the given number
658
+ // Note: called from _setInitialState, keyup handler, setNumber
659
+ _updateFlagFromNumber: function (number) {
660
+ // 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
661
+ // 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
662
+ if (number && this.options.nationalMode && this.selectedCountryData.dialCode == "1" && number.charAt(0) != "+") {
663
+ if (number.charAt(0) != "1") {
664
+ number = "1" + number;
665
+ }
666
+ number = "+" + number;
667
+ }
668
+ // try and extract valid dial code from input
669
+ var dialCode = this._getDialCode(number), countryCode = null, numeric = this._getNumeric(number);
670
+ if (dialCode) {
671
+ // check if one of the matching countries is already selected
672
+ var countryCodes = this.countryCodes[this._getNumeric(dialCode)], alreadySelected = $.inArray(this.selectedCountryData.iso2, countryCodes) > -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
673
+ isNanpAreaCode = dialCode == "+1" && numeric.length >= 4, nanpSelected = this.selectedCountryData.dialCode == "1";
674
+ // only update the flag if:
675
+ // A) NOT (we currently have a NANP flag selected, and the number is a regionlessNanp)
676
+ // AND
677
+ // 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)
678
+ if (!(nanpSelected && this._isRegionlessNanp(numeric)) && (!alreadySelected || isNanpAreaCode)) {
679
+ // if using onlyCountries option, countryCodes[0] may be empty, so we must find the first non-empty index
680
+ for (var j = 0; j < countryCodes.length; j++) {
681
+ if (countryCodes[j]) {
682
+ countryCode = countryCodes[j];
683
+ break;
1026
684
  }
1027
685
  }
1028
- } else if (number.charAt(0) === "+" && numeric.length) {
1029
- // invalid dial code, so empty
1030
- // Note: use getNumeric here because the number has not been formatted yet, so could contain
1031
- // bad chars
1032
- countryCode = "";
1033
- } else if (!number || number === "+") {
1034
- // empty, or just a plus, so default
1035
- countryCode = this.defaultCountry;
1036
- }
1037
- if (countryCode !== null) {
1038
- return this._setFlag(countryCode);
1039
686
  }
1040
- return false;
687
+ } else if (number.charAt(0) == "+" && numeric.length) {
688
+ // invalid dial code, so empty
689
+ // Note: use getNumeric here because the number has not been formatted yet, so could contain bad chars
690
+ countryCode = "";
691
+ } else if (!number || number == "+") {
692
+ // empty, or just a plus, so default
693
+ countryCode = this.defaultCountry;
1041
694
  }
1042
- }, {
1043
- key: "_isRegionlessNanp",
1044
- value: function _isRegionlessNanp(number) {
1045
- var numeric = this._getNumeric(number);
1046
- if (numeric.charAt(0) === "1") {
1047
- var areaCode = numeric.substr(1, 3);
1048
- return regionlessNanpNumbers.indexOf(areaCode) !== -1;
1049
- }
1050
- return false;
695
+ if (countryCode !== null) {
696
+ return this._setFlag(countryCode);
1051
697
  }
1052
- }, {
1053
- key: "_highlightListItem",
1054
- value: function _highlightListItem(listItem, shouldFocus) {
1055
- var prevItem = this.highlightedItem;
1056
- if (prevItem) {
1057
- prevItem.classList.remove("iti__highlight");
1058
- }
1059
- this.highlightedItem = listItem;
1060
- this.highlightedItem.classList.add("iti__highlight");
1061
- this.selectedFlag.setAttribute("aria-activedescendant", listItem.getAttribute("id"));
1062
- if (shouldFocus) {
1063
- this.highlightedItem.focus();
1064
- }
1065
- }
1066
- }, {
1067
- key: "_getCountryData",
1068
- value: function _getCountryData(countryCode, ignoreOnlyCountriesOption, allowFail) {
1069
- var countryList = ignoreOnlyCountriesOption ? allCountries : this.countries;
1070
- for (var i = 0; i < countryList.length; i++) {
1071
- if (countryList[i].iso2 === countryCode) {
1072
- return countryList[i];
1073
- }
1074
- }
1075
- if (allowFail) {
1076
- return null;
698
+ return false;
699
+ },
700
+ // check if the given number is a regionless NANP number (expects the number to contain an international dial code)
701
+ _isRegionlessNanp: function (number) {
702
+ var numeric = this._getNumeric(number);
703
+ if (numeric.charAt(0) == "1") {
704
+ var areaCode = numeric.substr(1, 3);
705
+ return $.inArray(areaCode, regionlessNanpNumbers) > -1;
706
+ }
707
+ return false;
708
+ },
709
+ // remove highlighting from other list items and highlight the given item
710
+ _highlightListItem: function (listItem) {
711
+ this.countryListItems.removeClass("highlight");
712
+ listItem.addClass("highlight");
713
+ },
714
+ // find the country data for the given country code
715
+ // the ignoreOnlyCountriesOption is only used during init() while parsing the onlyCountries array
716
+ _getCountryData: function (countryCode, ignoreOnlyCountriesOption, allowFail) {
717
+ var countryList = ignoreOnlyCountriesOption ? allCountries : this.countries;
718
+ for (var i = 0; i < countryList.length; i++) {
719
+ if (countryList[i].iso2 == countryCode) {
720
+ return countryList[i];
1077
721
  }
1078
- throw new Error("No country data for '".concat(countryCode, "'"));
1079
722
  }
1080
- }, {
1081
- key: "_setFlag",
1082
- value: function _setFlag(countryCode) {
1083
- var _this$options3 = this.options, allowDropdown = _this$options3.allowDropdown, separateDialCode = _this$options3.separateDialCode, showFlags = _this$options3.showFlags;
1084
- var prevCountry = this.selectedCountryData.iso2 ? this.selectedCountryData : {};
1085
- // do this first as it will throw an error and stop if countryCode is invalid
1086
- this.selectedCountryData = countryCode ? this._getCountryData(countryCode, false, false) : {};
1087
- // update the defaultCountry - we only need the iso2 from now on, so just store that
1088
- if (this.selectedCountryData.iso2) {
1089
- this.defaultCountry = this.selectedCountryData.iso2;
1090
- }
1091
- if (showFlags) {
1092
- this.selectedFlagInner.setAttribute("class", "iti__flag iti__".concat(countryCode));
1093
- }
1094
- this._setSelectedCountryFlagTitleAttribute(countryCode, separateDialCode);
1095
- if (separateDialCode) {
1096
- var dialCode = this.selectedCountryData.dialCode ? "+".concat(this.selectedCountryData.dialCode) : "";
1097
- this.selectedDialCode.innerHTML = dialCode;
1098
- // offsetWidth is zero if input is in a hidden container during initialisation
1099
- var selectedFlagWidth = this.selectedFlag.offsetWidth || this._getHiddenSelectedFlagWidth();
1100
- // add 6px of padding after the grey selected-dial-code box, as this is what we use in the css
1101
- if (this.isRTL) {
1102
- this.telInput.style.paddingRight = "".concat(selectedFlagWidth + 6, "px");
1103
- } else {
1104
- this.telInput.style.paddingLeft = "".concat(selectedFlagWidth + 6, "px");
1105
- }
1106
- }
1107
- // and the input's placeholder
1108
- this._updatePlaceholder();
1109
- // update the active list item
1110
- if (allowDropdown) {
1111
- var prevItem = this.activeItem;
1112
- if (prevItem) {
1113
- prevItem.classList.remove("iti__active");
1114
- prevItem.setAttribute("aria-selected", "false");
1115
- }
1116
- if (countryCode) {
1117
- // check if there is a preferred item first, else fall back to standard
1118
- var nextItem = this.countryList.querySelector("#iti-".concat(this.id, "__item-").concat(countryCode, "-preferred")) || this.countryList.querySelector("#iti-".concat(this.id, "__item-").concat(countryCode));
1119
- nextItem.setAttribute("aria-selected", "true");
1120
- nextItem.classList.add("iti__active");
1121
- this.activeItem = nextItem;
1122
- }
1123
- }
1124
- // return if the flag has changed or not
1125
- return prevCountry.iso2 !== countryCode;
723
+ if (allowFail) {
724
+ return null;
725
+ } else {
726
+ throw new Error("No country data for '" + countryCode + "'");
1126
727
  }
1127
- }, {
1128
- key: "_setSelectedCountryFlagTitleAttribute",
1129
- value: function _setSelectedCountryFlagTitleAttribute(countryCode, separateDialCode) {
1130
- if (!this.selectedFlag) {
1131
- return;
1132
- }
1133
- var title;
1134
- if (countryCode && !separateDialCode) {
1135
- title = "".concat(this.selectedCountryData.name, ": +").concat(this.selectedCountryData.dialCode);
1136
- } else if (countryCode) {
1137
- // For screen reader output, we don't want to include the dial code in the reader output twice
1138
- // so just use the selected country name here:
1139
- title = this.selectedCountryData.name;
1140
- } else {
1141
- title = "Unknown";
728
+ },
729
+ // select the given flag, update the placeholder and the active list item
730
+ // Note: called from _setInitialState, _updateFlagFromNumber, _selectListItem, setCountry
731
+ _setFlag: function (countryCode) {
732
+ var prevCountry = this.selectedCountryData.iso2 ? this.selectedCountryData : {};
733
+ // do this first as it will throw an error and stop if countryCode is invalid
734
+ this.selectedCountryData = countryCode ? this._getCountryData(countryCode, false, false) : {};
735
+ // update the defaultCountry - we only need the iso2 from now on, so just store that
736
+ if (this.selectedCountryData.iso2) {
737
+ this.defaultCountry = this.selectedCountryData.iso2;
738
+ }
739
+ this.selectedFlagInner.attr("class", "iti-flag " + countryCode);
740
+ // update the selected country's title attribute
741
+ var title = countryCode ? this.selectedCountryData.name + ": +" + this.selectedCountryData.dialCode : "Unknown";
742
+ this.selectedFlagInner.parent().attr("title", title);
743
+ if (this.options.separateDialCode) {
744
+ var dialCode = this.selectedCountryData.dialCode ? "+" + this.selectedCountryData.dialCode : "", parent = this.telInput.parent();
745
+ if (prevCountry.dialCode) {
746
+ parent.removeClass("iti-sdc-" + (prevCountry.dialCode.length + 1));
1142
747
  }
1143
- this.selectedFlag.setAttribute("title", title);
1144
- }
1145
- }, {
1146
- key: "_getHiddenSelectedFlagWidth",
1147
- value: function _getHiddenSelectedFlagWidth() {
1148
- // to get the right styling to apply, all we need is a shallow clone of the container,
1149
- // and then to inject a deep clone of the selectedFlag element
1150
- var containerClone = this.telInput.parentNode.cloneNode();
1151
- containerClone.style.visibility = "hidden";
1152
- document.body.appendChild(containerClone);
1153
- var flagsContainerClone = this.flagsContainer.cloneNode();
1154
- containerClone.appendChild(flagsContainerClone);
1155
- var selectedFlagClone = this.selectedFlag.cloneNode(true);
1156
- flagsContainerClone.appendChild(selectedFlagClone);
1157
- var width = selectedFlagClone.offsetWidth;
1158
- containerClone.parentNode.removeChild(containerClone);
1159
- return width;
1160
- }
1161
- }, {
1162
- key: "_updatePlaceholder",
1163
- value: function _updatePlaceholder() {
1164
- var shouldSetPlaceholder = this.options.autoPlaceholder === "aggressive" || !this.hadInitialPlaceholder && this.options.autoPlaceholder === "polite";
1165
- if (window.intlTelInputUtils && shouldSetPlaceholder) {
1166
- var numberType = intlTelInputUtils.numberType[this.options.placeholderNumberType];
1167
- var placeholder = this.selectedCountryData.iso2 ? intlTelInputUtils.getExampleNumber(this.selectedCountryData.iso2, this.options.nationalMode, numberType) : "";
1168
- placeholder = this._beforeSetNumber(placeholder);
1169
- if (typeof this.options.customPlaceholder === "function") {
1170
- placeholder = this.options.customPlaceholder(placeholder, this.selectedCountryData);
1171
- }
1172
- this.telInput.setAttribute("placeholder", placeholder);
748
+ if (dialCode) {
749
+ parent.addClass("iti-sdc-" + dialCode.length);
1173
750
  }
751
+ this.selectedDialCode.text(dialCode);
1174
752
  }
1175
- }, {
1176
- key: "_selectListItem",
1177
- value: function _selectListItem(listItem) {
1178
- // update selected flag and active list item
1179
- var flagChanged = this._setFlag(listItem.getAttribute("data-country-code"));
1180
- this._closeDropdown();
1181
- this._updateDialCode(listItem.getAttribute("data-dial-code"));
1182
- // focus the input
1183
- this.telInput.focus();
1184
- // put cursor at end - this fix is required for FF and IE11 (with auto inserting dial code),
1185
- // who try to put the cursor at the beginning the first time
1186
- var len = this.telInput.value.length;
1187
- this.telInput.setSelectionRange(len, len);
1188
- if (flagChanged) {
1189
- this._triggerCountryChange();
1190
- }
753
+ // and the input's placeholder
754
+ this._updatePlaceholder();
755
+ // update the active list item
756
+ this.countryListItems.removeClass("active");
757
+ if (countryCode) {
758
+ this.countryListItems.find(".iti-flag." + countryCode).first().closest(".country").addClass("active");
1191
759
  }
1192
- }, {
1193
- key: "_closeDropdown",
1194
- value: function _closeDropdown() {
1195
- this.countryList.classList.add("iti__hide");
1196
- this.selectedFlag.setAttribute("aria-expanded", "false");
1197
- this.selectedFlag.removeAttribute("aria-activedescendant");
1198
- // update the arrow
1199
- this.dropdownArrow.classList.remove("iti__arrow--up");
1200
- // unbind key events
1201
- document.removeEventListener("keydown", this._handleKeydownOnDropdown);
1202
- document.documentElement.removeEventListener("click", this._handleClickOffToClose);
1203
- this.countryList.removeEventListener("mouseover", this._handleMouseoverCountryList);
1204
- this.countryList.removeEventListener("click", this._handleClickCountryList);
1205
- // remove menu from container
1206
- if (this.options.dropdownContainer) {
1207
- if (!this.isMobile) {
1208
- window.removeEventListener("scroll", this._handleWindowScroll);
1209
- }
1210
- if (this.dropdown.parentNode) {
1211
- this.dropdown.parentNode.removeChild(this.dropdown);
1212
- }
760
+ // return if the flag has changed or not
761
+ return prevCountry.iso2 !== countryCode;
762
+ },
763
+ // update the input placeholder to an example number from the currently selected country
764
+ _updatePlaceholder: function () {
765
+ var shouldSetPlaceholder = this.options.autoPlaceholder === "aggressive" || !this.hadInitialPlaceholder && (this.options.autoPlaceholder === true || this.options.autoPlaceholder === "polite");
766
+ if (window.intlTelInputUtils && shouldSetPlaceholder) {
767
+ var numberType = intlTelInputUtils.numberType[this.options.placeholderNumberType], placeholder = this.selectedCountryData.iso2 ? intlTelInputUtils.getExampleNumber(this.selectedCountryData.iso2, this.options.nationalMode, numberType) : "";
768
+ placeholder = this._beforeSetNumber(placeholder);
769
+ if (typeof this.options.customPlaceholder === "function") {
770
+ placeholder = this.options.customPlaceholder(placeholder, this.selectedCountryData);
1213
771
  }
1214
- this._trigger("close:countrydropdown");
772
+ this.telInput.attr("placeholder", placeholder);
1215
773
  }
1216
- }, {
1217
- key: "_scrollTo",
1218
- value: function _scrollTo(element, middle) {
1219
- var container = this.countryList;
1220
- // windowTop from https://stackoverflow.com/a/14384091/217866
1221
- var windowTop = window.pageYOffset || document.documentElement.scrollTop;
1222
- var containerHeight = container.offsetHeight;
1223
- var containerTop = container.getBoundingClientRect().top + windowTop;
1224
- var containerBottom = containerTop + containerHeight;
1225
- var elementHeight = element.offsetHeight;
1226
- var elementTop = element.getBoundingClientRect().top + windowTop;
1227
- var elementBottom = elementTop + elementHeight;
1228
- var newScrollTop = elementTop - containerTop + container.scrollTop;
1229
- var middleOffset = containerHeight / 2 - elementHeight / 2;
1230
- if (elementTop < containerTop) {
1231
- // scroll up
1232
- if (middle) {
1233
- newScrollTop -= middleOffset;
1234
- }
1235
- container.scrollTop = newScrollTop;
1236
- } else if (elementBottom > containerBottom) {
1237
- // scroll down
1238
- if (middle) {
1239
- newScrollTop += middleOffset;
1240
- }
1241
- var heightDifference = containerHeight - elementHeight;
1242
- container.scrollTop = newScrollTop - heightDifference;
1243
- }
774
+ },
775
+ // called when the user selects a list item from the dropdown
776
+ _selectListItem: function (listItem) {
777
+ // update selected flag and active list item
778
+ var flagChanged = this._setFlag(listItem.attr("data-country-code"));
779
+ this._closeDropdown();
780
+ this._updateDialCode(listItem.attr("data-dial-code"), true);
781
+ // focus the input
782
+ this.telInput.focus();
783
+ // 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
784
+ if (this.isGoodBrowser) {
785
+ var len = this.telInput.val().length;
786
+ this.telInput[0].setSelectionRange(len, len);
787
+ }
788
+ if (flagChanged) {
789
+ this._triggerCountryChange();
1244
790
  }
1245
- }, {
1246
- key: "_updateDialCode",
1247
- value: function _updateDialCode(newDialCodeBare) {
1248
- var inputVal = this.telInput.value;
1249
- // save having to pass this every time
1250
- var newDialCode = "+".concat(newDialCodeBare);
1251
- var newNumber;
1252
- if (inputVal.charAt(0) === "+") {
1253
- // there's a plus so we're dealing with a replacement
1254
- var prevDialCode = this._getDialCode(inputVal);
1255
- if (prevDialCode) {
1256
- // current number contains a valid dial code, so replace it
1257
- newNumber = inputVal.replace(prevDialCode, newDialCode);
1258
- } else {
1259
- // current number contains an invalid dial code, so ditch it
1260
- // (no way to determine where the invalid dial code ends and the rest of the number begins)
1261
- newNumber = newDialCode;
1262
- }
1263
- this.telInput.value = newNumber;
1264
- } else if (this.options.autoInsertDialCode) {
1265
- if (inputVal) {
1266
- // there is an existing value with no dial code: prefix the new dial code
1267
- newNumber = newDialCode + inputVal;
1268
- } else {
1269
- newNumber = newDialCode;
1270
- }
1271
- this.telInput.value = newNumber;
791
+ },
792
+ // close the dropdown and unbind any listeners
793
+ _closeDropdown: function () {
794
+ this.countryList.addClass("hide");
795
+ // update the arrow
796
+ this.selectedFlagInner.children(".iti-arrow").removeClass("up");
797
+ // unbind key events
798
+ $(document).off(this.ns);
799
+ // unbind click-off-to-close
800
+ $("html").off(this.ns);
801
+ // unbind hover and click listeners
802
+ this.countryList.off(this.ns);
803
+ // remove menu from container
804
+ if (this.options.dropdownContainer) {
805
+ if (!this.isMobile) {
806
+ $(window).off("scroll" + this.ns);
1272
807
  }
808
+ this.dropdown.detach();
1273
809
  }
1274
- }, {
1275
- key: "_getDialCode",
1276
- value: function _getDialCode(number, includeAreaCode) {
1277
- var dialCode = "";
1278
- // only interested in international numbers (starting with a plus)
1279
- if (number.charAt(0) === "+") {
1280
- var numericChars = "";
1281
- // iterate over chars
1282
- for (var i = 0; i < number.length; i++) {
1283
- var c = number.charAt(i);
1284
- // if char is number (https://stackoverflow.com/a/8935649/217866)
1285
- if (!isNaN(parseInt(c, 10))) {
1286
- numericChars += c;
1287
- // if current numericChars make a valid dial code
1288
- if (includeAreaCode) {
1289
- if (this.countryCodes[numericChars]) {
1290
- // store the actual raw string (useful for matching later)
1291
- dialCode = number.substr(0, i + 1);
1292
- }
1293
- } else {
1294
- if (this.dialCodes[numericChars]) {
1295
- dialCode = number.substr(0, i + 1);
1296
- // if we're just looking for a dial code, we can break as soon as we find one
1297
- break;
1298
- }
1299
- }
1300
- // stop searching as soon as we can - in this case when we hit max len
1301
- if (numericChars.length === this.countryCodeMaxLen) {
1302
- break;
1303
- }
1304
- }
1305
- }
1306
- }
1307
- return dialCode;
810
+ this.telInput.trigger("close:countrydropdown");
811
+ },
812
+ // check if an element is visible within it's container, else scroll until it is
813
+ _scrollTo: function (element, middle) {
814
+ var container = this.countryList, containerHeight = container.height(), containerTop = container.offset().top, containerBottom = containerTop + containerHeight, elementHeight = element.outerHeight(), elementTop = element.offset().top, elementBottom = elementTop + elementHeight, newScrollTop = elementTop - containerTop + container.scrollTop(), middleOffset = containerHeight / 2 - elementHeight / 2;
815
+ if (elementTop < containerTop) {
816
+ // scroll up
817
+ if (middle) {
818
+ newScrollTop -= middleOffset;
819
+ }
820
+ container.scrollTop(newScrollTop);
821
+ } else if (elementBottom > containerBottom) {
822
+ // scroll down
823
+ if (middle) {
824
+ newScrollTop += middleOffset;
825
+ }
826
+ var heightDifference = containerHeight - elementHeight;
827
+ container.scrollTop(newScrollTop - heightDifference);
1308
828
  }
1309
- }, {
1310
- key: "_getFullNumber",
1311
- value: function _getFullNumber() {
1312
- var val = this.telInput.value.trim();
1313
- var dialCode = this.selectedCountryData.dialCode;
1314
- var prefix;
1315
- var numericVal = this._getNumeric(val);
1316
- if (this.options.separateDialCode && val.charAt(0) !== "+" && dialCode && numericVal) {
1317
- // when using separateDialCode, it is visible so is effectively part of the typed number
1318
- prefix = "+".concat(dialCode);
829
+ },
830
+ // replace any existing dial code with the new one
831
+ // Note: called from _selectListItem and setCountry
832
+ _updateDialCode: function (newDialCode, hasSelectedListItem) {
833
+ var inputVal = this.telInput.val(), newNumber;
834
+ // save having to pass this every time
835
+ newDialCode = "+" + newDialCode;
836
+ if (inputVal.charAt(0) == "+") {
837
+ // there's a plus so we're dealing with a replacement (doesn't matter if nationalMode or not)
838
+ var prevDialCode = this._getDialCode(inputVal);
839
+ if (prevDialCode) {
840
+ // current number contains a valid dial code, so replace it
841
+ newNumber = inputVal.replace(prevDialCode, newDialCode);
1319
842
  } else {
1320
- prefix = "";
1321
- }
1322
- return prefix + val;
1323
- }
1324
- }, {
1325
- key: "_beforeSetNumber",
1326
- value: function _beforeSetNumber(originalNumber) {
1327
- var number = originalNumber;
1328
- if (this.options.separateDialCode) {
1329
- var dialCode = this._getDialCode(number);
1330
- // if there is a valid dial code
1331
- if (dialCode) {
1332
- // in case _getDialCode returned an area code as well
1333
- dialCode = "+".concat(this.selectedCountryData.dialCode);
1334
- // a lot of numbers will have a space separating the dial code and the main number, and
1335
- // some NANP numbers will have a hyphen e.g. +1 684-733-1234 - in both cases we want to get
1336
- // rid of it
1337
- // NOTE: don't just trim all non-numerics as may want to preserve an open parenthesis etc
1338
- var start = number[dialCode.length] === " " || number[dialCode.length] === "-" ? dialCode.length + 1 : dialCode.length;
1339
- number = number.substr(start);
1340
- }
1341
- }
1342
- return this._cap(number);
1343
- }
1344
- }, {
1345
- key: "_triggerCountryChange",
1346
- value: function _triggerCountryChange() {
1347
- this._trigger("countrychange");
1348
- }
1349
- }, {
1350
- key: "handleAutoCountry",
1351
- value: function handleAutoCountry() {
1352
- if (this.options.initialCountry === "auto") {
1353
- // we must set this even if there is an initial val in the input: in case the initial val is
1354
- // invalid and they delete it - they should see their auto country
1355
- this.defaultCountry = window.intlTelInputGlobals.autoCountry;
1356
- // if there's no initial value in the input, then update the flag
1357
- if (!this.telInput.value) {
1358
- this.setCountry(this.defaultCountry);
1359
- }
1360
- this.resolveAutoCountryPromise();
843
+ // current number contains an invalid dial code, so ditch it
844
+ // (no way to determine where the invalid dial code ends and the rest of the number begins)
845
+ newNumber = newDialCode;
846
+ }
847
+ } else if (this.options.nationalMode || this.options.separateDialCode) {
848
+ // don't do anything
849
+ return;
850
+ } else {
851
+ // nationalMode is disabled
852
+ if (inputVal) {
853
+ // there is an existing value with no dial code: prefix the new dial code
854
+ newNumber = newDialCode + inputVal;
855
+ } else if (hasSelectedListItem || !this.options.autoHideDialCode) {
856
+ // no existing value and either they've just selected a list item, or autoHideDialCode is disabled: insert new dial code
857
+ newNumber = newDialCode;
858
+ } else {
859
+ return;
1361
860
  }
1362
861
  }
1363
- }, {
1364
- key: "handleUtils",
1365
- value: function handleUtils() {
1366
- // if the request was successful
1367
- if (window.intlTelInputUtils) {
1368
- // if there's an initial value in the input, then format it
1369
- if (this.telInput.value) {
1370
- this._updateValFromNumber(this.telInput.value);
862
+ this.telInput.val(newNumber);
863
+ },
864
+ // try and extract a valid international dial code from a full telephone number
865
+ // Note: returns the raw string inc plus character and any whitespace/dots etc
866
+ _getDialCode: function (number) {
867
+ var dialCode = "";
868
+ // only interested in international numbers (starting with a plus)
869
+ if (number.charAt(0) == "+") {
870
+ var numericChars = "";
871
+ // iterate over chars
872
+ for (var i = 0; i < number.length; i++) {
873
+ var c = number.charAt(i);
874
+ // if char is number
875
+ if ($.isNumeric(c)) {
876
+ numericChars += c;
877
+ // if current numericChars make a valid dial code
878
+ if (this.countryCodes[numericChars]) {
879
+ // store the actual raw string (useful for matching later)
880
+ dialCode = number.substr(0, i + 1);
881
+ }
882
+ // longest dial code is 4 chars
883
+ if (numericChars.length == 4) {
884
+ break;
885
+ }
1371
886
  }
1372
- this._updatePlaceholder();
1373
887
  }
1374
- this.resolveUtilsScriptPromise();
1375
888
  }
1376
- }, {
1377
- key: "destroy",
1378
- value: function destroy() {
1379
- var form = this.telInput.form;
1380
- if (this.options.allowDropdown) {
1381
- // make sure the dropdown is closed (and unbind listeners)
1382
- this._closeDropdown();
1383
- this.selectedFlag.removeEventListener("click", this._handleClickSelectedFlag);
1384
- this.flagsContainer.removeEventListener("keydown", this._handleFlagsContainerKeydown);
1385
- // label click hack
1386
- var label = this._getClosestLabel();
1387
- if (label) {
1388
- label.removeEventListener("click", this._handleLabelClick);
1389
- }
1390
- }
1391
- // unbind hiddenInput listeners
1392
- if (this.hiddenInput && form) {
1393
- form.removeEventListener("submit", this._handleHiddenInputSubmit);
1394
- }
1395
- // unbind autoInsertDialCode listeners
1396
- if (this.options.autoInsertDialCode) {
1397
- if (form) {
1398
- form.removeEventListener("submit", this._handleSubmitOrBlurEvent);
889
+ return dialCode;
890
+ },
891
+ // get the input val, adding the dial code if separateDialCode is enabled
892
+ _getFullNumber: function () {
893
+ var val = $.trim(this.telInput.val()), 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
894
+ normalizedVal = numericVal.charAt(0) == "1" ? numericVal : "1" + numericVal;
895
+ if (this.options.separateDialCode) {
896
+ prefix = "+" + dialCode;
897
+ } else if (val.charAt(0) != "+" && val.charAt(0) != "1" && dialCode && dialCode.charAt(0) == "1" && dialCode.length == 4 && dialCode != normalizedVal.substr(0, 4)) {
898
+ // if the user has entered a national NANP number, then ensure it includes the full dial code / area code
899
+ prefix = dialCode.substr(1);
900
+ } else {
901
+ prefix = "";
902
+ }
903
+ return prefix + val;
904
+ },
905
+ // remove the dial code if separateDialCode is enabled
906
+ _beforeSetNumber: function (number) {
907
+ if (this.options.separateDialCode) {
908
+ var dialCode = this._getDialCode(number);
909
+ if (dialCode) {
910
+ // US dialCode is "+1", which is what we want
911
+ // CA dialCode is "+1 123", which is wrong - should be "+1" (as it has multiple area codes)
912
+ // AS dialCode is "+1 684", which is what we want
913
+ // Solution: if the country has area codes, then revert to just the dial code
914
+ if (this.selectedCountryData.areaCodes !== null) {
915
+ dialCode = "+" + this.selectedCountryData.dialCode;
1399
916
  }
1400
- this.telInput.removeEventListener("blur", this._handleSubmitOrBlurEvent);
917
+ // 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
918
+ // NOTE: don't just trim all non-numerics as may want to preserve an open parenthesis etc
919
+ var start = number[dialCode.length] === " " || number[dialCode.length] === "-" ? dialCode.length + 1 : dialCode.length;
920
+ number = number.substr(start);
1401
921
  }
1402
- // unbind key events, and cut/paste events
1403
- this.telInput.removeEventListener("keyup", this._handleKeyupEvent);
1404
- this.telInput.removeEventListener("cut", this._handleClipboardEvent);
1405
- this.telInput.removeEventListener("paste", this._handleClipboardEvent);
1406
- // remove attribute of id instance: data-intl-tel-input-id
1407
- this.telInput.removeAttribute("data-intl-tel-input-id");
1408
- // remove markup (but leave the original input)
1409
- var wrapper = this.telInput.parentNode;
1410
- wrapper.parentNode.insertBefore(this.telInput, wrapper);
1411
- wrapper.parentNode.removeChild(wrapper);
1412
- delete window.intlTelInputGlobals.instances[this.id];
1413
922
  }
1414
- }, {
1415
- key: "getExtension",
1416
- value: function getExtension() {
1417
- if (window.intlTelInputUtils) {
1418
- return intlTelInputUtils.getExtension(this._getFullNumber(), this.selectedCountryData.iso2);
1419
- }
1420
- return "";
1421
- }
1422
- }, {
1423
- key: "getNumber",
1424
- value: function getNumber(format) {
1425
- if (window.intlTelInputUtils) {
1426
- var iso2 = this.selectedCountryData.iso2;
1427
- return intlTelInputUtils.formatNumber(this._getFullNumber(), iso2, format);
1428
- }
1429
- return "";
1430
- }
1431
- }, {
1432
- key: "getNumberType",
1433
- value: function getNumberType() {
1434
- if (window.intlTelInputUtils) {
1435
- return intlTelInputUtils.getNumberType(this._getFullNumber(), this.selectedCountryData.iso2);
1436
- }
1437
- return -99;
1438
- }
1439
- }, {
1440
- key: "getSelectedCountryData",
1441
- value: function getSelectedCountryData() {
1442
- return this.selectedCountryData;
923
+ return this._cap(number);
924
+ },
925
+ // trigger the 'countrychange' event
926
+ _triggerCountryChange: function () {
927
+ this.telInput.trigger("countrychange", this.selectedCountryData);
928
+ },
929
+ /**************************
930
+ * SECRET PUBLIC METHODS
931
+ **************************/
932
+ // this is called when the geoip call returns
933
+ handleAutoCountry: function () {
934
+ if (this.options.initialCountry === "auto") {
935
+ // we must set this even if there is an initial val in the input: in case the initial val is invalid and they delete it - they should see their auto country
936
+ this.defaultCountry = $.fn[pluginName].autoCountry;
937
+ // if there's no initial value in the input, then update the flag
938
+ if (!this.telInput.val()) {
939
+ this.setCountry(this.defaultCountry);
940
+ }
941
+ this.autoCountryDeferred.resolve();
1443
942
  }
1444
- }, {
1445
- key: "getValidationError",
1446
- value: function getValidationError() {
1447
- if (window.intlTelInputUtils) {
1448
- var iso2 = this.selectedCountryData.iso2;
1449
- return intlTelInputUtils.getValidationError(this._getFullNumber(), iso2);
943
+ },
944
+ // this is called when the utils request completes
945
+ handleUtils: function () {
946
+ // if the request was successful
947
+ if (window.intlTelInputUtils) {
948
+ // if there's an initial value in the input, then format it
949
+ if (this.telInput.val()) {
950
+ this._updateValFromNumber(this.telInput.val());
1450
951
  }
1451
- return -99;
1452
- }
1453
- }, {
1454
- key: "isValidNumber",
1455
- value: function isValidNumber() {
1456
- var val = this._getFullNumber().trim();
1457
- return window.intlTelInputUtils ? intlTelInputUtils.isValidNumber(val, this.selectedCountryData.iso2) : null;
952
+ this._updatePlaceholder();
1458
953
  }
1459
- }, {
1460
- key: "setCountry",
1461
- value: function setCountry(originalCountryCode) {
1462
- var countryCode = originalCountryCode.toLowerCase();
1463
- // check if already selected
1464
- if (this.selectedCountryData.iso2 !== countryCode) {
1465
- this._setFlag(countryCode);
1466
- this._updateDialCode(this.selectedCountryData.dialCode);
1467
- this._triggerCountryChange();
1468
- }
954
+ this.utilsScriptDeferred.resolve();
955
+ },
956
+ /********************
957
+ * PUBLIC METHODS
958
+ ********************/
959
+ // remove plugin
960
+ destroy: function () {
961
+ if (this.allowDropdown) {
962
+ // make sure the dropdown is closed (and unbind listeners)
963
+ this._closeDropdown();
964
+ // click event to open dropdown
965
+ this.selectedFlagInner.parent().off(this.ns);
966
+ // label click hack
967
+ this.telInput.closest("label").off(this.ns);
968
+ }
969
+ // unbind submit event handler on form
970
+ if (this.options.autoHideDialCode) {
971
+ var form = this.telInput.prop("form");
972
+ if (form) {
973
+ $(form).off(this.ns);
974
+ }
975
+ }
976
+ // unbind all events: key events, and focus/blur events if autoHideDialCode=true
977
+ this.telInput.off(this.ns);
978
+ // remove markup (but leave the original input)
979
+ var container = this.telInput.parent();
980
+ container.before(this.telInput).remove();
981
+ },
982
+ // get the extension from the current number
983
+ getExtension: function () {
984
+ if (window.intlTelInputUtils) {
985
+ return intlTelInputUtils.getExtension(this._getFullNumber(), this.selectedCountryData.iso2);
1469
986
  }
1470
- }, {
1471
- key: "setNumber",
1472
- value: function setNumber(number) {
1473
- // we must update the flag first, which updates this.selectedCountryData, which is used for
1474
- // formatting the number before displaying it
1475
- var flagChanged = this._updateFlagFromNumber(number);
1476
- this._updateValFromNumber(number);
1477
- if (flagChanged) {
1478
- this._triggerCountryChange();
1479
- }
987
+ return "";
988
+ },
989
+ // format the number to the given format
990
+ getNumber: function (format) {
991
+ if (window.intlTelInputUtils) {
992
+ return intlTelInputUtils.formatNumber(this._getFullNumber(), this.selectedCountryData.iso2, format);
1480
993
  }
1481
- }, {
1482
- key: "setPlaceholderNumberType",
1483
- value: function setPlaceholderNumberType(type) {
1484
- this.options.placeholderNumberType = type;
1485
- this._updatePlaceholder();
994
+ return "";
995
+ },
996
+ // get the type of the entered number e.g. landline/mobile
997
+ getNumberType: function () {
998
+ if (window.intlTelInputUtils) {
999
+ return intlTelInputUtils.getNumberType(this._getFullNumber(), this.selectedCountryData.iso2);
1486
1000
  }
1487
- } ]);
1488
- return Iti;
1489
- }();
1490
- /********************
1491
- * STATIC METHODS
1492
- ********************/
1493
- // get the country data object
1494
- intlTelInputGlobals.getCountryData = function() {
1495
- return allCountries;
1496
- };
1497
- // inject a <script> element to load utils.js
1498
- var injectScript = function injectScript(path, handleSuccess, handleFailure) {
1499
- // inject a new script element into the page
1500
- var script = document.createElement("script");
1501
- script.onload = function() {
1502
- forEachInstance("handleUtils");
1503
- if (handleSuccess) {
1504
- handleSuccess();
1001
+ return -99;
1002
+ },
1003
+ // get the country data for the currently selected flag
1004
+ getSelectedCountryData: function () {
1005
+ return this.selectedCountryData;
1006
+ },
1007
+ // get the validation error
1008
+ getValidationError: function () {
1009
+ if (window.intlTelInputUtils) {
1010
+ return intlTelInputUtils.getValidationError(this._getFullNumber(), this.selectedCountryData.iso2);
1505
1011
  }
1506
- };
1507
- script.onerror = function() {
1508
- forEachInstance("rejectUtilsScriptPromise");
1509
- if (handleFailure) {
1510
- handleFailure();
1012
+ return -99;
1013
+ },
1014
+ // validate the input val - assumes the global function isValidNumber (from utilsScript)
1015
+ isValidNumber: function () {
1016
+ var val = $.trim(this._getFullNumber()), countryCode = this.options.nationalMode ? this.selectedCountryData.iso2 : "";
1017
+ return window.intlTelInputUtils ? intlTelInputUtils.isValidNumber(val, countryCode) : null;
1018
+ },
1019
+ // update the selected flag, and update the input val accordingly
1020
+ setCountry: function (countryCode) {
1021
+ countryCode = countryCode.toLowerCase();
1022
+ // check if already selected
1023
+ if (!this.selectedFlagInner.hasClass(countryCode)) {
1024
+ this._setFlag(countryCode);
1025
+ this._updateDialCode(this.selectedCountryData.dialCode, false);
1026
+ this._triggerCountryChange();
1511
1027
  }
1512
- };
1513
- script.className = "iti-load-utils";
1514
- script.async = true;
1515
- script.src = path;
1516
- document.body.appendChild(script);
1517
- };
1518
- // load the utils script
1519
- intlTelInputGlobals.loadUtils = function(path) {
1520
- // 2 options:
1521
- // 1) not already started loading (start)
1522
- // 2) already started loading (do nothing - just wait for the onload callback to fire, which will
1523
- // trigger handleUtils on all instances, invoking their resolveUtilsScriptPromise functions)
1524
- if (!window.intlTelInputUtils && !window.intlTelInputGlobals.startedLoadingUtilsScript) {
1525
- // only do this once
1526
- window.intlTelInputGlobals.startedLoadingUtilsScript = true;
1527
- // if we have promises, then return a promise
1528
- if (typeof Promise !== "undefined") {
1529
- return new Promise(function(resolve, reject) {
1530
- return injectScript(path, resolve, reject);
1531
- });
1028
+ },
1029
+ // set the input value and update the flag
1030
+ setNumber: function (number) {
1031
+ // we must update the flag first, which updates this.selectedCountryData, which is used for formatting the number before displaying it
1032
+ var flagChanged = this._updateFlagFromNumber(number);
1033
+ this._updateValFromNumber(number);
1034
+ if (flagChanged) {
1035
+ this._triggerCountryChange();
1532
1036
  }
1533
- injectScript(path);
1037
+ },
1038
+ // set the placeholder number typ
1039
+ setPlaceholderNumberType: function (type) {
1040
+ this.options.placeholderNumberType = type;
1041
+ this._updatePlaceholder();
1534
1042
  }
1535
- return null;
1536
1043
  };
1537
- // default options
1538
- intlTelInputGlobals.defaults = defaults;
1539
- // version
1540
- intlTelInputGlobals.version = "18.1.8";
1541
- var pluginName = "intlTelInput";
1542
- // A really lightweight plugin wrapper around the constructor,
1543
- // preventing against multiple instantiations
1544
- $.fn[pluginName] = function(options) {
1044
+ // using https://github.com/jquery-boilerplate/jquery-boilerplate/wiki/Extending-jQuery-Boilerplate
1045
+ // (adapted to allow public functions)
1046
+ $.fn[pluginName] = function (options) {
1545
1047
  var args = arguments;
1546
- // Is the first parameter an object (options), or was omitted, instantiate a new instance of the plugin.
1048
+ // Is the first parameter an object (options), or was omitted,
1049
+ // instantiate a new instance of the plugin.
1547
1050
  if (options === undefined || typeof options === "object") {
1548
- return this.each(function() {
1051
+ // collect all of the deferred objects for all instances created with this selector
1052
+ var deferreds = [];
1053
+ this.each(function () {
1549
1054
  if (!$.data(this, "plugin_" + pluginName)) {
1550
- var iti = new Iti(this, options);
1551
- iti._init();
1552
- window.intlTelInputGlobals.instances[iti.id] = iti;
1553
- $.data(this, "plugin_" + pluginName, iti);
1055
+ var instance = new Plugin(this, options);
1056
+ var instanceDeferreds = instance._init();
1057
+ // we now have 2 deffereds: 1 for auto country, 1 for utils script
1058
+ deferreds.push(instanceDeferreds[0]);
1059
+ deferreds.push(instanceDeferreds[1]);
1060
+ $.data(this, "plugin_" + pluginName, instance);
1554
1061
  }
1555
1062
  });
1063
+ // return the promise from the "master" deferred object that tracks all the others
1064
+ return $.when.apply(null, deferreds);
1556
1065
  } else if (typeof options === "string" && options[0] !== "_") {
1557
- // If the first parameter is a string and it doesn't start with an underscore treat this as a call to a public method.
1066
+ // If the first parameter is a string and it doesn't start
1067
+ // with an underscore or "contains" the `init`-function,
1068
+ // treat this as a call to a public method.
1558
1069
  // Cache the method call to make it possible to return a value
1559
1070
  var returns;
1560
- this.each(function() {
1071
+ this.each(function () {
1561
1072
  var instance = $.data(this, "plugin_" + pluginName);
1562
- // Tests that there's already a plugin-instance and checks that the requested public method exists
1563
- if (instance instanceof Iti && typeof instance[options] === "function") {
1564
- // Call the method of our plugin instance, and pass it the supplied arguments.
1073
+ // Tests that there's already a plugin-instance
1074
+ // and checks that the requested public method exists
1075
+ if (instance instanceof Plugin && typeof instance[options] === "function") {
1076
+ // Call the method of our plugin instance,
1077
+ // and pass it the supplied arguments.
1565
1078
  returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
1566
1079
  }
1567
1080
  // Allow instances to be destroyed via the 'destroy' method
1568
- if (options === "destroy") $.data(this, "plugin_" + pluginName, null);
1081
+ if (options === "destroy") {
1082
+ $.data(this, "plugin_" + pluginName, null);
1083
+ }
1569
1084
  });
1570
- // If the earlier cached method gives a value back return the value, otherwise return this to preserve chainability.
1085
+ // If the earlier cached method gives a value back return the value,
1086
+ // otherwise return this to preserve chainability.
1571
1087
  return returns !== undefined ? returns : this;
1572
1088
  }
1573
1089
  };
1090
+ /********************
1091
+ * STATIC METHODS
1092
+ ********************/
1093
+ // get the country data object
1094
+ $.fn[pluginName].getCountryData = function () {
1095
+ return allCountries;
1096
+ };
1097
+ // load the utils script
1098
+ $.fn[pluginName].loadUtils = function (path, utilsScriptDeferred) {
1099
+ if (!$.fn[pluginName].loadedUtilsScript) {
1100
+ // don't do this twice! (dont just check if window.intlTelInputUtils exists as if init plugin multiple times in quick succession, it may not have finished loading yet)
1101
+ $.fn[pluginName].loadedUtilsScript = true;
1102
+ // dont use $.getScript as it prevents caching
1103
+ $.ajax({
1104
+ type: "GET",
1105
+ url: path,
1106
+ complete: function () {
1107
+ // tell all instances that the utils request is complete
1108
+ $(".intl-tel-input input").intlTelInput("handleUtils");
1109
+ },
1110
+ dataType: "script",
1111
+ cache: true
1112
+ });
1113
+ } else if (utilsScriptDeferred) {
1114
+ utilsScriptDeferred.resolve();
1115
+ }
1116
+ };
1117
+ // default options
1118
+ $.fn[pluginName].defaults = defaults;
1119
+ // version
1120
+ $.fn[pluginName].version = "12.3.0";
1121
+ // Array of country objects for the flag dropdown.
1122
+ // Here is the criteria for the plugin to support a given country/territory
1123
+ // - It has an iso2 code: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2
1124
+ // - 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
1125
+ // - It has a flag in the region-flags project: https://github.com/behdad/region-flags/tree/gh-pages/png
1126
+ // - It is supported by libphonenumber (it must be listed on this page): https://github.com/googlei18n/libphonenumber/blob/master/resources/ShortNumberMetadata.xml
1127
+ // Each country array has the following information:
1128
+ // [
1129
+ // Country name,
1130
+ // iso2 code,
1131
+ // International dial code,
1132
+ // Order (if >1 country with same dial code),
1133
+ // Area codes
1134
+ // ]
1135
+ var allCountries = [["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"], ["Guernsey", "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], ["Israel (‫ישראל‬‎)", "il", "972"], ["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"], ["Россия", "ru", "7", 0], ["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"], ["Ukraine (Україна)", "ua", "380"], ["United Arab Emirates (‫الإمارات العربية المتحدة‬‎)", "ae", "971"], ["United Kingdom", "gb", "44", 0], ["United States", "us", "1", 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]];
1136
+ // loop over all of the countries above
1137
+ for (var i = 0; i < allCountries.length; i++) {
1138
+ var c = allCountries[i];
1139
+ allCountries[i] = {
1140
+ name: c[0],
1141
+ iso2: c[1],
1142
+ dialCode: c[2],
1143
+ priority: c[3] || 0,
1144
+ areaCodes: c[4] || null
1145
+ };
1146
+ }
1574
1147
  });