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.
- package/.eslintrc +2 -8
- package/.vscode/settings.json +8 -0
- package/CHANGELOG.md +3 -0
- package/Gruntfile.js +0 -2
- package/README.md +24 -30
- package/build/css/intlTelInput.css +1 -1
- package/build/js/data.js +1 -1
- package/build/js/data.min.js +1 -1
- package/build/js/intlTelInput-jquery.js +213 -89
- package/build/js/intlTelInput-jquery.min.js +3 -3
- package/build/js/intlTelInput.js +213 -89
- package/build/js/intlTelInput.min.js +3 -3
- package/composer.json +1 -1
- package/demo.html +42 -43
- package/demo_rtl.html +21 -23
- package/grunt/template.js +2 -265
- package/package.json +4 -1
- package/src/css/intlTelInput.scss +1 -1
- package/src/js/intlTelInput.js +605 -341
- package/examples/css/countrySync.css +0 -10
- package/examples/css/isValidNumber.css +0 -12
- package/examples/css/prism.css +0 -126
- package/examples/gen/country-sync.html +0 -98
- package/examples/gen/default-country-ip.html +0 -62
- package/examples/gen/display-number.html +0 -47
- package/examples/gen/hidden-input.html +0 -54
- package/examples/gen/init-promise.html +0 -66
- package/examples/gen/is-valid-number.html +0 -86
- package/examples/gen/js/countrySync.js +0 -31
- package/examples/gen/js/defaultCountryIp.js +0 -11
- package/examples/gen/js/displayNumber.js +0 -4
- package/examples/gen/js/hiddenInput.js +0 -5
- package/examples/gen/js/initPromise.js +0 -9
- package/examples/gen/js/isValidNumber.js +0 -37
- package/examples/gen/js/modifyCountryData.js +0 -11
- package/examples/gen/js/multipleInstances.js +0 -13
- package/examples/gen/js/nationalMode.js +0 -18
- package/examples/gen/js/onlyCountriesEurope.js +0 -8
- package/examples/gen/modify-country-data.html +0 -52
- package/examples/gen/multiple-instances.html +0 -60
- package/examples/gen/national-mode.html +0 -63
- package/examples/gen/only-countries-europe.html +0 -49
- package/examples/js/countrySync.js.ejs +0 -31
- package/examples/js/defaultCountryIp.js.ejs +0 -11
- package/examples/js/displayNumber.js.ejs +0 -4
- package/examples/js/hiddenInput.js.ejs +0 -5
- package/examples/js/initPromise.js.ejs +0 -9
- package/examples/js/isValidNumber.js.ejs +0 -37
- package/examples/js/modifyCountryData.js.ejs +0 -11
- package/examples/js/multipleInstances.js.ejs +0 -13
- package/examples/js/nationalMode.js.ejs +0 -18
- package/examples/js/onlyCountriesEurope.js.ejs +0 -8
- package/examples/js/prism.js +0 -11
- package/examples/partials/countrySync.html +0 -13
- package/examples/partials/defaultCountryIp.html +0 -5
- package/examples/partials/displayNumber.html +0 -1
- package/examples/partials/hiddenInput.html +0 -4
- package/examples/partials/initPromise.html +0 -8
- package/examples/partials/isValidNumber.html +0 -3
- package/examples/partials/multipleInstances.html +0 -3
- package/examples/partials/nationalMode.html +0 -2
- package/examples/partials/simpleInput.html +0 -1
- package/examples/template.html.ejs +0 -43
package/src/js/intlTelInput.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
const intlTelInputGlobals = {
|
|
2
2
|
getInstance: (input) => {
|
|
3
|
-
const id = input.getAttribute(
|
|
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 ===
|
|
8
|
+
documentReady: () => document.readyState === "complete"
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
if (typeof window ===
|
|
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:
|
|
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
|
-
//
|
|
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:
|
|
48
|
+
placeholderNumberType: "MOBILE",
|
|
47
49
|
// the countries at the top of the list. defaults to united states and united kingdom
|
|
48
|
-
preferredCountries: [
|
|
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 = [
|
|
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] =
|
|
110
|
+
this.options[key] = customOptions.hasOwnProperty(key)
|
|
111
|
+
? customOptions[key]
|
|
112
|
+
: value;
|
|
92
113
|
});
|
|
93
114
|
|
|
94
|
-
this.hadInitialPlaceholder = Boolean(input.getAttribute(
|
|
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)
|
|
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)
|
|
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 =
|
|
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(
|
|
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)
|
|
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 !==
|
|
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)
|
|
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)
|
|
233
|
+
if (this.countryCodes[countryCode][i] === iso2) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
197
236
|
}
|
|
198
237
|
// check for undefined as 0 is falsy
|
|
199
|
-
const index =
|
|
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
|
|
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)
|
|
238
|
-
|
|
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])
|
|
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)
|
|
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)
|
|
301
|
-
|
|
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
|
|
312
|
-
if (
|
|
313
|
-
this.telInput.
|
|
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 =
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
parentClass +=
|
|
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(
|
|
390
|
+
const wrapper = this._createEl("div", { class: parentClass });
|
|
326
391
|
this.telInput.parentNode.insertBefore(wrapper, this.telInput);
|
|
327
|
-
|
|
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
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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.
|
|
351
|
-
this.
|
|
431
|
+
if (this.selectedFlag && this.telInput.disabled) {
|
|
432
|
+
this.selectedFlag.setAttribute("aria-disabled", "true");
|
|
352
433
|
}
|
|
353
434
|
|
|
354
|
-
if (
|
|
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(
|
|
446
|
+
this.selectedFlag.setAttribute("tabindex", "0");
|
|
358
447
|
}
|
|
359
448
|
|
|
360
|
-
this.dropdownArrow = this._createEl(
|
|
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(
|
|
364
|
-
class:
|
|
456
|
+
this.countryList = this._createEl("ul", {
|
|
457
|
+
class: "iti__country-list iti__hide",
|
|
365
458
|
id: `iti-${this.id}__country-listbox`,
|
|
366
|
-
role:
|
|
367
|
-
|
|
459
|
+
role: "listbox",
|
|
460
|
+
"aria-label": "List of countries"
|
|
368
461
|
});
|
|
369
462
|
if (this.preferredCountries.length) {
|
|
370
|
-
this._appendListItems(this.preferredCountries,
|
|
371
|
-
this._createEl(
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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,
|
|
474
|
+
this._appendListItems(this.countries, "iti__standard");
|
|
378
475
|
|
|
379
476
|
// create dropdownContainer markup
|
|
380
|
-
if (
|
|
381
|
-
this.dropdown = this._createEl(
|
|
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 (
|
|
389
|
-
let hiddenInputName =
|
|
390
|
-
const name = this.telInput.getAttribute(
|
|
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)
|
|
492
|
+
if (i !== -1) {
|
|
493
|
+
hiddenInputName = `${name.substr(0, i)}[${hiddenInputName}]`;
|
|
494
|
+
}
|
|
396
495
|
}
|
|
397
|
-
this.hiddenInput = this._createEl(
|
|
398
|
-
type:
|
|
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 ?
|
|
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
|
-
|
|
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 +=
|
|
523
|
+
tmp += "</li>";
|
|
424
524
|
}
|
|
425
|
-
this.countryList.insertAdjacentHTML(
|
|
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(
|
|
537
|
+
const attributeValue = this.telInput.getAttribute("value");
|
|
439
538
|
const inputValue = this.telInput.value;
|
|
440
|
-
const useAttribute =
|
|
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 !==
|
|
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(
|
|
559
|
+
this._setFlag("us");
|
|
461
560
|
} else {
|
|
462
561
|
// no dial code and no initialCountry, so default to first in list
|
|
463
|
-
this.defaultCountry =
|
|
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)
|
|
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)
|
|
487
|
-
|
|
488
|
-
|
|
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)
|
|
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 !==
|
|
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(
|
|
517
|
-
|
|
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)
|
|
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 (
|
|
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(
|
|
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(
|
|
655
|
+
const isDropdownHidden = this.countryList.classList.contains("iti__hide");
|
|
536
656
|
|
|
537
|
-
if (
|
|
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 ===
|
|
670
|
+
if (e.key === "Tab") {
|
|
671
|
+
this._closeDropdown();
|
|
672
|
+
}
|
|
547
673
|
};
|
|
548
|
-
this.flagsContainer.addEventListener(
|
|
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(
|
|
689
|
+
window.addEventListener("load", () => {
|
|
562
690
|
window.intlTelInputGlobals.loadUtils(this.options.utilsScript);
|
|
563
691
|
});
|
|
564
692
|
}
|
|
565
|
-
} else
|
|
693
|
+
} else {
|
|
694
|
+
this.resolveUtilsScriptPromise();
|
|
695
|
+
}
|
|
566
696
|
|
|
567
|
-
if (this.options.initialCountry ===
|
|
568
|
-
|
|
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 ===
|
|
585
|
-
this.options.geoIpLookup(
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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(
|
|
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(
|
|
616
|
-
this.telInput.addEventListener(
|
|
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(
|
|
623
|
-
return
|
|
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)
|
|
634
|
-
|
|
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(
|
|
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(
|
|
672
|
-
this.selectedFlag.setAttribute(
|
|
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(
|
|
819
|
+
this.dropdownArrow.classList.add("iti__arrow--up");
|
|
687
820
|
|
|
688
|
-
this._trigger(
|
|
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))
|
|
695
|
-
|
|
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 =
|
|
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 =
|
|
713
|
-
|
|
714
|
-
|
|
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(
|
|
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 =
|
|
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(
|
|
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 (
|
|
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
|
|
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)
|
|
901
|
+
if (listItem) {
|
|
902
|
+
this._highlightListItem(listItem, false);
|
|
903
|
+
}
|
|
755
904
|
};
|
|
756
|
-
this.countryList.addEventListener(
|
|
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)
|
|
913
|
+
if (listItem) {
|
|
914
|
+
this._selectListItem(listItem);
|
|
915
|
+
}
|
|
762
916
|
};
|
|
763
|
-
this.countryList.addEventListener(
|
|
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)
|
|
924
|
+
if (!isOpening) {
|
|
925
|
+
this._closeDropdown();
|
|
926
|
+
}
|
|
771
927
|
isOpening = false;
|
|
772
928
|
};
|
|
773
|
-
document.documentElement.addEventListener(
|
|
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 (
|
|
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 ===
|
|
955
|
+
else if (e.key === "Enter") {
|
|
956
|
+
this._handleEnterKey();
|
|
957
|
+
}
|
|
790
958
|
// esc to close
|
|
791
|
-
else if (e.key ===
|
|
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)
|
|
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(
|
|
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 =
|
|
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(
|
|
815
|
-
next =
|
|
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)
|
|
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(
|
|
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
|
|
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 (
|
|
853
|
-
|
|
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(
|
|
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
|
|
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 =
|
|
875
|
-
if (number &&
|
|
876
|
-
if (number.charAt(0) !==
|
|
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 (
|
|
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 =
|
|
896
|
-
|
|
897
|
-
|
|
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) ===
|
|
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) ===
|
|
1127
|
+
if (numeric.charAt(0) === "1") {
|
|
935
1128
|
const areaCode = numeric.substr(1, 3);
|
|
936
|
-
return
|
|
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)
|
|
1137
|
+
if (prevItem) {
|
|
1138
|
+
prevItem.classList.remove("iti__highlight");
|
|
1139
|
+
}
|
|
946
1140
|
this.highlightedItem = listItem;
|
|
947
|
-
this.highlightedItem.classList.add(
|
|
948
|
-
this.selectedFlag.setAttribute(
|
|
949
|
-
|
|
950
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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.
|
|
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
|
-
|
|
985
|
-
|
|
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
|
|
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 =
|
|
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(
|
|
1005
|
-
prevItem.setAttribute(
|
|
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 =
|
|
1010
|
-
|
|
1011
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1047
|
-
|
|
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 ===
|
|
1051
|
-
placeholder = this.options.customPlaceholder(
|
|
1281
|
+
if (typeof this.options.customPlaceholder === "function") {
|
|
1282
|
+
placeholder = this.options.customPlaceholder(
|
|
1283
|
+
placeholder,
|
|
1284
|
+
this.selectedCountryData
|
|
1285
|
+
);
|
|
1052
1286
|
}
|
|
1053
|
-
this.telInput.setAttribute(
|
|
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(
|
|
1294
|
+
const flagChanged = this._setFlag(
|
|
1295
|
+
listItem.getAttribute("data-country-code")
|
|
1296
|
+
);
|
|
1062
1297
|
this._closeDropdown();
|
|
1063
1298
|
|
|
1064
|
-
this._updateDialCode(listItem.getAttribute(
|
|
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
|
|
1069
|
-
//
|
|
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(
|
|
1082
|
-
this.selectedFlag.setAttribute(
|
|
1083
|
-
this.selectedFlag.removeAttribute(
|
|
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(
|
|
1320
|
+
this.dropdownArrow.classList.remove("iti__arrow--up");
|
|
1087
1321
|
|
|
1088
1322
|
// unbind key events
|
|
1089
|
-
document.removeEventListener(
|
|
1090
|
-
document.documentElement.removeEventListener(
|
|
1091
|
-
|
|
1092
|
-
|
|
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)
|
|
1097
|
-
|
|
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(
|
|
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 =
|
|
1359
|
+
const middleOffset = containerHeight / 2 - elementHeight / 2;
|
|
1117
1360
|
|
|
1118
1361
|
if (elementTop < containerTop) {
|
|
1119
1362
|
// scroll up
|
|
1120
|
-
if (middle)
|
|
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)
|
|
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
|
|
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 (
|
|
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 =
|
|
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(
|
|
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 ===
|
|
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(
|
|
1293
|
-
|
|
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)
|
|
1547
|
+
if (label) {
|
|
1548
|
+
label.removeEventListener("click", this._handleLabelClick);
|
|
1549
|
+
}
|
|
1297
1550
|
}
|
|
1298
1551
|
|
|
1299
1552
|
// unbind hiddenInput listeners
|
|
1300
|
-
if (this.hiddenInput && form)
|
|
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)
|
|
1305
|
-
|
|
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(
|
|
1310
|
-
this.telInput.removeEventListener(
|
|
1311
|
-
this.telInput.removeEventListener(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
1373
|
-
|
|
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 (
|
|
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(
|
|
1677
|
+
const script = document.createElement("script");
|
|
1421
1678
|
script.onload = () => {
|
|
1422
|
-
forEachInstance(
|
|
1423
|
-
if (handleSuccess)
|
|
1679
|
+
forEachInstance("handleUtils");
|
|
1680
|
+
if (handleSuccess) {
|
|
1681
|
+
handleSuccess();
|
|
1682
|
+
}
|
|
1424
1683
|
};
|
|
1425
1684
|
script.onerror = () => {
|
|
1426
|
-
forEachInstance(
|
|
1427
|
-
if (handleFailure)
|
|
1685
|
+
forEachInstance("rejectUtilsScriptPromise");
|
|
1686
|
+
if (handleFailure) {
|
|
1687
|
+
handleFailure();
|
|
1688
|
+
}
|
|
1428
1689
|
};
|
|
1429
|
-
script.className =
|
|
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 (
|
|
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 !==
|
|
1448
|
-
return new Promise((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 =
|
|
1724
|
+
intlTelInputGlobals.version = "<%= version %>";
|