intl-tel-input 18.5.3 → 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 +158 -151
  7. package/build/js/intlTelInput-jquery.min.js +3 -3
  8. package/build/js/intlTelInput.js +158 -151
  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 +76 -125
  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,20 +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 (customContainer) {
404
- parentClass += ` ${customContainer}`;
383
+ if (containerClass) {
384
+ parentClass += ` ${containerClass}`;
385
+ }
386
+ if (!useFullscreenPopup) {
387
+ parentClass += " iti--inline-dropdown";
405
388
  }
406
389
 
407
390
  const wrapper = this._createEl("div", { class: parentClass });
408
391
  this.telInput.parentNode.insertBefore(wrapper, this.telInput);
409
- // only hide the flagsContainer if allowDropdown, showFlags and separateDialCode are all false
410
- const showFlagsContainer = allowDropdown || showFlags || separateDialCode;
392
+ // only hide the flagsContainer if allowDropdown, showFlags and showSelectedDialCode are all false
393
+ const showFlagsContainer = allowDropdown || showFlags || showSelectedDialCode;
411
394
  if (showFlagsContainer) {
412
395
  this.flagsContainer = this._createEl(
413
396
  "div",
@@ -430,7 +413,7 @@ class Iti {
430
413
  "aria-haspopup": "listbox",
431
414
  "aria-controls": `iti-${this.id}__country-listbox`,
432
415
  "aria-expanded": "false",
433
- "aria-label": "Telephone country code"
416
+ "aria-label": this.options.i18n.selectedCountryAriaLabel || "Selected country"
434
417
  })
435
418
  },
436
419
  this.flagsContainer
@@ -448,7 +431,7 @@ class Iti {
448
431
  this.selectedFlag.setAttribute("aria-disabled", "true");
449
432
  }
450
433
 
451
- if (separateDialCode) {
434
+ if (showSelectedDialCode) {
452
435
  this.selectedDialCode = this._createEl(
453
436
  "div",
454
437
  { class: "iti__selected-dial-code" },
@@ -479,7 +462,7 @@ class Iti {
479
462
  {
480
463
  type: "text",
481
464
  class: "iti__search-input",
482
- placeholder: "Search"
465
+ placeholder: this.options.i18n.searchPlaceholder || "Search"
483
466
  },
484
467
  this.dropdownContent
485
468
  );
@@ -492,7 +475,7 @@ class Iti {
492
475
  class: "iti__country-list",
493
476
  id: `iti-${this.id}__country-listbox`,
494
477
  role: "listbox",
495
- "aria-label": "List of countries"
478
+ "aria-label": this.options.i18n.countryListAriaLabel || "List of countries"
496
479
  },
497
480
  this.dropdownContent
498
481
  );
@@ -514,6 +497,8 @@ class Iti {
514
497
  let dropdownClasses = "iti iti--container";
515
498
  if (useFullscreenPopup) {
516
499
  dropdownClasses += " iti--fullscreen-popup";
500
+ } else {
501
+ dropdownClasses += " iti--inline-dropdown";
517
502
  }
518
503
  if (countrySearch) {
519
504
  dropdownClasses += " iti--country-search";
@@ -526,16 +511,8 @@ class Iti {
526
511
  }
527
512
 
528
513
  if (hiddenInput) {
529
- let hiddenInputName = hiddenInput;
530
- const name = this.telInput.getAttribute("name");
531
- if (name) {
532
- const i = name.lastIndexOf("[");
533
- // if input name contains square brackets, then give the hidden input the same name,
534
- // replacing the contents of the last set of brackets with the given hiddenInput name
535
- if (i !== -1) {
536
- hiddenInputName = `${name.substr(0, i)}[${hiddenInputName}]`;
537
- }
538
- }
514
+ const telInputName = this.telInput.getAttribute("name");
515
+ const hiddenInputName = hiddenInput(telInputName);
539
516
  this.hiddenInput = this._createEl("input", {
540
517
  type: "hidden",
541
518
  name: hiddenInputName
@@ -663,15 +640,6 @@ class Iti {
663
640
  }
664
641
  }
665
642
 
666
- // iterate through parent nodes to find the closest label ancestor, if it exists
667
- _getClosestLabel() {
668
- let el = this.telInput;
669
- while (el && el.tagName !== "LABEL") {
670
- el = el.parentNode;
671
- }
672
- return el;
673
- }
674
-
675
643
  // initialise the dropdown listeners
676
644
  _initDropdownListeners() {
677
645
  // hack for input nested inside label (which is valid markup): clicking the selected-flag to
@@ -685,7 +653,7 @@ class Iti {
685
653
  e.preventDefault();
686
654
  }
687
655
  };
688
- const label = this._getClosestLabel();
656
+ const label = this.telInput.closest("label");
689
657
  if (label) {
690
658
  label.addEventListener("click", this._handleLabelClick);
691
659
  }
@@ -848,9 +816,10 @@ class Iti {
848
816
 
849
817
  // trigger a custom event on the input
850
818
  _trigger(name) {
851
- // have to use old school document.createEvent as IE11 doesn't support `new Event()` syntax
852
- const e = document.createEvent("Event");
853
- e.initEvent(name, true, true); // can bubble, and is cancellable
819
+ const e = new Event(name, {
820
+ bubbles: true,
821
+ cancelable: true
822
+ });
854
823
  this.telInput.dispatchEvent(e);
855
824
  }
856
825
 
@@ -892,7 +861,7 @@ class Iti {
892
861
  }
893
862
  }
894
863
 
895
- // 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)
896
865
  _setDropdownPosition() {
897
866
  if (this.options.dropdownContainer) {
898
867
  this.options.dropdownContainer.appendChild(this.dropdown);
@@ -901,8 +870,7 @@ class Iti {
901
870
  if (!this.options.useFullscreenPopup) {
902
871
  const pos = this.telInput.getBoundingClientRect();
903
872
  // windowTop from https://stackoverflow.com/a/14384091/217866
904
- const windowTop =
905
- window.pageYOffset || document.documentElement.scrollTop;
873
+ const windowTop = document.documentElement.scrollTop;
906
874
  const inputTop = pos.top + windowTop;
907
875
  const dropdownHeight = this.dropdownContent.offsetHeight;
908
876
  // dropdownFitsBelow = (dropdownBottom < windowBottom)
@@ -941,27 +909,13 @@ class Iti {
941
909
  }
942
910
  }
943
911
 
944
- // iterate through parent nodes to find the closest list item
945
- _getClosestListItem(target) {
946
- let el = target;
947
- while (
948
- el &&
949
- el !== this.countryList &&
950
- !el.classList.contains("iti__country")
951
- ) {
952
- el = el.parentNode;
953
- }
954
- // if we reached the countryList element, then return null
955
- return el === this.countryList ? null : el;
956
- }
957
-
958
912
  // we only bind dropdown listeners when the dropdown is open
959
913
  _bindDropdownListeners() {
960
914
  // when mouse over a list item, just highlight that one
961
915
  // we add the class "highlight", so if they hit "enter" we know which one to select
962
916
  this._handleMouseoverCountryList = (e) => {
963
917
  // handle event delegation, as we're listening for this event on the countryList
964
- const listItem = this._getClosestListItem(e.target);
918
+ const listItem = e.target.closest(".iti__country");
965
919
  if (listItem) {
966
920
  this._highlightListItem(listItem, false);
967
921
  }
@@ -973,7 +927,7 @@ class Iti {
973
927
 
974
928
  // listen for country selection
975
929
  this._handleClickCountryList = (e) => {
976
- const listItem = this._getClosestListItem(e.target);
930
+ const listItem = e.target.closest(".iti__country");
977
931
  if (listItem) {
978
932
  this._selectListItem(listItem);
979
933
  }
@@ -1078,7 +1032,8 @@ class Iti {
1078
1032
  if (
1079
1033
  isReset ||
1080
1034
  nameLower.includes(query) ||
1081
- fullDialCode.includes(query)
1035
+ fullDialCode.includes(query) ||
1036
+ c.iso2.includes(query)
1082
1037
  ) {
1083
1038
  this.countryList.appendChild(c.node);
1084
1039
  // highlight the first item
@@ -1157,7 +1112,7 @@ class Iti {
1157
1112
  ) {
1158
1113
  const useNational =
1159
1114
  this.options.nationalMode ||
1160
- (number.charAt(0) !== "+" && !this.options.separateDialCode);
1115
+ (number.charAt(0) !== "+" && !this.options.showSelectedDialCode);
1161
1116
  const { NATIONAL, INTERNATIONAL } = intlTelInputUtils.numberFormat;
1162
1117
  const format = useNational ? NATIONAL : INTERNATIONAL;
1163
1118
  number = intlTelInputUtils.formatNumber(
@@ -1194,9 +1149,9 @@ class Iti {
1194
1149
  number = `+${number}`;
1195
1150
  }
1196
1151
 
1197
- // 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
1198
1153
  if (
1199
- this.options.separateDialCode &&
1154
+ this.options.showSelectedDialCode &&
1200
1155
  selectedDialCode &&
1201
1156
  number.charAt(0) !== "+"
1202
1157
  ) {
@@ -1298,7 +1253,7 @@ class Iti {
1298
1253
  // select the given flag, update the placeholder, title, and the active list item
1299
1254
  // Note: called from _setInitialState, _updateFlagFromNumber, _selectListItem, setCountry
1300
1255
  _setFlag(countryCode) {
1301
- const { allowDropdown, separateDialCode, showFlags } = this.options;
1256
+ const { allowDropdown, showSelectedDialCode, showFlags } = this.options;
1302
1257
 
1303
1258
  const prevCountry = this.selectedCountryData.iso2
1304
1259
  ? this.selectedCountryData
@@ -1320,9 +1275,9 @@ class Iti {
1320
1275
  );
1321
1276
  }
1322
1277
 
1323
- this._setSelectedCountryFlagTitleAttribute(countryCode, separateDialCode);
1278
+ this._setSelectedCountryFlagTitleAttribute(countryCode, showSelectedDialCode);
1324
1279
 
1325
- if (separateDialCode) {
1280
+ if (showSelectedDialCode) {
1326
1281
  const dialCode = this.selectedCountryData.dialCode
1327
1282
  ? `+${this.selectedCountryData.dialCode}`
1328
1283
  : "";
@@ -1368,13 +1323,13 @@ class Iti {
1368
1323
  return prevCountry.iso2 !== countryCode;
1369
1324
  }
1370
1325
 
1371
- _setSelectedCountryFlagTitleAttribute(countryCode, separateDialCode) {
1326
+ _setSelectedCountryFlagTitleAttribute(countryCode, showSelectedDialCode) {
1372
1327
  if (!this.selectedFlag) {
1373
1328
  return;
1374
1329
  }
1375
1330
 
1376
1331
  let title;
1377
- if (countryCode && !separateDialCode) {
1332
+ if (countryCode && !showSelectedDialCode) {
1378
1333
  title = `${this.selectedCountryData.name}: +${this.selectedCountryData.dialCode}`;
1379
1334
  } else if (countryCode) {
1380
1335
  // For screen reader output, we don't want to include the dial code in the reader output twice
@@ -1389,7 +1344,7 @@ class Iti {
1389
1344
 
1390
1345
  // when the input is in a hidden container during initialisation, we must inject some markup
1391
1346
  // into the end of the DOM to calculate the correct offsetWidth
1392
- // 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
1393
1348
  // will definitely exist
1394
1349
  _getHiddenSelectedFlagWidth() {
1395
1350
  // to get the right styling to apply, all we need is a shallow clone of the container,
@@ -1449,10 +1404,6 @@ class Iti {
1449
1404
 
1450
1405
  // focus the input
1451
1406
  this.telInput.focus();
1452
- // put cursor at end - this fix is required for FF and IE11 (with auto inserting dial code),
1453
- // who try to put the cursor at the beginning the first time
1454
- const len = this.telInput.value.length;
1455
- this.telInput.setSelectionRange(len, len);
1456
1407
 
1457
1408
  if (flagChanged) {
1458
1409
  this._triggerCountryChange();
@@ -1500,7 +1451,7 @@ class Iti {
1500
1451
  _scrollTo(element, middle) {
1501
1452
  const container = this.dropdownContent;
1502
1453
  // windowTop from https://stackoverflow.com/a/14384091/217866
1503
- const windowTop = window.pageYOffset || document.documentElement.scrollTop;
1454
+ const windowTop = document.documentElement.scrollTop;
1504
1455
  const containerHeight = container.offsetHeight;
1505
1456
  const containerTop = container.getBoundingClientRect().top + windowTop;
1506
1457
  const containerBottom = containerTop + containerHeight;
@@ -1593,7 +1544,7 @@ class Iti {
1593
1544
  return dialCode;
1594
1545
  }
1595
1546
 
1596
- // 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
1597
1548
  _getFullNumber() {
1598
1549
  const val = this.telInput.value.trim();
1599
1550
  const { dialCode } = this.selectedCountryData;
@@ -1601,12 +1552,12 @@ class Iti {
1601
1552
  const numericVal = this._getNumeric(val);
1602
1553
 
1603
1554
  if (
1604
- this.options.separateDialCode &&
1555
+ this.options.showSelectedDialCode &&
1605
1556
  val.charAt(0) !== "+" &&
1606
1557
  dialCode &&
1607
1558
  numericVal
1608
1559
  ) {
1609
- // 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
1610
1561
  prefix = `+${dialCode}`;
1611
1562
  } else {
1612
1563
  prefix = "";
@@ -1614,11 +1565,11 @@ class Iti {
1614
1565
  return prefix + val;
1615
1566
  }
1616
1567
 
1617
- // remove the dial code if separateDialCode is enabled
1568
+ // remove the dial code if showSelectedDialCode is enabled
1618
1569
  // also cap the length if the input has a maxlength attribute
1619
1570
  _beforeSetNumber(fullNumber) {
1620
1571
  let number = fullNumber;
1621
- if (this.options.separateDialCode) {
1572
+ if (this.options.showSelectedDialCode) {
1622
1573
  let dialCode = this._getDialCode(number);
1623
1574
  // if there is a valid dial code
1624
1575
  if (dialCode) {
@@ -1695,7 +1646,7 @@ class Iti {
1695
1646
  this._handleFlagsContainerKeydown
1696
1647
  );
1697
1648
  // label click hack
1698
- const label = this._getClosestLabel();
1649
+ const label = this.telInput.closest("label");
1699
1650
  if (label) {
1700
1651
  label.removeEventListener("click", this._handleLabelClick);
1701
1652
  }
@@ -1779,19 +1730,19 @@ class Iti {
1779
1730
  return -99;
1780
1731
  }
1781
1732
 
1782
- // validate the input val - assumes the global function isValidNumber (from utilsScript)
1733
+ // validate the input val - assumes the global function isPossibleNumber (from utilsScript)
1783
1734
  isValidNumber() {
1784
1735
  const val = this._getFullNumber().trim();
1785
1736
  return window.intlTelInputUtils
1786
- ? intlTelInputUtils.isValidNumber(val, this.selectedCountryData.iso2)
1737
+ ? intlTelInputUtils.isPossibleNumber(val, this.selectedCountryData.iso2)
1787
1738
  : null;
1788
1739
  }
1789
1740
 
1790
- // check if input val is possible number (weaker validation, but more future-proof) - assumes the global function isPossibleNumber (from utilsScript)
1791
- isPossibleNumber() {
1741
+ // validate the input val (precise) - assumes the global function isValidNumber (from utilsScript)
1742
+ isValidNumberPrecise() {
1792
1743
  const val = this._getFullNumber().trim();
1793
1744
  return window.intlTelInputUtils
1794
- ? intlTelInputUtils.isPossibleNumber(val, this.selectedCountryData.iso2)
1745
+ ? intlTelInputUtils.isValidNumber(val, this.selectedCountryData.iso2)
1795
1746
  : null;
1796
1747
  }
1797
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() {