intl-tel-input 18.5.2 → 19.0.0

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 (34) hide show
  1. package/README.md +42 -28
  2. package/build/css/demo.css +1 -1
  3. package/build/css/intlTelInput.css +28 -20
  4. package/build/js/data.js +1 -1
  5. package/build/js/data.min.js +1 -1
  6. package/build/js/intlTelInput-jquery.js +159 -154
  7. package/build/js/intlTelInput-jquery.min.js +3 -3
  8. package/build/js/intlTelInput.js +159 -154
  9. package/build/js/intlTelInput.min.js +3 -3
  10. package/composer.json +1 -1
  11. package/demo.html +5 -5
  12. package/grunt/replace.js +1 -7
  13. package/package.json +1 -1
  14. package/spec.html +6 -4
  15. package/src/css/demo.scss +1 -1
  16. package/src/css/intlTelInput.scss +41 -30
  17. package/src/js/intlTelInput.js +77 -128
  18. package/src/spec/helpers/helpers.js +23 -10
  19. package/src/spec/tests/core/countrychangeEvent.js +1 -1
  20. package/src/spec/tests/core/dropdownShortcuts.js +3 -2
  21. package/src/spec/tests/core/initialValues.js +2 -3
  22. package/src/spec/tests/methods/getSelectedCountryData.js +1 -1
  23. package/src/spec/tests/methods/isValidNumber.js +15 -32
  24. package/src/spec/tests/methods/isValidNumberPrecise.js +73 -0
  25. package/src/spec/tests/methods/setCountry.js +4 -4
  26. package/src/spec/tests/options/allowDropdown.js +3 -3
  27. package/src/spec/tests/options/autoInsertDialCode.js +1 -3
  28. package/src/spec/tests/options/autoPlaceholder.js +5 -5
  29. package/src/spec/tests/options/{customContainer.js → containerClass.js} +3 -3
  30. package/src/spec/tests/options/countrySearch.js +63 -0
  31. package/src/spec/tests/options/customPlaceholder.js +1 -1
  32. package/src/spec/tests/options/preferredCountries.js +3 -1
  33. package/src/spec/tests/options/{separateDialCode.js → showSelectedDialCode.js} +7 -7
  34. package/src/spec/tests/methods/isPossibleNumber.js +0 -56
