intl-tel-input 18.0.3 → 18.1.1

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.
Files changed (63) hide show
  1. package/.eslintrc +2 -8
  2. package/.vscode/settings.json +8 -0
  3. package/CHANGELOG.md +3 -0
  4. package/Gruntfile.js +0 -2
  5. package/README.md +24 -30
  6. package/build/css/intlTelInput.css +1 -1
  7. package/build/js/data.js +1 -1
  8. package/build/js/data.min.js +1 -1
  9. package/build/js/intlTelInput-jquery.js +213 -89
  10. package/build/js/intlTelInput-jquery.min.js +3 -3
  11. package/build/js/intlTelInput.js +213 -89
  12. package/build/js/intlTelInput.min.js +3 -3
  13. package/composer.json +1 -1
  14. package/demo.html +42 -43
  15. package/demo_rtl.html +21 -23
  16. package/grunt/template.js +2 -265
  17. package/package.json +4 -1
  18. package/src/css/intlTelInput.scss +1 -1
  19. package/src/js/intlTelInput.js +605 -341
  20. package/examples/css/countrySync.css +0 -10
  21. package/examples/css/isValidNumber.css +0 -12
  22. package/examples/css/prism.css +0 -126
  23. package/examples/gen/country-sync.html +0 -98
  24. package/examples/gen/default-country-ip.html +0 -62
  25. package/examples/gen/display-number.html +0 -47
  26. package/examples/gen/hidden-input.html +0 -54
  27. package/examples/gen/init-promise.html +0 -66
  28. package/examples/gen/is-valid-number.html +0 -86
  29. package/examples/gen/js/countrySync.js +0 -31
  30. package/examples/gen/js/defaultCountryIp.js +0 -11
  31. package/examples/gen/js/displayNumber.js +0 -4
  32. package/examples/gen/js/hiddenInput.js +0 -5
  33. package/examples/gen/js/initPromise.js +0 -9
  34. package/examples/gen/js/isValidNumber.js +0 -37
  35. package/examples/gen/js/modifyCountryData.js +0 -11
  36. package/examples/gen/js/multipleInstances.js +0 -13
  37. package/examples/gen/js/nationalMode.js +0 -18
  38. package/examples/gen/js/onlyCountriesEurope.js +0 -8
  39. package/examples/gen/modify-country-data.html +0 -52
  40. package/examples/gen/multiple-instances.html +0 -60
  41. package/examples/gen/national-mode.html +0 -63
  42. package/examples/gen/only-countries-europe.html +0 -49
  43. package/examples/js/countrySync.js.ejs +0 -31
  44. package/examples/js/defaultCountryIp.js.ejs +0 -11
  45. package/examples/js/displayNumber.js.ejs +0 -4
  46. package/examples/js/hiddenInput.js.ejs +0 -5
  47. package/examples/js/initPromise.js.ejs +0 -9
  48. package/examples/js/isValidNumber.js.ejs +0 -37
  49. package/examples/js/modifyCountryData.js.ejs +0 -11
  50. package/examples/js/multipleInstances.js.ejs +0 -13
  51. package/examples/js/nationalMode.js.ejs +0 -18
  52. package/examples/js/onlyCountriesEurope.js.ejs +0 -8
  53. package/examples/js/prism.js +0 -11
  54. package/examples/partials/countrySync.html +0 -13
  55. package/examples/partials/defaultCountryIp.html +0 -5
  56. package/examples/partials/displayNumber.html +0 -1
  57. package/examples/partials/hiddenInput.html +0 -4
  58. package/examples/partials/initPromise.html +0 -8
  59. package/examples/partials/isValidNumber.html +0 -3
  60. package/examples/partials/multipleInstances.html +0 -3
  61. package/examples/partials/nationalMode.html +0 -2
  62. package/examples/partials/simpleInput.html +0 -1
  63. package/examples/template.html.ejs +0 -43
@@ -1,14 +1,16 @@
1
1
  const intlTelInputGlobals = {
2
2
  getInstance: (input) => {
3
- const id = input.getAttribute('data-intl-tel-input-id');
3
+ const id = input.getAttribute("data-intl-tel-input-id");
4
4
  return window.intlTelInputGlobals.instances[id];
5
5
  },
6
6
  instances: {},
7
7
  // using a global like this allows us to mock it in the tests
8
- documentReady: () => document.readyState === 'complete',
8
+ documentReady: () => document.readyState === "complete"
9
9
  };
10
10
 
11
- if (typeof window === 'object') window.intlTelInputGlobals = intlTelInputGlobals;
11
+ if (typeof window === "object") {
12
+ window.intlTelInputGlobals = intlTelInputGlobals;
13
+ }
12
14
 
13
15
  // these vars persist through all instances of the plugin
14
16
  let id = 0;
@@ -19,9 +21,9 @@ const defaults = {
19
21
  // also listen for blur/submit and auto remove dial code if that's all there is
20
22
  autoInsertDialCode: false,
21
23
  // add a placeholder in the input with an example number for the selected country
22
- autoPlaceholder: 'polite',
24
+ autoPlaceholder: "polite",
23
25
  // modify the parentClass
24
- customContainer: '',
26
+ customContainer: "",
25
27
  // modify the auto placeholder
26
28
  customPlaceholder: null,
27
29
  // append menu to specified element
@@ -33,27 +35,46 @@ const defaults = {
33
35
  // geoIp lookup function
34
36
  geoIpLookup: null,
35
37
  // inject a hidden input with this name, and on submit, populate it with the result of getNumber
36
- hiddenInput: '',
38
+ hiddenInput: "",
37
39
  // initial country
38
- initialCountry: '',
40
+ initialCountry: "",
39
41
  // localized country names e.g. { 'de': 'Deutschland' }
40
42
  localizedCountries: null,
41
- // deal with national numbers instead of international numbers
43
+ // national vs international formatting for numbers e.g. placeholders and displaying existing numbers
42
44
  nationalMode: true,
43
45
  // display only these countries
44
46
  onlyCountries: [],
45
47
  // number type to use for placeholders
46
- placeholderNumberType: 'MOBILE',
48
+ placeholderNumberType: "MOBILE",
47
49
  // the countries at the top of the list. defaults to united states and united kingdom
48
- preferredCountries: ['us', 'gb'],
50
+ preferredCountries: ["us", "gb"],
49
51
  // display the country dial code next to the selected flag
50
52
  separateDialCode: false,
53
+ // option to hide the flags - must be used with separateDialCode, or allowDropdown=false
54
+ showFlags: true,
51
55
  // specify the path to the libphonenumber script to enable validation/formatting
52
- utilsScript: '',
56
+ utilsScript: ""
53
57
  };
54
58
  // https://en.wikipedia.org/wiki/List_of_North_American_Numbering_Plan_area_codes#Non-geographic_area_codes
55
- const regionlessNanpNumbers = ['800', '822', '833', '844', '855', '866', '877', '880', '881', '882', '883', '884', '885', '886', '887', '888', '889'];
56
-
59
+ const regionlessNanpNumbers = [
60
+ "800",
61
+ "822",
62
+ "833",
63
+ "844",
64
+ "855",
65
+ "866",
66
+ "877",
67
+ "880",
68
+ "881",
69
+ "882",
70
+ "883",
71
+ "884",
72
+ "885",
73
+ "886",
74
+ "887",
75
+ "888",
76
+ "889"
77
+ ];
57
78
 
58
79
  // utility function to iterate over an object. can't use Object.entries or native forEach because
59
80
  // of IE11
@@ -64,7 +85,6 @@ const forEachProp = (obj, callback) => {
64
85
  }
65
86
  };
66
87
 
67
-
68
88
  // run a method on each instance of the plugin