@@ -23,9 +23,9 @@ const defaults = {
23
23
  // add a placeholder in the input with an example number for the selected country
24
24
  autoPlaceholder: "polite",
25
25
  // add a country search input at the top of the dropdown
26
- countrySearch: false,
26
+ countrySearch: true,
27
27
  // modify the parentClass
28
- customContainer: "",
28
+ containerClass: "",
29
29
  // modify the auto placeholder
30
30
  customPlaceholder: null,
31
31
  // append menu to specified element
@@ -33,29 +33,29 @@ const defaults = {
33
33
  // don't display these countries
34
34
  excludeCountries: [],
35
35
  // fix the dropdown width to the input width (rather than being as wide as the longest country name)
36
- fixDropdownWidth: false,
36
+ fixDropdownWidth: true,
37
37
  // format the input value during initialisation and on setNumber
38
38
  formatOnDisplay: true,
39
39
  // geoIp lookup function
40
40
  geoIpLookup: null,
41
41
  // inject a hidden input with this name, and on submit, populate it with the result of getNumber
42
- hiddenInput: "",
42
+ hiddenInput: null,
43
+ // internationalise the plugin text e.g. search input placeholder, country names
44
+ i18n: {},
43
45
  // initial country
44
46
  initialCountry: "",
45
- // localized country names e.g. { 'de': 'Deutschland' }
46
- localizedCountries: null,
47
47
  // national vs international formatting for numbers e.g. placeholders and displaying existing numbers
48
48
  nationalMode: true,
49
49
  // display only these countries
50
50
  onlyCountries: [],
51
51
  // number type to use for placeholders
52
52
  placeholderNumberType: "MOBILE",
53
- // the countries at the top of the list. defaults to united states and united kingdom
54
- preferredCountries: ["us", "gb"],
55
- // display the country dial code next to the selected flag
56
- separateDialCode: false,
57
- // option to hide the flags - must be used with separateDialCode, or allowDropdown=false
53
+ // the countries at the top of the list
54
+ preferredCountries: [],
55
+ // option to hide the flags - must be used with showSelectedDialCode, or allowDropdown=false
58
56
  showFlags: true,
57
+ // display the international dial code next to the selected flag
58
+ showSelectedDialCode: false,
59
59
  // use full screen popup instead of dropdown for country list
60
60
  useFullscreenPopup:
61
61
  typeof navigator !== "undefined" && typeof window !== "undefined"
@@ -90,26 +90,16 @@ const regionlessNanpNumbers = [
90
90
  "889"
91
91
  ];
92
92
 
93
- // utility function to iterate over an object. can't use Object.entries or native forEach because
94
- // of IE11
95
- const forEachProp = (obj, callback) => {
96
- const keys = Object.keys(obj);
97
- for (let i = 0; i < keys.length; i++) {
98
- callback(keys[i], obj[keys[i]]);
99
- }
100
- };
101
-
102
93
  // run a method on each instance of the plugin
103
94
  const forEachInstance = (method) => {
104
- forEachProp(window.intlTelInputGlobals.instances, (key) => {
105
- window.intlTelInputGlobals.instances[key][method]();
106
- });
95
+ const { instances } = window.intlTelInputGlobals;
96
+ Object.values(instances).forEach((instance) => instance[method]());
107
97
  };
108
98
 
109
99
  // this is our plugin class that we will create an instance of
110
100
  // eslint-disable-next-line no-unused-vars
111
101
  class Iti {
112
- constructor(input, options) {
102
+ constructor(input, customOptions = {}) {
113
103
  this.id = id++;
114
104
  this.telInput = input;
115
105
 
@@ -117,15 +107,7 @@ class Iti {
117
107
  this.highlightedItem = null;
118
108
 
119
109
  // process specified options / defaults
120
- // alternative to Object.assign, which isn't supported by IE11
121
- const customOptions = options || {};
122
- this.options = {};
123
- forEachProp(defaults, (key, value) => {
124
- this.options[key] = customOptions.hasOwnProperty(key)
125
- ? customOptions[key]
126
- : value;
127
- });
128
-
110
+ this.options = Object.assign({}, defaults, customOptions);
129
111
  this.hadInitialPlaceholder = Boolean(input.getAttribute("placeholder"));
130
112
  }
131
113
 
@@ -145,15 +127,15 @@ class Iti {
145
127
  this.options.autoInsertDialCode = false;
146
128
  }
147
129
 
148
- // if separateDialCode enabled, do not insert dial codes
149
- if (this.options.separateDialCode) {
130
+ // if showSelectedDialCode enabled, do not insert dial codes
131
+ if (this.options.showSelectedDialCode) {
150
132
  this.options.autoInsertDialCode = false;
151
133
  }
152
134
 
153
135
  // force showFlags=true if there's a dropdown and we're not displaying the dial code,
154
136
  // as otherwise you just have a down arrow on it's own which doesn't make sense
155
137
  const forceShowFlags =
156
- this.options.allowDropdown && !this.options.separateDialCode;
138
+ this.options.allowDropdown && !this.options.showSelectedDialCode;
157
139
  if (!this.options.showFlags && forceShowFlags) {
158
140
  this.options.showFlags = true;
159
141
  }
@@ -221,13 +203,11 @@ class Iti {
221
203
  // process the preferredCountries
222
204
  this._processPreferredCountries();
223
205
 
224
- // translate countries according to localizedCountries option
225
- if (this.options.localizedCountries) {
226
- this._translateCountriesByLocale();
227
- }
206
+ // translate country names according to i18n option
207
+ this._translateCountryNames();
228
208
 
229
209
  // sort countries by name
230
- if (this.options.onlyCountries.length || this.options.localizedCountries) {
210
+ if (this.options.onlyCountries.length || this.options.i18n) {
231
211
  this.countries.sort(this._countryNameSort);
232
212
  }
233
213
  }
@@ -274,11 +254,11 @@ class Iti {
274
254
  }
275
255
 
276
256
  // Translate Countries by object literal provided on config
277
- _translateCountriesByLocale() {
257
+ _translateCountryNames() {
278
258
  for (let i = 0; i < this.countries.length; i++) {
279
259
  const iso = this.countries[i].iso2.toLowerCase();
280
- if (this.options.localizedCountries.hasOwnProperty(iso)) {
281
- this.countries[i].name = this.options.localizedCountries[iso];
260
+ if (this.options.i18n.hasOwnProperty(iso)) {
261
+ this.countries[i].name = this.options.i18n[iso];
282
262
  }
283
263
  }
284
264
  }
@@ -354,7 +334,7 @@ class Iti {
354
334
  _createEl(name, attrs, container) {
355
335
  const el = document.createElement(name);
356
336
  if (attrs) {
357
- forEachProp(attrs, (key, value) => el.setAttribute(key, value));
337
+ Object.entries(attrs).forEach(([key, value]) => el.setAttribute(key, value));
358
338
  }
359
339
  if (container) {
360
340
  container.appendChild(el);
@@ -379,9 +359,9 @@ class Iti {
379
359
 
380
360
  const {
381
361
  allowDropdown,
382
- separateDialCode,
362
+ showSelectedDialCode,
383
363
  showFlags,
384
- customContainer,
364
+ containerClass,
385
365
  hiddenInput,
386
366
  dropdownContainer,
387
367
  fixDropdownWidth,
@@ -394,23 +374,23 @@ class Iti {
394
374
  if (allowDropdown) {
395
375
  parentClass += " iti--allow-dropdown";
396
376
  }
397
- if (separateDialCode) {
398
- parentClass += " iti--separate-dial-code";
377
+ if (showSelectedDialCode) {
378
+ parentClass += " iti--show-selected-dial-code";
399
379
  }
400
380
  if (showFlags) {
401
381
  parentClass += " iti--show-flags";
402
382
  }
403
- if (!fixDropdownWidth) {
404
- parentClass += " iti--flexible-dropdown-width";
383
+ if (containerClass) {
384
+ parentClass += ` ${containerClass}`;
405
385
  }
406
- if (customContainer) {
407
- parentClass += ` ${customContainer}`;
386
+ if (!useFullscreenPopup) {
387
+ parentClass += " iti--inline-dropdown";
408
388
  }
409
389
 
410
390
  const wrapper = this._createEl("div", { class: parentClass });
411
391
  this.telInput.parentNode.insertBefore(wrapper, this.telInput);
412
- // only hide the flagsContainer if allowDropdown, showFlags and separateDialCode are all false
413
- const showFlagsContainer = allowDropdown || showFlags || separateDialCode;
392
+ // only hide the flagsContainer if allowDropdown, showFlags and showSelectedDialCode are all false
393
+ const showFlagsContainer = allowDropdown || showFlags || showSelectedDialCode;
414
394
  if (showFlagsContainer) {
415
395
  this.flagsContainer = this._createEl(
416
396
  "div",
@@ -433,7 +413,7 @@ class Iti {
433
413
  "aria-haspopup": "listbox",
434
414
  "aria-controls": `iti-${this.id}__country-listbox`,
435
415
  "aria-expanded": "false",
436
- "aria-label": "Telephone country code"
416
+ "aria-label": this.options.i18n.selectedCountryAriaLabel || "Selected country"
437
417
  })
438
418
  },
439
419
  this.flagsContainer
@@ -451,7 +431,7 @@ class Iti {
451
431
  this.selectedFlag.setAttribute("aria-disabled", "true");
452
432
  }
453
433
 
454
- if (separateDialCode) {
434
+ if (showSelectedDialCode) {
455
435
  this.selectedDialCode = this._createEl(
456
436
  "div",
457
437
  { class: "iti__selected-dial-code" },
@@ -471,8 +451,9 @@ class Iti {
471
451
  this.selectedFlag
472
452
  );
473
453
 
454
+ const extraClasses = fixDropdownWidth ? "" : "iti--flexible-dropdown-width";
474
455
  this.dropdownContent = this._createEl("div", {
475
- class: "iti__dropdown-content iti__hide"
456
+ class: `iti__dropdown-content iti__hide ${extraClasses}`
476
457
  });
477
458
 
478
459
  if (countrySearch) {
@@ -481,7 +462,7 @@ class Iti {
481
462
  {
482
463
  type: "text",
483
464
  class: "iti__search-input",
484
- placeholder: "Search"
465
+ placeholder: this.options.i18n.searchPlaceholder || "Search"
485
466
  },
486
467
  this.dropdownContent
487
468
  );
@@ -494,7 +475,7 @@ class Iti {
494
475
  class: "iti__country-list",
495
476
  id: `iti-${this.id}__country-listbox`,
496
477
  role: "listbox",
497
- "aria-label": "List of countries"
478
+ "aria-label": this.options.i18n.countryListAriaLabel || "List of countries"
498
479
  },
499
480
  this.dropdownContent
500
481
  );
@@ -516,6 +497,8 @@ class Iti {
516
497
  let dropdownClasses = "iti iti--container";
517
498
  if (useFullscreenPopup) {
518
499
  dropdownClasses += " iti--fullscreen-popup";
500
+ } else {
501
+ dropdownClasses += " iti--inline-dropdown";
519
502
  }
520
503
  if (countrySearch) {
521
504
  dropdownClasses += " iti--country-search";
@@ -528,16 +511,8 @@ class Iti {
528
511
  }
529
512
 
530
513
  if (hiddenInput) {
531
- let hiddenInputName = hiddenInput;
532
- const name = this.telInput.getAttribute("name");
533
- if (name) {
534
- const i = name.lastIndexOf("[");
535
- // if input name contains square brackets, then give the hidden input the same name,
536
- // replacing the contents of the last set of brackets with the given hiddenInput name
537
- if (i !== -1) {
538
- hiddenInputName = `${name.substr(0, i)}[${hiddenInputName}]`;
539
- }
540
- }
514
+ const telInputName = this.telInput.getAttribute("name");
515
+ const hiddenInputName = hiddenInput(telInputName);
541
516
  this.hiddenInput = this._createEl("input", {
542
517
  type: "hidden",
543
518
  name: hiddenInputName
@@ -665,15 +640,6 @@ class Iti {
665
640
  }
666
641
  }
667
642
 
668
- // iterate through parent nodes to find the closest label ancestor, if it exists
669
- _getClosestLabel() {
670
- let el = this.telInput;
671
- while (el && el.tagName !== "LABEL") {
672
- el = el.parentNode;
673
- }
674
- return el;
675
- }
676
-
677
643
  // initialise the dropdown listeners
678
644
  _initDropdownListeners() {
679
645
  // hack for input nested inside label (which is valid markup): clicking the selected-flag to
@@ -687,7 +653,7 @@ class Iti {
687
653
  e.preventDefault();
688
654
  }
689
655
  };
690
- const label = this._getClosestLabel();
656
+ const label = this.telInput.closest("label");
691
657
  if (label) {
692
658
  label.addEventListener("click", this._handleLabelClick);
693
659
  }
@@ -850,9 +816,10 @@ class Iti {
850
816
 
851
817
  // trigger a custom event on the input
852
818
  _trigger(name) {
853
- // have to use old school document.createEvent as IE11 doesn't support `new Event()` syntax
854
- const e = document.createEvent("Event");
855
- e.initEvent(name, true, true); // can bubble, and is cancellable
819
+ const e = new Event(name, {
820
+ bubbles: true,
821
+ cancelable: true
822
+ });
856
823
  this.telInput.dispatchEvent(e);
857
824
  }
858
825
 
@@ -894,7 +861,7 @@ class Iti {
894
861
  }
895
862
  }
896
863
 
897
- // decide where to position dropdown (depends on position within viewport, and scroll)
864
+ // decide if should position dropdown above or below input (depends on position within viewport, and scroll)
898
865
  _setDropdownPosition() {
899
866
  if (this.options.dropdownContainer) {
900
867
  this.options.dropdownContainer.appendChild(this.dropdown);
@@ -903,8 +870,7 @@ class Iti {
903
870
  if (!this.options.useFullscreenPopup) {
904
871
  const pos = this.telInput.getBoundingClientRect();
905
872
  // windowTop from https://stackoverflow.com/a/14384091/217866
906
- const windowTop =
907
- window.pageYOffset || document.documentElement.scrollTop;
873
+ const windowTop = document.documentElement.scrollTop;
908
874
  const inputTop = pos.top + windowTop;
909
875
  const dropdownHeight = this.dropdownContent.offsetHeight;
910
876
  // dropdownFitsBelow = (dropdownBottom < windowBottom)
@@ -943,27 +909,13 @@ class Iti {
943
909
  }
944
910
  }
945
911
 
946
- // iterate through parent nodes to find the closest list item
947
- _getClosestListItem(target) {
948
- let el = target;
949
- while (
950
- el &&
951
- el !== this.countryList &&
952
- !el.classList.contains("iti__country")
953
- ) {
954
- el = el.parentNode;
955
- }
956
- // if we reached the countryList element, then return null
957
- return el === this.countryList ? null : el;
958
- }
959
-
960
912
  // we only bind dropdown listeners when the dropdown is open
961
913
  _bindDropdownListeners() {
962
914
  // when mouse over a list item, just highlight that one
963
915
  // we add the class "highlight", so if they hit "enter" we know which one to select
964
916
  this._handleMouseoverCountryList = (e) => {
965
917
  // handle event delegation, as we're listening for this event on the countryList
966
- const listItem = this._getClosestListItem(e.target);
918
+ const listItem = e.target.closest(".iti__country");
967
919
  if (listItem) {
968
920
  this._highlightListItem(listItem, false);
969
921
  }
@@ -975,7 +927,7 @@ class Iti {
975
927
 
976
928
  // listen for country selection
977
929
  this._handleClickCountryList = (e) => {
978
- const listItem = this._getClosestListItem(e.target);
930
+ const listItem = e.target.closest(".iti__country");
979
931
  if (listItem) {
980
932
  this._selectListItem(listItem);
981
933
  }
@@ -1080,7 +1032,8 @@ class Iti {
1080
1032
  if (
1081
1033
  isReset ||
1082
1034
  nameLower.includes(query) ||
1083
- fullDialCode.includes(query)
1035
+ fullDialCode.includes(query) ||
1036
+ c.iso2.includes(query)
1084
1037
  ) {
1085
1038
  this.countryList.appendChild(c.node);
1086
1039
  // highlight the first item
@@ -1159,7 +1112,7 @@ class Iti {
1159
1112
  ) {
1160
1113
  const useNational =
1161
1114
  this.options.nationalMode ||
1162
- (number.charAt(0) !== "+" && !this.options.separateDialCode);
1115
+ (number.charAt(0) !== "+" && !this.options.showSelectedDialCode);
1163
1116
  const { NATIONAL, INTERNATIONAL } = intlTelInputUtils.numberFormat;
1164
1117
  const format = useNational ? NATIONAL : INTERNATIONAL;
1165
1118
  number = intlTelInputUtils.formatNumber(
@@ -1196,9 +1149,9 @@ class Iti {
1196
1149
  number = `+${number}`;
1197
1150
  }
1198
1151
 
1199
- // if separateDialCode enabled, then consider the selected dial code to be part of the number
1152
+ // if showSelectedDialCode enabled, then consider the selected dial code to be part of the number
1200
1153
  if (
1201
- this.options.separateDialCode &&
1154
+ this.options.showSelectedDialCode &&
1202
1155
  selectedDialCode &&
1203
1156
  number.charAt(0) !== "+"
1204
1157
  ) {
@@ -1300,7 +1253,7 @@ class Iti {
1300
1253
  // select the given flag, update the placeholder, title, and the active list item
1301
1254
  // Note: called from _setInitialState, _updateFlagFromNumber, _selectListItem, setCountry
1302
1255
  _setFlag(countryCode) {
1303
- const { allowDropdown, separateDialCode, showFlags } = this.options;
1256
+ const { allowDropdown, showSelectedDialCode, showFlags } = this.options;
1304
1257
 
1305
1258
  const prevCountry = this.selectedCountryData.iso2
1306
1259
  ? this.selectedCountryData
@@ -1322,9 +1275,9 @@ class Iti {
1322
1275
  );
1323
1276
  }
1324
1277
 
1325
- this._setSelectedCountryFlagTitleAttribute(countryCode, separateDialCode);
1278
+ this._setSelectedCountryFlagTitleAttribute(countryCode, showSelectedDialCode);
1326
1279
 
1327
- if (separateDialCode) {
1280
+ if (showSelectedDialCode) {
1328
1281
  const dialCode = this.selectedCountryData.dialCode
1329
1282
  ? `+${this.selectedCountryData.dialCode}`
1330
1283
  : "";
@@ -1370,13 +1323,13 @@ class Iti {
1370
1323
  return prevCountry.iso2 !== countryCode;
1371
1324
  }
1372
1325
 
1373
- _setSelectedCountryFlagTitleAttribute(countryCode, separateDialCode) {
1326
+ _setSelectedCountryFlagTitleAttribute(countryCode, showSelectedDialCode) {
1374
1327
  if (!this.selectedFlag) {
1375
1328
  return;
1376
1329
  }
1377
1330
 
1378
1331
  let title;
1379
- if (countryCode && !separateDialCode) {
1332
+ if (countryCode && !showSelectedDialCode) {
1380
1333
  title = `${this.selectedCountryData.name}: +${this.selectedCountryData.dialCode}`;
1381
1334
  } else if (countryCode) {
1382
1335
  // For screen reader output, we don't want to include the dial code in the reader output twice
@@ -1391,7 +1344,7 @@ class Iti {
1391
1344
 
1392
1345
  // when the input is in a hidden container during initialisation, we must inject some markup
1393
1346
  // into the end of the DOM to calculate the correct offsetWidth
1394
- // NOTE: this is only used when separateDialCode is enabled, so flagsContainer and selectedFlag
1347
+ // NOTE: this is only used when showSelectedDialCode is enabled, so flagsContainer and selectedFlag
1395
1348
  // will definitely exist
1396
1349
  _getHiddenSelectedFlagWidth() {
1397
1350
  // to get the right styling to apply, all we need is a shallow clone of the container,
@@ -1451,10 +1404,6 @@ class Iti {
1451
1404
 
1452
1405
  // focus the input
1453
1406
  this.telInput.focus();
1454
- // put cursor at end - this fix is required for FF and IE11 (with auto inserting dial code),
1455
- // who try to put the cursor at the beginning the first time
1456
- const len = this.telInput.value.length;
1457
- this.telInput.setSelectionRange(len, len);
1458
1407
 
1459
1408
  if (flagChanged) {
1460
1409
  this._triggerCountryChange();
@@ -1502,7 +1451,7 @@ class Iti {
1502
1451
  _scrollTo(element, middle) {
1503
1452
  const container = this.dropdownContent;
1504
1453
  // windowTop from https://stackoverflow.com/a/14384091/217866
1505
- const windowTop = window.pageYOffset || document.documentElement.scrollTop;
1454
+ const windowTop = document.documentElement.scrollTop;
1506
1455
  const containerHeight = container.offsetHeight;
1507
1456
  const containerTop = container.getBoundingClientRect().top + windowTop;
1508
1457
  const containerBottom = containerTop + containerHeight;
@@ -1595,7 +1544,7 @@ class Iti {
1595
1544
  return dialCode;
1596
1545
  }
1597
1546
 
1598
- // get the input val, adding the dial code if separateDialCode is enabled
1547
+ // get the input val, adding the dial code if showSelectedDialCode is enabled
1599
1548
  _getFullNumber() {
1600
1549
  const val = this.telInput.value.trim();
1601
1550
  const { dialCode } = this.selectedCountryData;
@@ -1603,12 +1552,12 @@ class Iti {
1603
1552
  const numericVal = this._getNumeric(val);
1604
1553
 
1605
1554
  if (
1606
- this.options.separateDialCode &&
1555
+ this.options.showSelectedDialCode &&
1607
1556
  val.charAt(0) !== "+" &&
1608
1557
  dialCode &&
1609
1558
  numericVal
1610
1559
  ) {
1611
- // when using separateDialCode, it is visible so is effectively part of the typed number
1560
+ // when using showSelectedDialCode, it is visible so is effectively part of the typed number
1612
1561
  prefix = `+${dialCode}`;
1613
1562
  } else {
1614
1563
  prefix = "";
@@ -1616,11 +1565,11 @@ class Iti {
1616
1565
  return prefix + val;
1617
1566
  }
1618
1567
 
1619
- // remove the dial code if separateDialCode is enabled
1568
+ // remove the dial code if showSelectedDialCode is enabled
1620
1569
  // also cap the length if the input has a maxlength attribute
1621
1570
  _beforeSetNumber(fullNumber) {
1622
1571
  let number = fullNumber;
1623
- if (this.options.separateDialCode) {
1572
+ if (this.options.showSelectedDialCode) {
1624
1573
  let dialCode = this._getDialCode(number);
1625
1574
  // if there is a valid dial code
1626
1575
  if (dialCode) {
@@ -1697,7 +1646,7 @@ class Iti {
1697
1646
  this._handleFlagsContainerKeydown
1698
1647
  );
1699
1648
  // label click hack
1700
- const label = this._getClosestLabel();
1649
+ const label = this.telInput.closest("label");
1701
1650
  if (label) {
1702
1651
  label.removeEventListener("click", this._handleLabelClick);
1703
1652
  }
@@ -1781,19 +1730,19 @@ class Iti {
1781
1730
  return -99;
1782
1731
  }
1783
1732
 
1784
- // validate the input val - assumes the global function isValidNumber (from utilsScript)
1733
+ // validate the input val - assumes the global function isPossibleNumber (from utilsScript)
1785
1734
  isValidNumber() {
1786
1735
  const val = this._getFullNumber().trim();
1787
1736
  return window.intlTelInputUtils
1788
- ? intlTelInputUtils.isValidNumber(val, this.selectedCountryData.iso2)
1737
+ ? intlTelInputUtils.isPossibleNumber(val, this.selectedCountryData.iso2)
1789
1738
  : null;
1790
1739
  }
1791
1740
 
1792
- // check if input val is possible number (weaker validation, but more future-proof) - assumes the global function isPossibleNumber (from utilsScript)
1793
- isPossibleNumber() {
1741
+ // validate the input val (precise) - assumes the global function isValidNumber (from utilsScript)
1742
+ isValidNumberPrecise() {
1794
1743
  const val = this._getFullNumber().trim();
1795
1744
  return window.intlTelInputUtils
1796
- ? intlTelInputUtils.isPossibleNumber(val, this.selectedCountryData.iso2)
1745
+ ? intlTelInputUtils.isValidNumber(val, this.selectedCountryData.iso2)
1797
1746
  : null;
1798
1747
  }
1799
1748
 
@@ -2,7 +2,8 @@ var input,
2
2
  iti,
3
3
  totalCountries = 244,
4
4
  totalDialCodes = 228,
5
- defaultPreferredCountries = 2;
5
+ defaultPreferredCountries = 0,
6
+ afghanistanDialCode = "+93";
6
7
 
7
8
  var intlSetup = function(utilsScript) {
8
9
  // by default put us in desktop mode
@@ -50,6 +51,16 @@ var getParentElement = function(i) {
50
51
  return i.parent();
51
52
  };
52
53
 
54
+ var getDropdownContent = function(i) {
55
+ i = i || input;
56
+ return i.parent().find(".iti__dropdown-content");
57
+ };
58
+
59
+ var getSearchInput = function(i) {
60
+ i = i || input;
61
+ return i.parent().find(".iti__search-input");
62
+ };
63
+
53
64
  var getListElement = function(i) {
54
65
  i = i || input;
55
66
  return i.parent().find(".iti__country-list");
@@ -111,29 +122,31 @@ var selectInputChars = function(start, end) {
111
122
 
112
123
  // use this for focus/blur (instead of using .focus() and .blur() directly, which cause problems in IE11)
113
124
  var triggerInputEvent = function(type) {
114
- var e = new CustomEvent(type);
125
+ var e = new Event(type);
115
126
  input[0].dispatchEvent(e);
116
127
  }
117
128
 
118
129
  var triggerKey = function(el, type, key) {
119
- var e = new CustomEvent(type);
120
- e.key = key;
130
+ var e = new KeyboardEvent(type, { key: key });
121
131
  el.dispatchEvent(e);
122
132
  };
123
133
 
124
134
  // trigger keydown, then keypress, then add the key, then keyup
125
- var triggerKeyOnInput = function(key) {
126
- triggerKey(input[0], 'keydown', key);
127
- triggerKey(input[0], 'keypress', key);
128
- var val = input.val();
129
- input.val(val + key);
130
- triggerKey(input[0], 'keyup', key);
135
+ var triggerKeyOnInput = function(key, customInput) {
136
+ const inputEl = customInput || input;
137
+ triggerKey(inputEl[0], 'keydown', key);
138
+ triggerKey(inputEl[0], 'keypress', key);
139
+ var previousVal = inputEl.val();
140
+ inputEl.val(previousVal + key);
141
+ triggerKey(inputEl[0], 'keyup', key);
142
+ triggerKey(inputEl[0], 'input', key);
131
143
  };
132
144
 
133
145
  var triggerKeyOnBody = function(key) {
134
146
  triggerKey(document, 'keydown', key);
135
147
  triggerKey(document, 'keypress', key);
136
148
  triggerKey(document, 'keyup', key);
149
+ triggerKey(document, 'input', key);
137
150
  };
138
151
 
139
152
  var triggerKeyOnFlagsContainerElement = function(key) {
@@ -35,7 +35,7 @@ describe("countrychange event:", function() {
35
35
  });
36
36
 
37
37
  it("selecting another country triggers the event", function() {
38
- selectFlag("af");
38
+ selectFlag("gb");
39
39
  expect(spy).toHaveBeenTriggered();
40
40
  });
41
41
 
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
 
3
- describe("dropdown shortcuts: init plugin (with nationalMode=false, autoInsertDialCode=true) to test keyboard shortcuts", function() {
3
+ describe("dropdown shortcuts: init plugin (with countrySearch=false, nationalMode=false, autoInsertDialCode=true) to test keyboard shortcuts", function() {
4
4
 
5
5
  beforeEach(function() {
6
6
  intlSetup();
7
7
  input = $("<input>").appendTo("body");
8
8
  iti = window.intlTelInput(input[0], {
9
+ countrySearch: false,
9
10
  nationalMode: false,
10
11
  autoInsertDialCode: true,
11
12
  });
@@ -138,7 +139,7 @@ describe("dropdown shortcuts: init plugin (with nationalMode=false, autoInsertDi
138
139
  });
139
140
 
140
141
  it("updates the dial code", function() {
141
- expect(getInputVal()).toEqual("+44");
142
+ expect(getInputVal()).toEqual("+355");
142
143
  });
143
144
 
144
145
  });
@@ -25,14 +25,13 @@ describe("initial values:", function() {
25
25
 
26
26
  it("has the right number of list items", function() {
27
27
  expect(getListLength()).toEqual(totalCountries + defaultPreferredCountries);
28
- expect(getPreferredCountriesLength()).toEqual(defaultPreferredCountries);
29
28
  // only 1 active list item
30
29
  expect(getActiveListItem().length).toEqual(1);
31
30
  });
32
31
 
33
32
  it("sets the state correctly: selected flag and active list item", function() {
34
- expect(getSelectedFlagElement()).toHaveClass("iti__us");
35
- expect(getActiveListItem().attr("data-country-code")).toEqual("us");
33
+ expect(getSelectedFlagElement()).toHaveClass("iti__af");
34
+ expect(getActiveListItem().attr("data-country-code")).toEqual("af");
36
35
  });
37
36
 
38
37
  });
@@ -13,7 +13,7 @@ describe("getSelectedCountryData: init plugin to test public method getSelectedC
13
13
  });
14
14
 
15
15
  it("gets the right default country data", function() {
16
- expect(iti.getSelectedCountryData().iso2).toEqual("us");
16
+ expect(iti.getSelectedCountryData().iso2).toEqual("af");
17
17
  });
18
18
 
19
19
  it("change country by number gets the right country data", function() {