69
89
  const forEachInstance = (method) => {
70
90
  forEachProp(window.intlTelInputGlobals.instances, (key) => {
@@ -72,7 +92,6 @@ const forEachInstance = (method) => {
72
92
  });
73
93
  };
74
94
 
75
-
76
95
  // this is our plugin class that we will create an instance of
77
96
  // eslint-disable-next-line no-unused-vars
78
97
  class Iti {
@@ -88,38 +107,57 @@ class Iti {
88
107
  const customOptions = options || {};
89
108
  this.options = {};
90
109
  forEachProp(defaults, (key, value) => {
91
- this.options[key] = (customOptions.hasOwnProperty(key)) ? customOptions[key] : value;
110
+ this.options[key] = customOptions.hasOwnProperty(key)
111
+ ? customOptions[key]
112
+ : value;
92
113
  });
93
114
 
94
- this.hadInitialPlaceholder = Boolean(input.getAttribute('placeholder'));
115
+ this.hadInitialPlaceholder = Boolean(input.getAttribute("placeholder"));
95
116
  }
96
117
 
97
118
  _init() {
98
119
  // if in nationalMode, do not insert dial codes
99
- if (this.options.nationalMode) this.options.autoInsertDialCode = false;
120
+ if (this.options.nationalMode) {
121
+ this.options.autoInsertDialCode = false;
122
+ }
100
123
 
101
124
  // if separateDialCode enabled, do not insert dial codes
102
- if (this.options.separateDialCode) this.options.autoInsertDialCode = false;
125
+ if (this.options.separateDialCode) {
126
+ this.options.autoInsertDialCode = false;
127
+ }
128
+
129
+ // force showFlags=true if there's a dropdown and we're not displaying the dial code,
130
+ // as otherwise you just have a down arrow on it's own which doesn't make sense
131
+ const forceShowFlags =
132
+ this.options.allowDropdown && !this.options.separateDialCode;
133
+ if (!this.options.showFlags && forceShowFlags) {
134
+ this.options.showFlags = true;
135
+ }
103
136
 
104
137
  // we cannot just test screen size as some smartphones/website meta tags will report desktop
105
138
  // resolutions
106
139
  // Note: for some reason jasmine breaks if you put this in the main Plugin function with the
107
140
  // rest of these declarations
108
141
  // Note: to target Android Mobiles (and not Tablets), we must find 'Android' and 'Mobile'
109
- this.isMobile = /Android.+Mobile|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
142
+ this.isMobile =
143
+ /Android.+Mobile|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
144
+ navigator.userAgent
145
+ );
110
146
 
111
147
  if (this.isMobile) {
112
148
  // trigger the mobile dropdown css
113
- document.body.classList.add('iti-mobile');
149
+ document.body.classList.add("iti-mobile");
114
150
 
115
151
  // on mobile, we want a full screen dropdown, so we must append it to the body
116
- if (!this.options.dropdownContainer) this.options.dropdownContainer = document.body;
152
+ if (!this.options.dropdownContainer) {
153
+ this.options.dropdownContainer = document.body;
154
+ }
117
155
  }
118
156
 
119
157
  // these promises get resolved when their individual requests complete
120
158
  // this way the dev can do something like iti.promise.then(...) to know when all requests are
121
159
  // complete
122
- if (typeof Promise !== 'undefined') {
160
+ if (typeof Promise !== "undefined") {
123
161
  const autoCountryPromise = new Promise((resolve, reject) => {
124
162
  this.resolveAutoCountryPromise = resolve;
125
163
  this.rejectAutoCountryPromise = reject;
@@ -155,12 +193,10 @@ class Iti {
155
193
  this._initRequests();
156
194
  }
157
195
 
158
-
159
196
  /********************
160
197
  * PRIVATE METHODS
161
198
  ********************/
162
199
 
163
-
164
200
  // prepare all of the country data, including onlyCountries, excludeCountries and
165
201
  // preferredCountries options
166
202
  _processCountryData() {
@@ -174,7 +210,9 @@ class Iti {
174
210
  this._processPreferredCountries();
175
211
 
176
212
  // translate countries according to localizedCountries option
177
- if (this.options.localizedCountries) this._translateCountriesByLocale();
213
+ if (this.options.localizedCountries) {
214
+ this._translateCountriesByLocale();
215
+ }
178
216
 
179
217
  // sort countries by name
180
218
  if (this.options.onlyCountries.length || this.options.localizedCountries) {
@@ -182,7 +220,6 @@ class Iti {
182
220
  }
183
221
  }
184
222
 
185
-
186
223
  // add a country code to this.countryCodes
187
224
  _addCountryCode(iso2, countryCode, priority) {
188
225
  if (countryCode.length > this.countryCodeMaxLen) {
@@ -193,29 +230,31 @@ class Iti {
193
230
  }
194
231
  // bail if we already have this country for this countryCode
195
232
  for (let i = 0; i < this.countryCodes[countryCode].length; i++) {
196
- if (this.countryCodes[countryCode][i] === iso2) return;
233
+ if (this.countryCodes[countryCode][i] === iso2) {
234
+ return;
235
+ }
197
236
  }
198
237
  // check for undefined as 0 is falsy
199
- const index = (priority !== undefined) ? priority : this.countryCodes[countryCode].length;
238
+ const index =
239
+ priority !== undefined ? priority : this.countryCodes[countryCode].length;
200
240
  this.countryCodes[countryCode][index] = iso2;
201
241
  }
202
242
 
203
-
204
243
  // process onlyCountries or excludeCountries array if present
205
244
  _processAllCountries() {
206
245
  if (this.options.onlyCountries.length) {
207
- const lowerCaseOnlyCountries = this.options.onlyCountries.map(
208
- country => country.toLowerCase()
246
+ const lowerCaseOnlyCountries = this.options.onlyCountries.map((country) =>
247
+ country.toLowerCase()
209
248
  );
210
249
  this.countries = allCountries.filter(
211
- country => lowerCaseOnlyCountries.indexOf(country.iso2) > -1
250
+ (country) => lowerCaseOnlyCountries.indexOf(country.iso2) > -1
212
251
  );
213
252
  } else if (this.options.excludeCountries.length) {
214
253
  const lowerCaseExcludeCountries = this.options.excludeCountries.map(
215
- country => country.toLowerCase()
254
+ (country) => country.toLowerCase()
216
255
  );
217
256
  this.countries = allCountries.filter(
218
- country => lowerCaseExcludeCountries.indexOf(country.iso2) === -1
257
+ (country) => lowerCaseExcludeCountries.indexOf(country.iso2) === -1
219
258
  );
220
259
  } else {
221
260
  this.countries = allCountries;
@@ -234,12 +273,15 @@ class Iti {
234
273
 
235
274
  // sort by country name
236
275
  _countryNameSort(a, b) {
237
- if (a.name < b.name) return -1;
238
- if (a.name > b.name) return 1;
276
+ if (a.name < b.name) {
277
+ return -1;
278
+ }
279
+ if (a.name > b.name) {
280
+ return 1;
281
+ }
239
282
  return 0;
240
283
  }
241
284
 
242
-
243
285
  // process the countryCodes map
244
286
  _processCountryCodes() {
245
287
  this.countryCodeMaxLen = 0;
@@ -251,7 +293,9 @@ class Iti {
251
293
  // first: add dial codes
252
294
  for (let i = 0; i < this.countries.length; i++) {
253
295
  const c = this.countries[i];
254
- if (!this.dialCodes[c.dialCode]) this.dialCodes[c.dialCode] = true;
296
+ if (!this.dialCodes[c.dialCode]) {
297
+ this.dialCodes[c.dialCode] = true;
298
+ }
255
299
  this._addCountryCode(c.iso2, c.dialCode, c.priority);
256
300
  }
257
301
 
@@ -281,7 +325,6 @@ class Iti {
281
325
  }
282
326
  }
283
327
 
284
-
285
328
  // process preferred countries - iterate through the preferences, fetching the country data for
286
329
  // each one
287
330
  _processPreferredCountries() {
@@ -289,143 +332,199 @@ class Iti {
289
332
  for (let i = 0; i < this.options.preferredCountries.length; i++) {
290
333
  const countryCode = this.options.preferredCountries[i].toLowerCase();
291
334
  const countryData = this._getCountryData(countryCode, false, true);
292
- if (countryData) this.preferredCountries.push(countryData);
335
+ if (countryData) {
336
+ this.preferredCountries.push(countryData);
337
+ }
293
338
  }
294
339
  }
295
340
 
296
-
297
341
  // create a DOM element
298
342
  _createEl(name, attrs, container) {
299
343
  const el = document.createElement(name);
300
- if (attrs) forEachProp(attrs, (key, value) => el.setAttribute(key, value));
301
- if (container) container.appendChild(el);
344
+ if (attrs) {
345
+ forEachProp(attrs, (key, value) => el.setAttribute(key, value));
346
+ }
347
+ if (container) {
348
+ container.appendChild(el);
349
+ }
302
350
  return el;
303
351
  }
304
352
 
305
-
306
353
  // generate all of the markup for the plugin: the selected flag overlay, and the dropdown
307
354
  _generateMarkup() {
308
355
  // if autocomplete does not exist on the element and its form, then
309
356
  // prevent autocomplete as there's no safe, cross-browser event we can react to, so it can
310
357
  // easily put the plugin in an inconsistent state e.g. the wrong flag selected for the
311
- // autocompleted number, which on submit could mean wrong number is saved (esp in nationalMode)
312
- if (!this.telInput.hasAttribute('autocomplete') && !(this.telInput.form && this.telInput.form.hasAttribute('autocomplete'))) {
313
- this.telInput.setAttribute('autocomplete', 'off');
358
+ // autocompleted number, which on submit could mean wrong number is saved
359
+ if (
360
+ !this.telInput.hasAttribute("autocomplete") &&
361
+ !(this.telInput.form && this.telInput.form.hasAttribute("autocomplete"))
362
+ ) {
363
+ this.telInput.setAttribute("autocomplete", "off");
314
364
  }
315
365
 
366
+ const {
367
+ allowDropdown,
368
+ separateDialCode,
369
+ showFlags,
370
+ customContainer,
371
+ hiddenInput,
372
+ dropdownContainer
373
+ } = this.options;
374
+
316
375
  // containers (mostly for positioning)
317
- let parentClass = 'iti';
318
- if (this.options.allowDropdown) parentClass += ' iti--allow-dropdown';
319
- if (this.options.separateDialCode) parentClass += ' iti--separate-dial-code';
320
- if (this.options.customContainer) {
321
- parentClass += ' ';
322
- parentClass += this.options.customContainer;
376
+ let parentClass = "iti";
377
+ if (allowDropdown) {
378
+ parentClass += " iti--allow-dropdown";
379
+ }
380
+ if (separateDialCode) {
381
+ parentClass += " iti--separate-dial-code";
382
+ }
383
+ if (showFlags) {
384
+ parentClass += " iti--show-flags";
385
+ }
386
+ if (customContainer) {
387
+ parentClass += ` ${customContainer}`;
323
388
  }
324
389
 
325
- const wrapper = this._createEl('div', { class: parentClass });
390
+ const wrapper = this._createEl("div", { class: parentClass });
326
391
  this.telInput.parentNode.insertBefore(wrapper, this.telInput);
327
- this.flagsContainer = this._createEl('div', { class: 'iti__flag-container' }, wrapper);
392
+ // only hide the flagsContainer if allowDropdown, showFlags and separateDialCode are all false
393
+ const showFlagsContainer = allowDropdown || showFlags || separateDialCode;
394
+ if (showFlagsContainer) {
395
+ this.flagsContainer = this._createEl(
396
+ "div",
397
+ { class: "iti__flag-container" },
398
+ wrapper
399
+ );
400
+ }
328
401
  wrapper.appendChild(this.telInput);
329
402
 
330
403
  // selected flag (displayed to left of input)
331
404
  // using Aria tags for "Select-Only Combobox Example"
332
405
  // https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/
333
- this.selectedFlag = this._createEl('div', {
334
- class: 'iti__selected-flag',
335
- ...(this.options.allowDropdown && {
336
- role: 'combobox',
337
- 'aria-haspopup': 'listbox',
338
- 'aria-controls': `iti-${this.id}__country-listbox`,
339
- 'aria-owns': `iti-${this.id}__country-listbox`,
340
- 'aria-expanded': 'false',
341
- 'aria-label': 'Telephone country code',
342
- }),
343
- }, this.flagsContainer);
344
- this.selectedFlagInner = this._createEl('div', { class: 'iti__flag' }, this.selectedFlag);
345
-
346
- if (this.telInput.disabled) {
347
- this.selectedFlag.setAttribute('aria-disabled', 'true');
406
+ if (showFlagsContainer) {
407
+ this.selectedFlag = this._createEl(
408
+ "div",
409
+ {
410
+ class: "iti__selected-flag",
411
+ ...(allowDropdown && {
412
+ role: "combobox",
413
+ "aria-haspopup": "listbox",
414
+ "aria-controls": `iti-${this.id}__country-listbox`,
415
+ "aria-owns": `iti-${this.id}__country-listbox`,
416
+ "aria-expanded": "false",
417
+ "aria-label": "Telephone country code"
418
+ })
419
+ },
420
+ this.flagsContainer
421
+ );
422
+ }
423
+ if (showFlags) {
424
+ this.selectedFlagInner = this._createEl(
425
+ "div",
426
+ { class: "iti__flag" },
427
+ this.selectedFlag
428
+ );
348
429
  }
349
430
 
350
- if (this.options.separateDialCode) {
351
- this.selectedDialCode = this._createEl('div', { class: 'iti__selected-dial-code' }, this.selectedFlag);
431
+ if (this.selectedFlag && this.telInput.disabled) {
432
+ this.selectedFlag.setAttribute("aria-disabled", "true");
352
433
  }
353
434
 
354
- if (this.options.allowDropdown) {
435
+ if (separateDialCode) {
436
+ this.selectedDialCode = this._createEl(
437
+ "div",
438
+ { class: "iti__selected-dial-code" },
439
+ this.selectedFlag
440
+ );
441
+ }
442
+
443
+ if (allowDropdown) {
355
444
  if (!this.telInput.disabled) {
356
445
  // make element focusable and tab navigable
357
- this.selectedFlag.setAttribute('tabindex', '0');
446
+ this.selectedFlag.setAttribute("tabindex", "0");
358
447
  }
359
448
 
360
- this.dropdownArrow = this._createEl('div', { class: 'iti__arrow' }, this.selectedFlag);
449
+ this.dropdownArrow = this._createEl(
450
+ "div",
451
+ { class: "iti__arrow" },
452
+ this.selectedFlag
453
+ );
361
454
 
362
455
  // country dropdown: preferred countries, then divider, then all countries
363
- this.countryList = this._createEl('ul', {
364
- class: 'iti__country-list iti__hide',
456
+ this.countryList = this._createEl("ul", {
457
+ class: "iti__country-list iti__hide",
365
458
  id: `iti-${this.id}__country-listbox`,
366
- role: 'listbox',
367
- 'aria-label': 'List of countries',
459
+ role: "listbox",
460
+ "aria-label": "List of countries"
368
461
  });
369
462
  if (this.preferredCountries.length) {
370
- this._appendListItems(this.preferredCountries, 'iti__preferred', true);
371
- this._createEl('li', {
372
- class: 'iti__divider',
373
- role: 'separator',
374
- 'aria-disabled': 'true',
375
- }, this.countryList);
463
+ this._appendListItems(this.preferredCountries, "iti__preferred", true);
464
+ this._createEl(
465
+ "li",
466
+ {
467
+ class: "iti__divider",
468
+ role: "separator",
469
+ "aria-disabled": "true"
470
+ },
471
+ this.countryList
472
+ );
376
473
  }
377
- this._appendListItems(this.countries, 'iti__standard');
474
+ this._appendListItems(this.countries, "iti__standard");
378
475
 
379
476
  // create dropdownContainer markup
380
- if (this.options.dropdownContainer) {
381
- this.dropdown = this._createEl('div', { class: 'iti iti--container' });
477
+ if (dropdownContainer) {
478
+ this.dropdown = this._createEl("div", { class: "iti iti--container" });
382
479
  this.dropdown.appendChild(this.countryList);
383
480
  } else {
384
481
  this.flagsContainer.appendChild(this.countryList);
385
482
  }
386
483
  }
387
484
 
388
- if (this.options.hiddenInput) {
389
- let hiddenInputName = this.options.hiddenInput;
390
- const name = this.telInput.getAttribute('name');
485
+ if (hiddenInput) {
486
+ let hiddenInputName = hiddenInput;
487
+ const name = this.telInput.getAttribute("name");
391
488
  if (name) {
392
- const i = name.lastIndexOf('[');
489
+ const i = name.lastIndexOf("[");
393
490
  // if input name contains square brackets, then give the hidden input the same name,
394
491
  // replacing the contents of the last set of brackets with the given hiddenInput name
395
- if (i !== -1) hiddenInputName = `${name.substr(0, i)}[${hiddenInputName}]`;
492
+ if (i !== -1) {
493
+ hiddenInputName = `${name.substr(0, i)}[${hiddenInputName}]`;
494
+ }
396
495
  }
397
- this.hiddenInput = this._createEl('input', {
398
- type: 'hidden',
399
- name: hiddenInputName,
496
+ this.hiddenInput = this._createEl("input", {
497
+ type: "hidden",
498
+ name: hiddenInputName
400
499
  });
401
500
  wrapper.appendChild(this.hiddenInput);
402
501
  }
403
502
  }
404
503
 
405
-
406
504
  // add a country <li> to the countryList <ul> container
407
505
  _appendListItems(countries, className, preferred) {
408
506
  // we create so many DOM elements, it is faster to build a temp string
409
507
  // and then add everything to the DOM in one go at the end
410
- let tmp = '';
508
+ let tmp = "";
411
509
  // for each country
412
510
  for (let i = 0; i < countries.length; i++) {
413
511
  const c = countries[i];
414
- const idSuffix = preferred ? '-preferred' : '';
512
+ const idSuffix = preferred ? "-preferred" : "";
415
513
  // open the list item
416
514
  tmp += `<li class='iti__country ${className}' tabIndex='-1' id='iti-${this.id}__item-${c.iso2}${idSuffix}' role='option' data-dial-code='${c.dialCode}' data-country-code='${c.iso2}' aria-selected='false'>`;
417
515
  // add the flag
418
- tmp += `<div class='iti__flag-box'><div class='iti__flag iti__${c.iso2}'></div></div>`;
516
+ if (this.options.showFlags) {
517
+ tmp += `<div class='iti__flag-box'><div class='iti__flag iti__${c.iso2}'></div></div>`;
518
+ }
419
519
  // and the country name and dial code
420
520
  tmp += `<span class='iti__country-name'>${c.name}</span>`;
421
521
  tmp += `<span class='iti__dial-code'>+${c.dialCode}</span>`;
422
522
  // close the list item
423
- tmp += '</li>';
523
+ tmp += "</li>";
424
524
  }
425
- this.countryList.insertAdjacentHTML('beforeend', tmp);
525
+ this.countryList.insertAdjacentHTML("beforeend", tmp);
426
526
  }
427
527
 
428
-
429
528
  // set the initial state of the input value and the selected flag by:
430
529
  // 1. extracting a dial code from the given number
431
530
  // 2. using explicit initialCountry
@@ -435,32 +534,33 @@ class Iti {
435
534
  // fix firefox bug: when first load page (with input with value set to number with intl dial
436
535
  // code) and initialising plugin removes the dial code from the input, then refresh page,
437
536
  // and we try to init plugin again but this time on number without dial code so get grey flag
438
- const attributeValue = this.telInput.getAttribute('value');
537
+ const attributeValue = this.telInput.getAttribute("value");
439
538
  const inputValue = this.telInput.value;
440
- const useAttribute = (attributeValue && attributeValue.charAt(0) === '+' && (!inputValue || inputValue.charAt(0) !== '+'));
539
+ const useAttribute =
540
+ attributeValue &&
541
+ attributeValue.charAt(0) === "+" &&
542
+ (!inputValue || inputValue.charAt(0) !== "+");
441
543
  const val = useAttribute ? attributeValue : inputValue;
442
544
  const dialCode = this._getDialCode(val);
443
545
  const isRegionlessNanp = this._isRegionlessNanp(val);
444
- const {
445
- initialCountry,
446
- autoInsertDialCode,
447
- } = this.options;
546
+ const { initialCountry, autoInsertDialCode } = this.options;
448
547
 
449
548
  // if we already have a dial code, and it's not a regionlessNanp, we can go ahead and set the
450
549
  // flag, else fall back to the default country
451
550
  if (dialCode && !isRegionlessNanp) {
452
551
  this._updateFlagFromNumber(val);
453
- } else if (initialCountry !== 'auto') {
552
+ } else if (initialCountry !== "auto") {
454
553
  // see if we should select a flag
455
554
  if (initialCountry) {
456
555
  this._setFlag(initialCountry.toLowerCase());
457
556
  } else {
458
557
  if (dialCode && isRegionlessNanp) {
459
558
  // has intl dial code, is regionless nanp, and no initialCountry, so default to US
460
- this._setFlag('us');
559
+ this._setFlag("us");
461
560
  } else {
462
561
  // no dial code and no initialCountry, so default to first in list
463
- this.defaultCountry = (this.preferredCountries.length) ? this.preferredCountries[0].iso2
562
+ this.defaultCountry = this.preferredCountries.length
563
+ ? this.preferredCountries[0].iso2
464
564
  : this.countries[0].iso2;
465
565
  if (!val) {
466
566
  this._setFlag(this.defaultCountry);
@@ -476,36 +576,47 @@ class Iti {
476
576
  // NOTE: if initialCountry is set to auto, that will be handled separately
477
577
 
478
578
  // format - note this wont be run after _updateDialCode as that's only called if no val
479
- if (val) this._updateValFromNumber(val);
579
+ if (val) {
580
+ this._updateValFromNumber(val);
581
+ }
480
582
  }
481
583
 
482
-
483
584
  // initialise the main event listeners: input keyup, and click selected flag
484
585
  _initListeners() {
485
586
  this._initKeyListeners();
486
- if (this.options.autoInsertDialCode) this._initBlurListeners();
487
- if (this.options.allowDropdown) this._initDropdownListeners();
488
- if (this.hiddenInput) this._initHiddenInputListener();
587
+ if (this.options.autoInsertDialCode) {
588
+ this._initBlurListeners();
589
+ }
590
+ if (this.options.allowDropdown) {
591
+ this._initDropdownListeners();
592
+ }
593
+ if (this.hiddenInput) {
594
+ this._initHiddenInputListener();
595
+ }
489
596
  }
490
597
 
491
-
492
598
  // update hidden input on form submit
493
599
  _initHiddenInputListener() {
494
600
  this._handleHiddenInputSubmit = () => {
495
601
  this.hiddenInput.value = this.getNumber();
496
602
  };
497
- if (this.telInput.form) this.telInput.form.addEventListener('submit', this._handleHiddenInputSubmit);
603
+ if (this.telInput.form) {
604
+ this.telInput.form.addEventListener(
605
+ "submit",
606
+ this._handleHiddenInputSubmit
607
+ );
608
+ }
498
609
  }
499
610
 
500
-
501
611
  // iterate through parent nodes to find the closest label ancestor, if it exists
502
612
  _getClosestLabel() {
503
613
  let el = this.telInput;
504
- while (el && el.tagName !== 'LABEL') el = el.parentNode;
614
+ while (el && el.tagName !== "LABEL") {
615
+ el = el.parentNode;
616
+ }
505
617
  return el;
506
618
  }
507
619
 
508
-
509
620
  // initialise the dropdown listeners
510
621
  _initDropdownListeners() {
511
622
  // hack for input nested inside label (which is valid markup): clicking the selected-flag to
@@ -513,28 +624,41 @@ class Iti {
513
624
  // close it again
514
625
  this._handleLabelClick = (e) => {
515
626
  // if the dropdown is closed, then focus the input, else ignore the click
516
- if (this.countryList.classList.contains('iti__hide')) this.telInput.focus();
517
- else e.preventDefault();
627
+ if (this.countryList.classList.contains("iti__hide")) {
628
+ this.telInput.focus();
629
+ } else {
630
+ e.preventDefault();
631
+ }
518
632
  };
519
633
  const label = this._getClosestLabel();
520
- if (label) label.addEventListener('click', this._handleLabelClick);
634
+ if (label) {
635
+ label.addEventListener("click", this._handleLabelClick);
636
+ }
521
637
 
522
638
  // toggle country dropdown on click
523
639
  this._handleClickSelectedFlag = () => {
524
640
  // only intercept this event if we're opening the dropdown
525
641
  // else let it bubble up to the top ("click-off-to-close" listener)
526
642
  // we cannot just stopPropagation as it may be needed to close another instance
527
- if (this.countryList.classList.contains('iti__hide') && !this.telInput.disabled && !this.telInput.readOnly) {
643
+ if (
644
+ this.countryList.classList.contains("iti__hide") &&
645
+ !this.telInput.disabled &&
646
+ !this.telInput.readOnly
647
+ ) {
528
648
  this._showDropdown();
529
649
  }
530
650
  };
531
- this.selectedFlag.addEventListener('click', this._handleClickSelectedFlag);
651
+ this.selectedFlag.addEventListener("click", this._handleClickSelectedFlag);
532
652
 
533
653
  // open dropdown list if currently focused
534
654
  this._handleFlagsContainerKeydown = (e) => {
535
- const isDropdownHidden = this.countryList.classList.contains('iti__hide');
655
+ const isDropdownHidden = this.countryList.classList.contains("iti__hide");
536
656
 
537
- if (isDropdownHidden && ['ArrowUp', 'Up', 'ArrowDown', 'Down', ' ', 'Enter'].indexOf(e.key) !== -1) {
657
+ if (
658
+ isDropdownHidden &&
659
+ ["ArrowUp", "Up", "ArrowDown", "Down", " ", "Enter"].indexOf(e.key) !==
660
+ -1
661
+ ) {
538
662
  // prevent form from being submitted if "ENTER" was pressed
539
663
  e.preventDefault();
540
664
  // prevent event from being handled again by document
@@ -543,12 +667,16 @@ class Iti {
543
667
  }
544
668
 
545
669
  // allow navigation from dropdown to input on TAB
546
- if (e.key === 'Tab') this._closeDropdown();
670
+ if (e.key === "Tab") {
671
+ this._closeDropdown();
672
+ }
547
673
  };
548
- this.flagsContainer.addEventListener('keydown', this._handleFlagsContainerKeydown);
674
+ this.flagsContainer.addEventListener(
675
+ "keydown",
676
+ this._handleFlagsContainerKeydown
677
+ );
549
678
  }
550
679
 
551
-
552
680
  // init many requests: utils script / geo ip lookup
553
681
  _initRequests() {
554
682
  // if the user has specified the path to the utils script, fetch it on window.load, else resolve
@@ -558,17 +686,21 @@ class Iti {
558
686
  window.intlTelInputGlobals.loadUtils(this.options.utilsScript);
559
687
  } else {
560
688
  // wait until the load event so we don't block any other requests e.g. the flags image
561
- window.addEventListener('load', () => {
689
+ window.addEventListener("load", () => {
562
690
  window.intlTelInputGlobals.loadUtils(this.options.utilsScript);
563
691
  });
564
692
  }
565
- } else this.resolveUtilsScriptPromise();
693
+ } else {
694
+ this.resolveUtilsScriptPromise();
695
+ }
566
696
 
567
- if (this.options.initialCountry === 'auto') this._loadAutoCountry();
568
- else this.resolveAutoCountryPromise();
697
+ if (this.options.initialCountry === "auto") {
698
+ this._loadAutoCountry();
699
+ } else {
700
+ this.resolveAutoCountryPromise();
701
+ }
569
702
  }
570
703
 
571
-
572
704
  // perform the geo ip lookup
573
705
  _loadAutoCountry() {
574
706
  // 3 options:
@@ -581,22 +713,24 @@ class Iti {
581
713
  // don't do this twice!
582
714
  window.intlTelInputGlobals.startedLoadingAutoCountry = true;
583
715
 
584
- if (typeof this.options.geoIpLookup === 'function') {
585
- this.options.geoIpLookup((countryCode) => {
586
- window.intlTelInputGlobals.autoCountry = countryCode.toLowerCase();
587
- // tell all instances the auto country is ready
588
- // TODO: this should just be the current instances
589
- // UPDATE: use setTimeout in case their geoIpLookup function calls this callback straight
590
- // away (e.g. if they have already done the geo ip lookup somewhere else). Using
591
- // setTimeout means that the current thread of execution will finish before executing
592
- // this, which allows the plugin to finish initialising.
593
- setTimeout(() => forEachInstance('handleAutoCountry'));
594
- }, () => forEachInstance('rejectAutoCountryPromise'));
716
+ if (typeof this.options.geoIpLookup === "function") {
717
+ this.options.geoIpLookup(
718
+ (countryCode) => {
719
+ window.intlTelInputGlobals.autoCountry = countryCode.toLowerCase();
720
+ // tell all instances the auto country is ready
721
+ // TODO: this should just be the current instances
722
+ // UPDATE: use setTimeout in case their geoIpLookup function calls this callback straight
723
+ // away (e.g. if they have already done the geo ip lookup somewhere else). Using
724
+ // setTimeout means that the current thread of execution will finish before executing
725
+ // this, which allows the plugin to finish initialising.
726
+ setTimeout(() => forEachInstance("handleAutoCountry"));
727
+ },
728
+ () => forEachInstance("rejectAutoCountryPromise")
729
+ );
595
730
  }
596
731
  }
597
732
  }
598
733
 
599
-
600
734
  // initialize any key listeners
601
735
  _initKeyListeners() {
602
736
  // update flag on keyup
@@ -605,71 +739,70 @@ class Iti {
605
739
  this._triggerCountryChange();
606
740
  }
607
741
  };
608
- this.telInput.addEventListener('keyup', this._handleKeyupEvent);
742
+ this.telInput.addEventListener("keyup", this._handleKeyupEvent);
609
743
 
610
744
  // update flag on cut/paste events (now supported in all major browsers)
611
745
  this._handleClipboardEvent = () => {
612
746
  // hack because "paste" event is fired before input is updated
613
747
  setTimeout(this._handleKeyupEvent);
614
748
  };
615
- this.telInput.addEventListener('cut', this._handleClipboardEvent);
616
- this.telInput.addEventListener('paste', this._handleClipboardEvent);
749
+ this.telInput.addEventListener("cut", this._handleClipboardEvent);
750
+ this.telInput.addEventListener("paste", this._handleClipboardEvent);
617
751
  }
618
752
 
619
-
620
753
  // adhere to the input's maxlength attr
621
754
  _cap(number) {
622
- const max = this.telInput.getAttribute('maxlength');
623
- return (max && number.length > max) ? number.substr(0, max) : number;
755
+ const max = this.telInput.getAttribute("maxlength");
756
+ return max && number.length > max ? number.substr(0, max) : number;
624
757
  }
625
758
 
626
-
627
759
  // listen for blur/submit (for autoInsertDialCode feature)
628
760
  _initBlurListeners() {
629
761
  // on blur or form submit: if just a dial code then remove it
630
762
  this._handleSubmitOrBlurEvent = () => {
631
763
  this._removeEmptyDialCode();
632
764
  };
633
- if (this.telInput.form) this.telInput.form.addEventListener('submit', this._handleSubmitOrBlurEvent);
634
- this.telInput.addEventListener('blur', this._handleSubmitOrBlurEvent);
765
+ if (this.telInput.form) {
766
+ this.telInput.form.addEventListener(
767
+ "submit",
768
+ this._handleSubmitOrBlurEvent
769
+ );
770
+ }
771
+ this.telInput.addEventListener("blur", this._handleSubmitOrBlurEvent);
635
772
 
636
773
  // made the decision not to trigger blur() now, because would only do anything in the case
637
774
  // where they manually set the initial value to just a dial code, in which case they probably
638
775
  // want it to be displayed.
639
776
  }
640
777
 
641
-
642
778
  // clear the input if it just contains a dial code
643
779
  _removeEmptyDialCode() {
644
- if (this.telInput.value.charAt(0) === '+') {
780
+ if (this.telInput.value.charAt(0) === "+") {
645
781
  const numeric = this._getNumeric(this.telInput.value);
646
782
  // if just a plus, or if just a dial code
647
783
  if (!numeric || this.selectedCountryData.dialCode === numeric) {
648
- this.telInput.value = '';
784
+ this.telInput.value = "";
649
785
  }
650
786
  }
651
787
  }
652
788
 
653
-
654
789
  // extract the numeric digits from the given string
655
790
  _getNumeric(s) {
656
- return s.replace(/\D/g, '');
791
+ return s.replace(/\D/g, "");
657
792
  }
658
793
 
659
-
660
794
  // trigger a custom event on the input
661
795
  _trigger(name) {
662
796
  // have to use old school document.createEvent as IE11 doesn't support `new Event()` syntax
663
- const e = document.createEvent('Event');
797
+ const e = document.createEvent("Event");
664
798
  e.initEvent(name, true, true); // can bubble, and is cancellable
665
799
  this.telInput.dispatchEvent(e);
666
800
  }
667
801
 
668
-
669
802
  // show the dropdown
670
803
  _showDropdown() {
671
- this.countryList.classList.remove('iti__hide');
672
- this.selectedFlag.setAttribute('aria-expanded', 'true');
804
+ this.countryList.classList.remove("iti__hide");
805
+ this.selectedFlag.setAttribute("aria-expanded", "true");
673
806
 
674
807
  this._setDropdownPosition();
675
808
 
@@ -683,19 +816,20 @@ class Iti {
683
816
  this._bindDropdownListeners();
684
817
 
685
818
  // update the arrow
686
- this.dropdownArrow.classList.add('iti__arrow--up');
819
+ this.dropdownArrow.classList.add("iti__arrow--up");
687
820
 
688
- this._trigger('open:countrydropdown');
821
+ this._trigger("open:countrydropdown");
689
822
  }
690
823
 
691
-
692
824
  // make sure the el has the className or not, depending on the value of shouldHaveClass
693
825
  _toggleClass(el, className, shouldHaveClass) {
694
- if (shouldHaveClass && !el.classList.contains(className)) el.classList.add(className);
695
- else if (!shouldHaveClass && el.classList.contains(className)) el.classList.remove(className);
826
+ if (shouldHaveClass && !el.classList.contains(className)) {
827
+ el.classList.add(className);
828
+ } else if (!shouldHaveClass && el.classList.contains(className)) {
829
+ el.classList.remove(className);
830
+ }
696
831
  }
697
832
 
698
-
699
833
  // decide where to position dropdown (depends on position within viewport, and scroll)
700
834
  _setDropdownPosition() {
701
835
  if (this.options.dropdownContainer) {
@@ -705,23 +839,32 @@ class Iti {
705
839
  if (!this.isMobile) {
706
840
  const pos = this.telInput.getBoundingClientRect();
707
841
  // windowTop from https://stackoverflow.com/a/14384091/217866
708
- const windowTop = window.pageYOffset || document.documentElement.scrollTop;
842
+ const windowTop =
843
+ window.pageYOffset || document.documentElement.scrollTop;
709
844
  const inputTop = pos.top + windowTop;
710
845
  const dropdownHeight = this.countryList.offsetHeight;
711
846
  // dropdownFitsBelow = (dropdownBottom < windowBottom)
712
- const dropdownFitsBelow = (inputTop + this.telInput.offsetHeight + dropdownHeight
713
- < (windowTop + window.innerHeight));
714
- const dropdownFitsAbove = (inputTop - dropdownHeight > windowTop);
847
+ const dropdownFitsBelow =
848
+ inputTop + this.telInput.offsetHeight + dropdownHeight <
849
+ windowTop + window.innerHeight;
850
+ const dropdownFitsAbove = inputTop - dropdownHeight > windowTop;
715
851
 
716
852
  // by default, the dropdown will be below the input. If we want to position it above the
717
853
  // input, we add the dropup class.
718
- this._toggleClass(this.countryList, 'iti__country-list--dropup', (!dropdownFitsBelow && dropdownFitsAbove));
854
+ this._toggleClass(
855
+ this.countryList,
856
+ "iti__country-list--dropup",
857
+ !dropdownFitsBelow && dropdownFitsAbove
858
+ );
719
859
 
720
860
  // if dropdownContainer is enabled, calculate postion
721
861
  if (this.options.dropdownContainer) {
722
862
  // by default the dropdown will be directly over the input because it's not in the flow.
723
863
  // If we want to position it below, we need to add some extra top value.
724
- const extraTop = (!dropdownFitsBelow && dropdownFitsAbove) ? 0 : this.telInput.offsetHeight;
864
+ const extraTop =
865
+ !dropdownFitsBelow && dropdownFitsAbove
866
+ ? 0
867
+ : this.telInput.offsetHeight;
725
868
 
726
869
  // calculate placement
727
870
  this.dropdown.style.top = `${inputTop + extraTop}px`;
@@ -729,21 +872,25 @@ class Iti {
729
872
 
730
873
  // close menu on window scroll
731
874
  this._handleWindowScroll = () => this._closeDropdown();
732
- window.addEventListener('scroll', this._handleWindowScroll);
875
+ window.addEventListener("scroll", this._handleWindowScroll);
733
876
  }
734
877
  }
735
878
  }
736
879
 
737
-
738
880
  // iterate through parent nodes to find the closest list item
739
881
  _getClosestListItem(target) {
740
882
  let el = target;
741
- while (el && el !== this.countryList && !el.classList.contains('iti__country')) el = el.parentNode;
883
+ while (
884
+ el &&
885
+ el !== this.countryList &&
886
+ !el.classList.contains("iti__country")
887
+ ) {
888
+ el = el.parentNode;
889
+ }
742
890
  // if we reached the countryList element, then return null
743
- return (el === this.countryList) ? null : el;
891
+ return el === this.countryList ? null : el;
744
892
  }
745
893
 
746
-
747
894
  // we only bind dropdown listeners when the dropdown is open
748
895
  _bindDropdownListeners() {
749
896
  // when mouse over a list item, just highlight that one
@@ -751,32 +898,44 @@ class Iti {
751
898
  this._handleMouseoverCountryList = (e) => {
752
899
  // handle event delegation, as we're listening for this event on the countryList
753
900
  const listItem = this._getClosestListItem(e.target);
754
- if (listItem) this._highlightListItem(listItem, false);
901
+ if (listItem) {
902
+ this._highlightListItem(listItem, false);
903
+ }
755
904
  };
756
- this.countryList.addEventListener('mouseover', this._handleMouseoverCountryList);
905
+ this.countryList.addEventListener(
906
+ "mouseover",
907
+ this._handleMouseoverCountryList
908
+ );
757
909
 
758
910
  // listen for country selection
759
911
  this._handleClickCountryList = (e) => {
760
912
  const listItem = this._getClosestListItem(e.target);
761
- if (listItem) this._selectListItem(listItem);
913
+ if (listItem) {
914
+ this._selectListItem(listItem);
915
+ }
762
916
  };
763
- this.countryList.addEventListener('click', this._handleClickCountryList);
917
+ this.countryList.addEventListener("click", this._handleClickCountryList);
764
918
 
765
919
  // click off to close
766
920
  // (except when this initial opening click is bubbling up)
767
921
  // we cannot just stopPropagation as it may be needed to close another instance
768
922
  let isOpening = true;
769
923
  this._handleClickOffToClose = () => {
770
- if (!isOpening) this._closeDropdown();
924
+ if (!isOpening) {
925
+ this._closeDropdown();
926
+ }
771
927
  isOpening = false;
772
928
  };
773
- document.documentElement.addEventListener('click', this._handleClickOffToClose);
929
+ document.documentElement.addEventListener(
930
+ "click",
931
+ this._handleClickOffToClose
932
+ );
774
933
 
775
934
  // listen for up/down scrolling, enter to select, or letters to jump to country name.
776
935
  // use keydown as keypress doesn't fire for non-char keys and we want to catch if they
777
936
  // just hit down and hold it to scroll down (no keyup event).
778
937
  // listen on the document because that's where key events are triggered if no input has focus
779
- let query = '';
938
+ let query = "";
780
939
  let queryTimer = null;
781
940
  this._handleKeydownOnDropdown = (e) => {
782
941
  // prevent down key from scrolling the whole page,
@@ -784,52 +943,72 @@ class Iti {
784
943
  e.preventDefault();
785
944
 
786
945
  // up and down to navigate
787
- if (e.key === 'ArrowUp' || e.key === 'Up' || e.key === 'ArrowDown' || e.key === 'Down') this._handleUpDownKey(e.key);
946
+ if (
947
+ e.key === "ArrowUp" ||
948
+ e.key === "Up" ||
949
+ e.key === "ArrowDown" ||
950
+ e.key === "Down"
951
+ ) {
952
+ this._handleUpDownKey(e.key);
953
+ }
788
954
  // enter to select
789
- else if (e.key === 'Enter') this._handleEnterKey();
955
+ else if (e.key === "Enter") {
956
+ this._handleEnterKey();
957
+ }
790
958
  // esc to close
791
- else if (e.key === 'Escape') this._closeDropdown();
959
+ else if (e.key === "Escape") {
960
+ this._closeDropdown();
961
+ }
792
962
  // alpha chars to perform search
793
963
  // regex allows one latin alpha char or space, based on https://stackoverflow.com/a/26900132/217866)
794
964
  else if (/^[a-zA-ZÀ-ÿа-яА-Я ]$/.test(e.key)) {
795
965
  // jump to countries that start with the query string
796
- if (queryTimer) clearTimeout(queryTimer);
966
+ if (queryTimer) {
967
+ clearTimeout(queryTimer);
968
+ }
797
969
  query += e.key.toLowerCase();
798
970
  this._searchForCountry(query);
799
971
  // if the timer hits 1 second, reset the query
800
972
  queryTimer = setTimeout(() => {
801
- query = '';
973
+ query = "";
802
974
  }, 1000);
803
975
  }
804
976
  };
805
- document.addEventListener('keydown', this._handleKeydownOnDropdown);
977
+ document.addEventListener("keydown", this._handleKeydownOnDropdown);
806
978
  }
807
979
 
808
-
809
980
  // highlight the next/prev item in the list (and ensure it is visible)
810
981
  _handleUpDownKey(key) {
811
- let next = (key === 'ArrowUp' || key === 'Up') ? this.highlightedItem.previousElementSibling : this.highlightedItem.nextElementSibling;
982
+ let next =
983
+ key === "ArrowUp" || key === "Up"
984
+ ? this.highlightedItem.previousElementSibling
985
+ : this.highlightedItem.nextElementSibling;
812
986
  if (next) {
813
987
  // skip the divider
814
- if (next.classList.contains('iti__divider')) {
815
- next = (key === 'ArrowUp' || key === 'Up') ? next.previousElementSibling : next.nextElementSibling;
988
+ if (next.classList.contains("iti__divider")) {
989
+ next =
990
+ key === "ArrowUp" || key === "Up"
991
+ ? next.previousElementSibling
992
+ : next.nextElementSibling;
816
993
  }
817
994
  this._highlightListItem(next, true);
818
995
  }
819
996
  }
820
997
 
821
-
822
998
  // select the currently highlighted item
823
999
  _handleEnterKey() {
824
- if (this.highlightedItem) this._selectListItem(this.highlightedItem);
1000
+ if (this.highlightedItem) {
1001
+ this._selectListItem(this.highlightedItem);
1002
+ }
825
1003
  }
826
1004
 
827
-
828
1005
  // find the first list item whose name starts with the query string
829
1006
  _searchForCountry(query) {
830
1007
  for (let i = 0; i < this.countries.length; i++) {
831
1008
  if (this._startsWith(this.countries[i].name, query)) {
832
- const listItem = this.countryList.querySelector(`#iti-${this.id}__item-${this.countries[i].iso2}`);
1009
+ const listItem = this.countryList.querySelector(
1010
+ `#iti-${this.id}__item-${this.countries[i].iso2}`
1011
+ );
833
1012
  // update highlighting and scroll
834
1013
  this._highlightListItem(listItem, false);
835
1014
  this._scrollTo(listItem, true);
@@ -838,47 +1017,60 @@ class Iti {
838
1017
  }
839
1018
  }
840
1019
 
841
-
842
1020
  // check if string a starts with string b
843
1021
  _startsWith(a, b) {
844
- return (a.substr(0, b.length).toLowerCase() === b);
1022
+ return a.substr(0, b.length).toLowerCase() === b;
845
1023
  }
846
1024
 
847
-
848
1025
  // update the input's value to the given val (format first if possible)
849
1026
  // NOTE: this is called from _setInitialState, handleUtils and setNumber
850
1027
  _updateValFromNumber(originalNumber) {
851
1028
  let number = originalNumber;
852
- if (this.options.formatOnDisplay && window.intlTelInputUtils && this.selectedCountryData) {
853
- const useNational = (this.options.nationalMode || (number.charAt(0) !== '+' && !this.options.separateDialCode));
1029
+ if (
1030
+ this.options.formatOnDisplay &&
1031
+ window.intlTelInputUtils &&
1032
+ this.selectedCountryData
1033
+ ) {
1034
+ const useNational =
1035
+ this.options.nationalMode ||
1036
+ (number.charAt(0) !== "+" && !this.options.separateDialCode);
854
1037
  const { NATIONAL, INTERNATIONAL } = intlTelInputUtils.numberFormat;
855
1038
  const format = useNational ? NATIONAL : INTERNATIONAL;
856
- number = intlTelInputUtils.formatNumber(number, this.selectedCountryData.iso2, format);
1039
+ number = intlTelInputUtils.formatNumber(
1040
+ number,
1041
+ this.selectedCountryData.iso2,
1042
+ format
1043
+ );
857
1044
  }
858
1045
 
859
1046
  number = this._beforeSetNumber(number);
860
1047
  this.telInput.value = number;
861
1048
  }
862
1049
 
863
-
864
1050
  // check if need to select a new flag based on the given number
865
1051
  // Note: called from _setInitialState, keyup handler, setNumber
866
1052
  _updateFlagFromNumber(originalNumber) {
867
- // if we're in nationalMode and we already have US/Canada selected, make sure the number starts
1053
+ // if we already have US/Canada selected, make sure the number starts
868
1054
  // with a +1 so _getDialCode will be able to extract the area code
869
1055
  // update: if we dont yet have selectedCountryData, but we're here (trying to update the flag
870
1056
  // from the number), that means we're initialising the plugin with a number that already has a
871
1057
  // dial code, so fine to ignore this bit
872
1058
  let number = originalNumber;
873
1059
  const selectedDialCode = this.selectedCountryData.dialCode;
874
- const isNanp = (selectedDialCode === '1');
875
- if (number && this.options.nationalMode && isNanp && number.charAt(0) !== '+') {
876
- if (number.charAt(0) !== '1') number = `1${number}`;
1060
+ const isNanp = selectedDialCode === "1";
1061
+ if (number && isNanp && number.charAt(0) !== "+") {
1062
+ if (number.charAt(0) !== "1") {
1063
+ number = `1${number}`;
1064
+ }
877
1065
  number = `+${number}`;
878
1066
  }
879
1067
 
880
1068
  // if separateDialCode enabled, then consider the selected dial code to be part of the number
881
- if (this.options.separateDialCode && selectedDialCode && number.charAt(0) !== '+') {
1069
+ if (
1070
+ this.options.separateDialCode &&
1071
+ selectedDialCode &&
1072
+ number.charAt(0) !== "+"
1073
+ ) {
882
1074
  number = `+${selectedDialCode}${number}`;
883
1075
  }
884
1076
 
@@ -892,9 +1084,11 @@ class Iti {
892
1084
  // longer than the matched dial code because in this case we need to make sure that if
893
1085
  // there are multiple country matches, that the first one is selected (note: we could
894
1086
  // just check that here, but it requires the same loop that we already have later)
895
- const alreadySelected = (countryCodes.indexOf(this.selectedCountryData.iso2) !== -1)
896
- && (numeric.length <= dialCode.length - 1);
897
- const isRegionlessNanpNumber = (selectedDialCode === '1' && this._isRegionlessNanp(numeric));
1087
+ const alreadySelected =
1088
+ countryCodes.indexOf(this.selectedCountryData.iso2) !== -1 &&
1089
+ numeric.length <= dialCode.length - 1;
1090
+ const isRegionlessNanpNumber =
1091
+ selectedDialCode === "1" && this._isRegionlessNanp(numeric);
898
1092
 
899
1093
  // only update the flag if:
900
1094
  // A) NOT (we currently have a NANP flag selected, and the number is a regionlessNanp)
@@ -910,12 +1104,12 @@ class Iti {
910
1104
  }
911
1105
  }
912
1106
  }
913
- } else if (number.charAt(0) === '+' && numeric.length) {
1107
+ } else if (number.charAt(0) === "+" && numeric.length) {
914
1108
  // invalid dial code, so empty
915
1109
  // Note: use getNumeric here because the number has not been formatted yet, so could contain
916
1110
  // bad chars
917
- countryCode = '';
918
- } else if (!number || number === '+') {
1111
+ countryCode = "";
1112
+ } else if (!number || number === "+") {
919
1113
  // empty, or just a plus, so default
920
1114
  countryCode = this.defaultCountry;
921
1115
  }
@@ -926,35 +1120,41 @@ class Iti {
926
1120
  return false;
927
1121
  }
928
1122
 
929
-
930
1123
  // check if the given number is a regionless NANP number (expects the number to contain an
931
1124
  // international dial code)
932
1125
  _isRegionlessNanp(number) {
933
1126
  const numeric = this._getNumeric(number);
934
- if (numeric.charAt(0) === '1') {
1127
+ if (numeric.charAt(0) === "1") {
935
1128
  const areaCode = numeric.substr(1, 3);
936
- return (regionlessNanpNumbers.indexOf(areaCode) !== -1);
1129
+ return regionlessNanpNumbers.indexOf(areaCode) !== -1;
937
1130
  }
938
1131
  return false;
939
1132
  }
940
1133
 
941
-
942
1134
  // remove highlighting from other list items and highlight the given item
943
1135
  _highlightListItem(listItem, shouldFocus) {
944
1136
  const prevItem = this.highlightedItem;
945
- if (prevItem) prevItem.classList.remove('iti__highlight');
1137
+ if (prevItem) {
1138
+ prevItem.classList.remove("iti__highlight");
1139
+ }
946
1140
  this.highlightedItem = listItem;
947
- this.highlightedItem.classList.add('iti__highlight');
948
- this.selectedFlag.setAttribute('aria-activedescendant', listItem.getAttribute('id'));
949
-
950
- if (shouldFocus) this.highlightedItem.focus();
1141
+ this.highlightedItem.classList.add("iti__highlight");
1142
+ this.selectedFlag.setAttribute(
1143
+ "aria-activedescendant",
1144
+ listItem.getAttribute("id")
1145
+ );
1146
+
1147
+ if (shouldFocus) {
1148
+ this.highlightedItem.focus();
1149
+ }
951
1150
  }
952
1151
 
953
-
954
1152
  // find the country data for the given country code
955
1153
  // the ignoreOnlyCountriesOption is only used during init() while parsing the onlyCountries array
956
1154
  _getCountryData(countryCode, ignoreOnlyCountriesOption, allowFail) {
957
- const countryList = (ignoreOnlyCountriesOption) ? allCountries : this.countries;
1155
+ const countryList = ignoreOnlyCountriesOption
1156
+ ? allCountries
1157
+ : this.countries;
958
1158
  for (let i = 0; i < countryList.length; i++) {
959
1159
  if (countryList[i].iso2 === countryCode) {
960
1160
  return countryList[i];
@@ -966,29 +1166,44 @@ class Iti {
966
1166
  throw new Error(`No country data for '${countryCode}'`);
967
1167
  }
968
1168
 
969
-
970
1169
  // select the given flag, update the placeholder and the active list item
971
1170
  // Note: called from _setInitialState, _updateFlagFromNumber, _selectListItem, setCountry
972
1171
  _setFlag(countryCode) {
973
- const prevCountry = (this.selectedCountryData.iso2) ? this.selectedCountryData : {};
1172
+ const prevCountry = this.selectedCountryData.iso2
1173
+ ? this.selectedCountryData
1174
+ : {};
974
1175
 
975
1176
  // do this first as it will throw an error and stop if countryCode is invalid
976
- this.selectedCountryData = (countryCode) ? this._getCountryData(countryCode, false, false) : {};
1177
+ this.selectedCountryData = countryCode
1178
+ ? this._getCountryData(countryCode, false, false)
1179
+ : {};
977
1180
  // update the defaultCountry - we only need the iso2 from now on, so just store that
978
1181
  if (this.selectedCountryData.iso2) {
979
1182
  this.defaultCountry = this.selectedCountryData.iso2;
980
1183
  }
981
1184
 
982
- this.selectedFlagInner.setAttribute('class', `iti__flag iti__${countryCode}`);
1185
+ if (this.options.showFlags) {
1186
+ this.selectedFlagInner.setAttribute(
1187
+ "class",
1188
+ `iti__flag iti__${countryCode}`
1189
+ );
1190
+ }
983
1191
  // update the selected country's title attribute
984
- const title = (countryCode) ? `${this.selectedCountryData.name}: +${this.selectedCountryData.dialCode}` : 'Unknown';
985
- this.selectedFlag.setAttribute('title', title);
1192
+ if (this.selectedFlag) {
1193
+ const title = countryCode
1194
+ ? `${this.selectedCountryData.name}: +${this.selectedCountryData.dialCode}`
1195
+ : "Unknown";
1196
+ this.selectedFlag.setAttribute("title", title);
1197
+ }
986
1198
 
987
1199
  if (this.options.separateDialCode) {
988
- const dialCode = this.selectedCountryData.dialCode ? `+${this.selectedCountryData.dialCode}` : '';
1200
+ const dialCode = this.selectedCountryData.dialCode
1201
+ ? `+${this.selectedCountryData.dialCode}`
1202
+ : "";
989
1203
  this.selectedDialCode.innerHTML = dialCode;
990
1204
  // offsetWidth is zero if input is in a hidden container during initialisation
991
- const selectedFlagWidth = this.selectedFlag.offsetWidth || this._getHiddenSelectedFlagWidth();
1205
+ const selectedFlagWidth =
1206
+ this.selectedFlag.offsetWidth || this._getHiddenSelectedFlagWidth();
992
1207
 
993
1208
  // add 6px of padding after the grey selected-dial-code box, as this is what we use in the css
994
1209
  this.telInput.style.paddingLeft = `${selectedFlagWidth + 6}px`;
@@ -1001,30 +1216,37 @@ class Iti {
1001
1216
  if (this.options.allowDropdown) {
1002
1217
  const prevItem = this.activeItem;
1003
1218
  if (prevItem) {
1004
- prevItem.classList.remove('iti__active');
1005
- prevItem.setAttribute('aria-selected', 'false');
1219
+ prevItem.classList.remove("iti__active");
1220
+ prevItem.setAttribute("aria-selected", "false");
1006
1221
  }
1007
1222
  if (countryCode) {
1008
1223
  // check if there is a preferred item first, else fall back to standard
1009
- const nextItem = this.countryList.querySelector(`#iti-${this.id}__item-${countryCode}-preferred`) || this.countryList.querySelector(`#iti-${this.id}__item-${countryCode}`);
1010
- nextItem.setAttribute('aria-selected', 'true');
1011
- nextItem.classList.add('iti__active');
1224
+ const nextItem =
1225
+ this.countryList.querySelector(
1226
+ `#iti-${this.id}__item-${countryCode}-preferred`
1227
+ ) ||
1228
+ this.countryList.querySelector(
1229
+ `#iti-${this.id}__item-${countryCode}`
1230
+ );
1231
+ nextItem.setAttribute("aria-selected", "true");
1232
+ nextItem.classList.add("iti__active");
1012
1233
  this.activeItem = nextItem;
1013
1234
  }
1014
1235
  }
1015
1236
 
1016
1237
  // return if the flag has changed or not
1017
- return (prevCountry.iso2 !== countryCode);
1238
+ return prevCountry.iso2 !== countryCode;
1018
1239
  }
1019
1240
 
1020
-
1021
1241
  // when the input is in a hidden container during initialisation, we must inject some markup
1022
1242
  // into the end of the DOM to calculate the correct offsetWidth
1243
+ // NOTE: this is only used when separateDialCode is enabled, so flagsContainer and selectedFlag
1244
+ // will definitely exist
1023
1245
  _getHiddenSelectedFlagWidth() {
1024
1246
  // to get the right styling to apply, all we need is a shallow clone of the container,
1025
1247
  // and then to inject a deep clone of the selectedFlag element
1026
1248
  const containerClone = this.telInput.parentNode.cloneNode();
1027
- containerClone.style.visibility = 'hidden';
1249
+ containerClone.style.visibility = "hidden";
1028
1250
  document.body.appendChild(containerClone);
1029
1251
 
1030
1252
  const flagsContainerClone = this.flagsContainer.cloneNode();
@@ -1038,35 +1260,48 @@ class Iti {
1038
1260
  return width;
1039
1261
  }
1040
1262
 
1041
-
1042
1263
  // update the input placeholder to an example number from the currently selected country
1043
1264
  _updatePlaceholder() {
1044
- const shouldSetPlaceholder = (this.options.autoPlaceholder === 'aggressive') || (!this.hadInitialPlaceholder && this.options.autoPlaceholder === 'polite');
1265
+ const shouldSetPlaceholder =
1266
+ this.options.autoPlaceholder === "aggressive" ||
1267
+ (!this.hadInitialPlaceholder &&
1268
+ this.options.autoPlaceholder === "polite");
1045
1269
  if (window.intlTelInputUtils && shouldSetPlaceholder) {
1046
- const numberType = intlTelInputUtils.numberType[this.options.placeholderNumberType];
1047
- let placeholder = (this.selectedCountryData.iso2) ? intlTelInputUtils.getExampleNumber(this.selectedCountryData.iso2, this.options.nationalMode, numberType) : '';
1270
+ const numberType =
1271
+ intlTelInputUtils.numberType[this.options.placeholderNumberType];
1272
+ let placeholder = this.selectedCountryData.iso2
1273
+ ? intlTelInputUtils.getExampleNumber(
1274
+ this.selectedCountryData.iso2,
1275
+ this.options.nationalMode,
1276
+ numberType
1277
+ )
1278
+ : "";
1048
1279
 
1049
1280
  placeholder = this._beforeSetNumber(placeholder);
1050
- if (typeof this.options.customPlaceholder === 'function') {
1051
- placeholder = this.options.customPlaceholder(placeholder, this.selectedCountryData);
1281
+ if (typeof this.options.customPlaceholder === "function") {
1282
+ placeholder = this.options.customPlaceholder(
1283
+ placeholder,
1284
+ this.selectedCountryData
1285
+ );
1052
1286
  }
1053
- this.telInput.setAttribute('placeholder', placeholder);
1287
+ this.telInput.setAttribute("placeholder", placeholder);
1054
1288
  }
1055
1289
  }
1056
1290
 
1057
-
1058
1291
  // called when the user selects a list item from the dropdown
1059
1292
  _selectListItem(listItem) {
1060
1293
  // update selected flag and active list item
1061
- const flagChanged = this._setFlag(listItem.getAttribute('data-country-code'));
1294
+ const flagChanged = this._setFlag(
1295
+ listItem.getAttribute("data-country-code")
1296
+ );
1062
1297
  this._closeDropdown();
1063
1298
 
1064
- this._updateDialCode(listItem.getAttribute('data-dial-code'));
1299
+ this._updateDialCode(listItem.getAttribute("data-dial-code"));
1065
1300
 
1066
1301
  // focus the input
1067
1302
  this.telInput.focus();
1068
- // put cursor at end - this fix is required for FF and IE11 (with nationalMode=false i.e. auto
1069
- // inserting dial code), who try to put the cursor at the beginning the first time
1303
+ // put cursor at end - this fix is required for FF and IE11 (with auto inserting dial code),
1304
+ // who try to put the cursor at the beginning the first time
1070
1305
  const len = this.telInput.value.length;
1071
1306
  this.telInput.setSelectionRange(len, len);
1072
1307
 
@@ -1075,32 +1310,40 @@ class Iti {
1075
1310
  }
1076
1311
  }
1077
1312
 
1078
-
1079
1313
  // close the dropdown and unbind any listeners
1080
1314
  _closeDropdown() {
1081
- this.countryList.classList.add('iti__hide');
1082
- this.selectedFlag.setAttribute('aria-expanded', 'false');
1083
- this.selectedFlag.removeAttribute('aria-activedescendant');
1315
+ this.countryList.classList.add("iti__hide");
1316
+ this.selectedFlag.setAttribute("aria-expanded", "false");
1317
+ this.selectedFlag.removeAttribute("aria-activedescendant");
1084
1318
 
1085
1319
  // update the arrow
1086
- this.dropdownArrow.classList.remove('iti__arrow--up');
1320
+ this.dropdownArrow.classList.remove("iti__arrow--up");
1087
1321
 
1088
1322
  // unbind key events
1089
- document.removeEventListener('keydown', this._handleKeydownOnDropdown);
1090
- document.documentElement.removeEventListener('click', this._handleClickOffToClose);
1091
- this.countryList.removeEventListener('mouseover', this._handleMouseoverCountryList);
1092
- this.countryList.removeEventListener('click', this._handleClickCountryList);
1323
+ document.removeEventListener("keydown", this._handleKeydownOnDropdown);
1324
+ document.documentElement.removeEventListener(
1325
+ "click",
1326
+ this._handleClickOffToClose
1327
+ );
1328
+ this.countryList.removeEventListener(
1329
+ "mouseover",
1330
+ this._handleMouseoverCountryList
1331
+ );
1332
+ this.countryList.removeEventListener("click", this._handleClickCountryList);
1093
1333
 
1094
1334
  // remove menu from container
1095
1335
  if (this.options.dropdownContainer) {
1096
- if (!this.isMobile) window.removeEventListener('scroll', this._handleWindowScroll);
1097
- if (this.dropdown.parentNode) this.dropdown.parentNode.removeChild(this.dropdown);
1336
+ if (!this.isMobile) {
1337
+ window.removeEventListener("scroll", this._handleWindowScroll);
1338
+ }
1339
+ if (this.dropdown.parentNode) {
1340
+ this.dropdown.parentNode.removeChild(this.dropdown);
1341
+ }
1098
1342
  }
1099
1343
 
1100
- this._trigger('close:countrydropdown');
1344
+ this._trigger("close:countrydropdown");
1101
1345
  }
1102
1346
 
1103
-
1104
1347
  // check if an element is visible within it's container, else scroll until it is
1105
1348
  _scrollTo(element, middle) {
1106
1349
  const container = this.countryList;
@@ -1113,21 +1356,24 @@ class Iti {
1113
1356
  const elementTop = element.getBoundingClientRect().top + windowTop;
1114
1357
  const elementBottom = elementTop + elementHeight;
1115
1358
  let newScrollTop = elementTop - containerTop + container.scrollTop;
1116
- const middleOffset = (containerHeight / 2) - (elementHeight / 2);
1359
+ const middleOffset = containerHeight / 2 - elementHeight / 2;
1117
1360
 
1118
1361
  if (elementTop < containerTop) {
1119
1362
  // scroll up
1120
- if (middle) newScrollTop -= middleOffset;
1363
+ if (middle) {
1364
+ newScrollTop -= middleOffset;
1365
+ }
1121
1366
  container.scrollTop = newScrollTop;
1122
1367
  } else if (elementBottom > containerBottom) {
1123
1368
  // scroll down
1124
- if (middle) newScrollTop += middleOffset;
1369
+ if (middle) {
1370
+ newScrollTop += middleOffset;
1371
+ }
1125
1372
  const heightDifference = containerHeight - elementHeight;
1126
1373
  container.scrollTop = newScrollTop - heightDifference;
1127
1374
  }
1128
1375
  }
1129
1376
 
1130
-
1131
1377
  // replace any existing dial code with the new one
1132
1378
  // Note: called from _selectListItem and setCountry
1133
1379
  _updateDialCode(newDialCodeBare) {
@@ -1136,8 +1382,8 @@ class Iti {
1136
1382
  const newDialCode = `+${newDialCodeBare}`;
1137
1383
 
1138
1384
  let newNumber;
1139
- if (inputVal.charAt(0) === '+') {
1140
- // there's a plus so we're dealing with a replacement (doesn't matter if nationalMode or not)
1385
+ if (inputVal.charAt(0) === "+") {
1386
+ // there's a plus so we're dealing with a replacement
1141
1387
  const prevDialCode = this._getDialCode(inputVal);
1142
1388
  if (prevDialCode) {
1143
1389
  // current number contains a valid dial code, so replace it
@@ -1159,14 +1405,13 @@ class Iti {
1159
1405
  }
1160
1406
  }
1161
1407
 
1162
-
1163
1408
  // try and extract a valid international dial code from a full telephone number
1164
1409
  // Note: returns the raw string inc plus character and any whitespace/dots etc
1165
1410
  _getDialCode(number, includeAreaCode) {
1166
- let dialCode = '';
1411
+ let dialCode = "";
1167
1412
  // only interested in international numbers (starting with a plus)
1168
- if (number.charAt(0) === '+') {
1169
- let numericChars = '';
1413
+ if (number.charAt(0) === "+") {
1414
+ let numericChars = "";
1170
1415
  // iterate over chars
1171
1416
  for (let i = 0; i < number.length; i++) {
1172
1417
  const c = number.charAt(i);
@@ -1196,7 +1441,6 @@ class Iti {
1196
1441
  return dialCode;
1197
1442
  }
1198
1443
 
1199
-
1200
1444
  // get the input val, adding the dial code if separateDialCode is enabled
1201
1445
  _getFullNumber() {
1202
1446
  const val = this.telInput.value.trim();
@@ -1204,16 +1448,20 @@ class Iti {
1204
1448
  let prefix;
1205
1449
  const numericVal = this._getNumeric(val);
1206
1450
 
1207
- if (this.options.separateDialCode && val.charAt(0) !== '+' && dialCode && numericVal) {
1451
+ if (
1452
+ this.options.separateDialCode &&
1453
+ val.charAt(0) !== "+" &&
1454
+ dialCode &&
1455
+ numericVal
1456
+ ) {
1208
1457
  // when using separateDialCode, it is visible so is effectively part of the typed number
1209
1458
  prefix = `+${dialCode}`;
1210
1459
  } else {
1211
- prefix = '';
1460
+ prefix = "";
1212
1461
  }
1213
1462
  return prefix + val;
1214
1463
  }
1215
1464
 
1216
-
1217
1465
  // remove the dial code if separateDialCode is enabled
1218
1466
  // also cap the length if the input has a maxlength attribute
1219
1467
  _beforeSetNumber(originalNumber) {
@@ -1228,7 +1476,10 @@ class Iti {
1228
1476
  // some NANP numbers will have a hyphen e.g. +1 684-733-1234 - in both cases we want to get
1229
1477
  // rid of it
1230
1478
  // NOTE: don't just trim all non-numerics as may want to preserve an open parenthesis etc
1231
- const start = (number[dialCode.length] === ' ' || number[dialCode.length] === '-') ? dialCode.length + 1 : dialCode.length;
1479
+ const start =
1480
+ number[dialCode.length] === " " || number[dialCode.length] === "-"
1481
+ ? dialCode.length + 1
1482
+ : dialCode.length;
1232
1483
  number = number.substr(start);
1233
1484
  }
1234
1485
  }
@@ -1236,21 +1487,18 @@ class Iti {
1236
1487
  return this._cap(number);
1237
1488
  }
1238
1489
 
1239
-
1240
1490
  // trigger the 'countrychange' event
1241
1491
  _triggerCountryChange() {
1242
- this._trigger('countrychange');
1492
+ this._trigger("countrychange");
1243
1493
  }
1244
1494
 
1245
-
1246
1495
  /**************************
1247
1496
  * SECRET PUBLIC METHODS
1248
1497
  **************************/
1249
1498
 
1250
-
1251
1499
  // this is called when the geoip call returns
1252
1500
  handleAutoCountry() {
1253
- if (this.options.initialCountry === 'auto') {
1501
+ if (this.options.initialCountry === "auto") {
1254
1502
  // we must set this even if there is an initial val in the input: in case the initial val is
1255
1503
  // invalid and they delete it - they should see their auto country
1256
1504
  this.defaultCountry = window.intlTelInputGlobals.autoCountry;
@@ -1262,7 +1510,6 @@ class Iti {
1262
1510
  }
1263
1511
  }
1264
1512
 
1265
-
1266
1513
  // this is called when the utils request completes
1267
1514
  handleUtils() {
1268
1515
  // if the request was successful
@@ -1276,12 +1523,10 @@ class Iti {
1276
1523
  this.resolveUtilsScriptPromise();
1277
1524
  }
1278
1525
 
1279
-
1280
1526
  /********************
1281
1527
  * PUBLIC METHODS
1282
1528
  ********************/
1283
1529
 
1284
-
1285
1530
  // remove plugin
1286
1531
  destroy() {
1287
1532
  const { form } = this.telInput;
@@ -1289,29 +1534,41 @@ class Iti {
1289
1534
  if (this.options.allowDropdown) {
1290
1535
  // make sure the dropdown is closed (and unbind listeners)
1291
1536
  this._closeDropdown();
1292
- this.selectedFlag.removeEventListener('click', this._handleClickSelectedFlag);
1293
- this.flagsContainer.removeEventListener('keydown', this._handleFlagsContainerKeydown);
1537
+ this.selectedFlag.removeEventListener(
1538
+ "click",
1539
+ this._handleClickSelectedFlag
1540
+ );
1541
+ this.flagsContainer.removeEventListener(
1542
+ "keydown",
1543
+ this._handleFlagsContainerKeydown
1544
+ );
1294
1545
  // label click hack
1295
1546
  const label = this._getClosestLabel();
1296
- if (label) label.removeEventListener('click', this._handleLabelClick);
1547
+ if (label) {
1548
+ label.removeEventListener("click", this._handleLabelClick);
1549
+ }
1297
1550
  }
1298
1551
 
1299
1552
  // unbind hiddenInput listeners
1300
- if (this.hiddenInput && form) form.removeEventListener('submit', this._handleHiddenInputSubmit);
1553
+ if (this.hiddenInput && form) {
1554
+ form.removeEventListener("submit", this._handleHiddenInputSubmit);
1555
+ }
1301
1556
 
1302
1557
  // unbind autoInsertDialCode listeners
1303
1558
  if (this.options.autoInsertDialCode) {
1304
- if (form) form.removeEventListener('submit', this._handleSubmitOrBlurEvent);
1305
- this.telInput.removeEventListener('blur', this._handleSubmitOrBlurEvent);
1559
+ if (form) {
1560
+ form.removeEventListener("submit", this._handleSubmitOrBlurEvent);
1561
+ }
1562
+ this.telInput.removeEventListener("blur", this._handleSubmitOrBlurEvent);
1306
1563
  }
1307
1564
 
1308
1565
  // unbind key events, and cut/paste events
1309
- this.telInput.removeEventListener('keyup', this._handleKeyupEvent);
1310
- this.telInput.removeEventListener('cut', this._handleClipboardEvent);
1311
- this.telInput.removeEventListener('paste', this._handleClipboardEvent);
1566
+ this.telInput.removeEventListener("keyup", this._handleKeyupEvent);
1567
+ this.telInput.removeEventListener("cut", this._handleClipboardEvent);
1568
+ this.telInput.removeEventListener("paste", this._handleClipboardEvent);
1312
1569
 
1313
1570
  // remove attribute of id instance: data-intl-tel-input-id
1314
- this.telInput.removeAttribute('data-intl-tel-input-id');
1571
+ this.telInput.removeAttribute("data-intl-tel-input-id");
1315
1572
 
1316
1573
  // remove markup (but leave the original input)
1317
1574
  const wrapper = this.telInput.parentNode;
@@ -1321,41 +1578,46 @@ class Iti {
1321
1578
  delete window.intlTelInputGlobals.instances[this.id];
1322
1579
  }
1323
1580
 
1324
-
1325
1581
  // get the extension from the current number
1326
1582
  getExtension() {
1327
1583
  if (window.intlTelInputUtils) {
1328
- return intlTelInputUtils.getExtension(this._getFullNumber(), this.selectedCountryData.iso2);
1584
+ return intlTelInputUtils.getExtension(
1585
+ this._getFullNumber(),
1586
+ this.selectedCountryData.iso2
1587
+ );
1329
1588
  }
1330
- return '';
1589
+ return "";
1331
1590
  }
1332
1591
 
1333
-
1334
1592
  // format the number to the given format
1335
1593
  getNumber(format) {
1336
1594
  if (window.intlTelInputUtils) {
1337
1595
  const { iso2 } = this.selectedCountryData;
1338
- return intlTelInputUtils.formatNumber(this._getFullNumber(), iso2, format);
1596
+ return intlTelInputUtils.formatNumber(
1597
+ this._getFullNumber(),
1598
+ iso2,
1599
+ format
1600
+ );
1339
1601
  }
1340
- return '';
1602
+ return "";
1341
1603
  }
1342
1604
 
1343
-
1344
1605
  // get the type of the entered number e.g. landline/mobile
1345
1606
  getNumberType() {
1346
1607
  if (window.intlTelInputUtils) {
1347
- return intlTelInputUtils.getNumberType(this._getFullNumber(), this.selectedCountryData.iso2);
1608
+ return intlTelInputUtils.getNumberType(
1609
+ this._getFullNumber(),
1610
+ this.selectedCountryData.iso2
1611
+ );
1348
1612
  }
1349
1613
  return -99;
1350
1614
  }
1351
1615
 
1352
-
1353
1616
  // get the country data for the currently selected flag
1354
1617
  getSelectedCountryData() {
1355
1618
  return this.selectedCountryData;
1356
1619
  }
1357
1620
 
1358
-
1359
1621
  // get the validation error
1360
1622
  getValidationError() {
1361
1623
  if (window.intlTelInputUtils) {
@@ -1365,27 +1627,25 @@ class Iti {
1365
1627
  return -99;
1366
1628
  }
1367
1629
 
1368
-
1369
1630
  // validate the input val - assumes the global function isValidNumber (from utilsScript)
1370
1631
  isValidNumber() {
1371
1632
  const val = this._getFullNumber().trim();
1372
- const countryCode = (this.options.nationalMode) ? this.selectedCountryData.iso2 : '';
1373
- return (window.intlTelInputUtils ? intlTelInputUtils.isValidNumber(val, countryCode) : null);
1633
+ return window.intlTelInputUtils
1634
+ ? intlTelInputUtils.isValidNumber(val, this.selectedCountryData.iso2)
1635
+ : null;
1374
1636
  }
1375
1637
 
1376
-
1377
1638
  // update the selected flag, and update the input val accordingly
1378
1639
  setCountry(originalCountryCode) {
1379
1640
  const countryCode = originalCountryCode.toLowerCase();
1380
1641
  // check if already selected
1381
- if (!this.selectedFlagInner.classList.contains(`iti__${countryCode}`)) {
1642
+ if (this.selectedCountryData.iso2 !== countryCode) {
1382
1643
  this._setFlag(countryCode);
1383
1644
  this._updateDialCode(this.selectedCountryData.dialCode);
1384
1645
  this._triggerCountryChange();
1385
1646
  }
1386
1647
  }
1387
1648
 
1388
-
1389
1649
  // set the input value and update the flag
1390
1650
  setNumber(number) {
1391
1651
  // we must update the flag first, which updates this.selectedCountryData, which is used for
@@ -1404,57 +1664,61 @@ class Iti {
1404
1664
  }
1405
1665
  }
1406
1666
 
1407
-
1408
1667
  /********************
1409
1668
  * STATIC METHODS
1410
1669
  ********************/
1411
1670
 
1412
-
1413
1671
  // get the country data object
1414
1672
  intlTelInputGlobals.getCountryData = () => allCountries;
1415
1673
 
1416
-
1417
1674
  // inject a <script> element to load utils.js
1418
1675
  const injectScript = (path, handleSuccess, handleFailure) => {
1419
1676
  // inject a new script element into the page
1420
- const script = document.createElement('script');
1677
+ const script = document.createElement("script");
1421
1678
  script.onload = () => {
1422
- forEachInstance('handleUtils');
1423
- if (handleSuccess) handleSuccess();
1679
+ forEachInstance("handleUtils");
1680
+ if (handleSuccess) {
1681
+ handleSuccess();
1682
+ }
1424
1683
  };
1425
1684
  script.onerror = () => {
1426
- forEachInstance('rejectUtilsScriptPromise');
1427
- if (handleFailure) handleFailure();
1685
+ forEachInstance("rejectUtilsScriptPromise");
1686
+ if (handleFailure) {
1687
+ handleFailure();
1688
+ }
1428
1689
  };
1429
- script.className = 'iti-load-utils';
1690
+ script.className = "iti-load-utils";
1430
1691
  script.async = true;
1431
1692
  script.src = path;
1432
1693
  document.body.appendChild(script);
1433
1694
  };
1434
1695
 
1435
-
1436
1696
  // load the utils script
1437
1697
  intlTelInputGlobals.loadUtils = (path) => {
1438
1698
  // 2 options:
1439
1699
  // 1) not already started loading (start)
1440
1700
  // 2) already started loading (do nothing - just wait for the onload callback to fire, which will
1441
1701
  // trigger handleUtils on all instances, invoking their resolveUtilsScriptPromise functions)
1442
- if (!window.intlTelInputUtils && !window.intlTelInputGlobals.startedLoadingUtilsScript) {
1702
+ if (
1703
+ !window.intlTelInputUtils &&
1704
+ !window.intlTelInputGlobals.startedLoadingUtilsScript
1705
+ ) {
1443
1706
  // only do this once
1444
1707
  window.intlTelInputGlobals.startedLoadingUtilsScript = true;
1445
1708
 
1446
1709
  // if we have promises, then return a promise
1447
- if (typeof Promise !== 'undefined') {
1448
- return new Promise((resolve, reject) => injectScript(path, resolve, reject));
1710
+ if (typeof Promise !== "undefined") {
1711
+ return new Promise((resolve, reject) =>
1712
+ injectScript(path, resolve, reject)
1713
+ );
1449
1714
  }
1450
1715
  injectScript(path);
1451
1716
  }
1452
1717
  return null;
1453
1718
  };
1454
1719
 
1455
-
1456
1720
  // default options
1457
1721
  intlTelInputGlobals.defaults = defaults;
1458
1722
 
1459
1723
  // version
1460
- intlTelInputGlobals.version = '<%= version %>';
1724
+ intlTelInputGlobals.version = "<%= version %>";