/phone/intl-tel-input-master/build/js/intlTelInput.js

https://github.com/leapinglangoor/plivo-sample-apps · JavaScript · 1953 lines · 1720 code · 0 blank · 233 comment · 99 complexity · 2ae9b0d344f46eab851aa5dfd0afdccd MD5 · raw file

Large files are truncated click here to view the full file

  1. /*
  2. International Telephone Input v1.1.12
  3. https://github.com/Bluefieldscom/intl-tel-input.git
  4. */
  5. // wrap in UMD - see https://github.com/umdjs/umd/blob/master/jqueryPlugin.js
  6. (function(factory) {
  7. if (typeof define === "function" && define.amd) {
  8. define([ "jquery" ], function($) {
  9. factory($, window, document);
  10. });
  11. } else {
  12. factory(jQuery, window, document);
  13. }
  14. })(function($, window, document, undefined) {
  15. "use strict";
  16. var pluginName = "intlTelInput", id = 1, // give each instance it's own id for namespaced event handling
  17. defaults = {
  18. // don't insert international dial codes
  19. nationalMode: false,
  20. // if there is just a dial code in the input: remove it on blur, and re-add it on focus
  21. autoHideDialCode: true,
  22. // default country
  23. defaultCountry: "",
  24. // character to appear between dial code and phone number
  25. dialCodeDelimiter: " ",
  26. // position the selected flag inside or outside of the input
  27. defaultStyling: "inside",
  28. // display only these countries
  29. onlyCountries: [],
  30. // the countries at the top of the list. defaults to united states and united kingdom
  31. preferredCountries: [ "us", "gb" ],
  32. // specify the path to the libphonenumber script to enable validation
  33. validationScript: ""
  34. }, keys = {
  35. UP: 38,
  36. DOWN: 40,
  37. ENTER: 13,
  38. ESC: 27,
  39. PLUS: 43,
  40. A: 65,
  41. Z: 90
  42. }, windowLoaded = false;
  43. // keep track of if the window.load event has fired as impossible to check after the fact
  44. $(window).load(function() {
  45. windowLoaded = true;
  46. });
  47. function Plugin(element, options) {
  48. this.element = element;
  49. this.options = $.extend({}, defaults, options);
  50. this._defaults = defaults;
  51. // event namespace
  52. this.ns = "." + pluginName + id++;
  53. this._name = pluginName;
  54. this.init();
  55. }
  56. Plugin.prototype = {
  57. init: function() {
  58. // process all the data: onlyCounties, preferredCountries, defaultCountry etc
  59. this._processCountryData();
  60. // generate the markup
  61. this._generateMarkup();
  62. // set the initial state of the input value and the selected flag
  63. this._setInitialState();
  64. // start all of the event listeners: autoHideDialCode, input keyup, selectedFlag click
  65. this._initListeners();
  66. },
  67. /********************
  68. * PRIVATE METHODS
  69. ********************/
  70. // prepare all of the country data, including onlyCountries, preferredCountries and
  71. // defaultCountry options
  72. _processCountryData: function() {
  73. // set the instances country data objects
  74. this._setInstanceCountryData();
  75. // set the preferredCountries property
  76. this._setPreferredCountries();
  77. },
  78. // process onlyCountries array if present
  79. _setInstanceCountryData: function() {
  80. var that = this;
  81. if (this.options.onlyCountries.length) {
  82. var newCountries = [], newCountryCodes = {};
  83. $.each(this.options.onlyCountries, function(i, countryCode) {
  84. var countryData = that._getCountryData(countryCode, true);
  85. if (countryData) {
  86. newCountries.push(countryData);
  87. // add this country's dial code to the countryCodes
  88. var dialCode = countryData.dialCode;
  89. if (newCountryCodes[dialCode]) {
  90. newCountryCodes[dialCode].push(countryCode);
  91. } else {
  92. newCountryCodes[dialCode] = [ countryCode ];
  93. }
  94. }
  95. });
  96. // maintain country priority
  97. for (var dialCode in newCountryCodes) {
  98. if (newCountryCodes[dialCode].length > 1) {
  99. var sortedCountries = [];
  100. // go through all of the allCountryCodes countries for this dialCode and create a new (ordered) array of values (if they're in the newCountryCodes array)
  101. for (var i = 0; i < allCountryCodes[dialCode].length; i++) {
  102. var country = allCountryCodes[dialCode][i];
  103. if ($.inArray(newCountryCodes[dialCode], country)) {
  104. sortedCountries.push(country);
  105. }
  106. }
  107. newCountryCodes[dialCode] = sortedCountries;
  108. }
  109. }
  110. this.countries = newCountries;
  111. this.countryCodes = newCountryCodes;
  112. } else {
  113. this.countries = allCountries;
  114. this.countryCodes = allCountryCodes;
  115. }
  116. },
  117. // process preferred countries - iterate through the preferences,
  118. // fetching the country data for each one
  119. _setPreferredCountries: function() {
  120. var that = this;
  121. this.preferredCountries = [];
  122. $.each(this.options.preferredCountries, function(i, countryCode) {
  123. var countryData = that._getCountryData(countryCode, false);
  124. if (countryData) {
  125. that.preferredCountries.push(countryData);
  126. }
  127. });
  128. },
  129. // generate all of the markup for the plugin: the selected flag overlay, and the dropdown
  130. _generateMarkup: function() {
  131. // telephone input
  132. this.telInput = $(this.element);
  133. // containers (mostly for positioning)
  134. var mainClass = "intl-tel-input";
  135. if (this.options.defaultStyling) {
  136. mainClass += " " + this.options.defaultStyling;
  137. }
  138. this.telInput.wrap($("<div>", {
  139. "class": mainClass
  140. }));
  141. var flagsContainer = $("<div>", {
  142. "class": "flag-dropdown"
  143. }).insertAfter(this.telInput);
  144. // currently selected flag (displayed to left of input)
  145. var selectedFlag = $("<div>", {
  146. "class": "selected-flag"
  147. }).appendTo(flagsContainer);
  148. this.selectedFlagInner = $("<div>", {
  149. "class": "flag"
  150. }).appendTo(selectedFlag);
  151. // CSS triangle
  152. $("<div>", {
  153. "class": "arrow"
  154. }).appendTo(this.selectedFlagInner);
  155. // country list contains: preferred countries, then divider, then all countries
  156. this.countryList = $("<ul>", {
  157. "class": "country-list v-hide"
  158. }).appendTo(flagsContainer);
  159. if (this.preferredCountries.length) {
  160. this._appendListItems(this.preferredCountries, "preferred");
  161. $("<li>", {
  162. "class": "divider"
  163. }).appendTo(this.countryList);
  164. }
  165. this._appendListItems(this.countries, "");
  166. // now we can grab the dropdown height, and hide it properly
  167. this.dropdownHeight = this.countryList.outerHeight();
  168. this.countryList.removeClass("v-hide").addClass("hide");
  169. // this is useful in lots of places
  170. this.countryListItems = this.countryList.children(".country");
  171. },
  172. // add a country <li> to the countryList <ul> container
  173. _appendListItems: function(countries, className) {
  174. // we create so many DOM elements, I decided it was faster to build a temp string
  175. // and then add everything to the DOM in one go at the end
  176. var tmp = "";
  177. // for each country
  178. $.each(countries, function(i, c) {
  179. // open the list item
  180. tmp += "<li class='country " + className + "' data-dial-code='" + c.dialCode + "' data-country-code='" + c.iso2 + "'>";
  181. // add the flag
  182. tmp += "<div class='flag " + c.iso2 + "'></div>";
  183. // and the country name and dial code
  184. tmp += "<span class='country-name'>" + c.name + "</span>";
  185. tmp += "<span class='dial-code'>+" + c.dialCode + "</span>";
  186. // close the list item
  187. tmp += "</li>";
  188. });
  189. this.countryList.append(tmp);
  190. },
  191. // set the initial state of the input value and the selected flag
  192. _setInitialState: function() {
  193. var flagIsSet = false;
  194. // if the input is pre-populated, then just update the selected flag accordingly
  195. // however, if no valid international dial code was found, flag will not have been set
  196. if (this.telInput.val()) {
  197. flagIsSet = this._updateFlagFromInputVal();
  198. }
  199. if (!flagIsSet) {
  200. // flag is not set, so set to the default country
  201. var defaultCountry;
  202. // check the defaultCountry option, else fall back to the first in the list
  203. if (this.options.defaultCountry) {
  204. defaultCountry = this._getCountryData(this.options.defaultCountry, false);
  205. } else {
  206. defaultCountry = this.preferredCountries.length ? this.preferredCountries[0] : this.countries[0];
  207. }
  208. this._selectFlag(defaultCountry.iso2);
  209. // if autoHideDialCode is disabled, insert the default dial code
  210. if (!this.options.autoHideDialCode) {
  211. this._resetToDialCode(defaultCountry.dialCode);
  212. }
  213. }
  214. },
  215. // initialise the main event listeners: input keyup, and click selected flag
  216. _initListeners: function() {
  217. var that = this;
  218. // auto hide dial code option (ignore if in national mode)
  219. if (this.options.autoHideDialCode && !this.options.nationalMode) {
  220. this._initAutoHideDialCode();
  221. }
  222. // update flag on keyup (by extracting the dial code from the input value).
  223. // use keyup instead of keypress because we want to update on backspace
  224. // and instead of keydown because the value hasn't updated when that event is fired
  225. // NOTE: better to have this one listener all the time instead of starting it on focus
  226. // and stopping it on blur, because then you've got two listeners (focus and blur)
  227. this.telInput.on("keyup" + this.ns, function() {
  228. that._updateFlagFromInputVal();
  229. });
  230. // toggle country dropdown on click
  231. var selectedFlag = this.selectedFlagInner.parent();
  232. selectedFlag.on("click" + this.ns, function(e) {
  233. // only intercept this event if we're opening the dropdown
  234. // else let it bubble up to the top ("click-off-to-close" listener)
  235. // we cannot just stopPropagation as it may be needed to close another instance
  236. if (that.countryList.hasClass("hide") && !that.telInput.prop("disabled")) {
  237. that._showDropdown();
  238. }
  239. });
  240. // if the user has specified the path to the validation script
  241. // inject a new script element for it at the end of the body
  242. if (this.options.validationScript) {
  243. var injectValidationScript = function() {
  244. var script = document.createElement("script");
  245. script.type = "text/javascript";
  246. script.src = that.options.validationScript;
  247. document.body.appendChild(script);
  248. };
  249. // if the plugin is being initialised after the window.load event has already been fired
  250. if (windowLoaded) {
  251. injectValidationScript();
  252. } else {
  253. // wait until the load event so we don't block any other requests e.g. the flags image
  254. $(window).load(injectValidationScript);
  255. }
  256. }
  257. },
  258. // on focus: if empty add dial code. on blur: if just dial code, then empty it
  259. _initAutoHideDialCode: function() {
  260. var that = this;
  261. // mousedown decides where the cursor goes, so if we're focusing
  262. // we must prevent this from happening
  263. this.telInput.on("mousedown" + this.ns, function(e) {
  264. if (!that.telInput.is(":focus") && !that.telInput.val()) {
  265. e.preventDefault();
  266. // but this also cancels the focus, so we must trigger that manually
  267. that._focus();
  268. }
  269. });
  270. // on focus: if empty, insert the dial code for the currently selected flag
  271. this.telInput.on("focus" + this.ns, function() {
  272. if (!$.trim(that.telInput.val())) {
  273. var countryData = that.getSelectedCountryData();
  274. that._resetToDialCode(countryData.dialCode);
  275. // after auto-inserting a dial code, if the first key they hit is '+' then assume
  276. // they are entering a new number, so remove the dial code.
  277. // use keypress instead of keydown because keydown gets triggered for the shift key
  278. // (required to hit the + key), and instead of keyup because that shows the new '+'
  279. // before removing the old one
  280. that.telInput.one("keypress" + that.ns, function(e) {
  281. if (e.which == keys.PLUS) {
  282. that.telInput.val("");
  283. }
  284. });
  285. }
  286. });
  287. // on blur: if just a dial code then remove it
  288. this.telInput.on("blur" + this.ns, function() {
  289. var value = $.trim(that.telInput.val());
  290. if (value) {
  291. if ($.trim(that._getDialCode(value) + that.options.dialCodeDelimiter) == value) {
  292. that.telInput.val("");
  293. }
  294. }
  295. that.telInput.off("keypress" + that.ns);
  296. });
  297. },
  298. // focus input and put the cursor at the end
  299. _focus: function() {
  300. this.telInput.focus();
  301. var input = this.telInput[0];
  302. // works for Chrome, FF, Safari, IE9+
  303. if (input.setSelectionRange) {
  304. var len = this.telInput.val().length;
  305. input.setSelectionRange(len, len);
  306. }
  307. },
  308. // show the dropdown
  309. _showDropdown: function() {
  310. this._setDropdownPosition();
  311. // update highlighting and scroll to active list item
  312. var activeListItem = this.countryList.children(".active");
  313. this._highlightListItem(activeListItem);
  314. // show it
  315. this.countryList.removeClass("hide");
  316. this._scrollTo(activeListItem);
  317. // bind all the dropdown-related listeners: mouseover, click, click-off, keydown
  318. this._bindDropdownListeners();
  319. // update the arrow
  320. this.selectedFlagInner.children(".arrow").addClass("up");
  321. },
  322. // decide where to position dropdown (depends on position within viewport, and scroll)
  323. _setDropdownPosition: function() {
  324. var inputTop = this.telInput.offset().top, windowTop = $(window).scrollTop(), // dropdownFitsBelow = (dropdownBottom < windowBottom)
  325. dropdownFitsBelow = inputTop + this.telInput.outerHeight() + this.dropdownHeight < windowTop + $(window).height(), dropdownFitsAbove = inputTop - this.dropdownHeight > windowTop;
  326. // dropdownHeight - 1 for border
  327. var cssTop = !dropdownFitsBelow && dropdownFitsAbove ? "-" + (this.dropdownHeight - 1) + "px" : "";
  328. this.countryList.css("top", cssTop);
  329. },
  330. // we only bind dropdown listeners when the dropdown is open
  331. _bindDropdownListeners: function() {
  332. var that = this;
  333. // when mouse over a list item, just highlight that one
  334. // we add the class "highlight", so if they hit "enter" we know which one to select
  335. this.countryList.on("mouseover" + this.ns, ".country", function(e) {
  336. that._highlightListItem($(this));
  337. });
  338. // listen for country selection
  339. this.countryList.on("click" + this.ns, ".country", function(e) {
  340. that._selectListItem($(this));
  341. });
  342. // click off to close
  343. // (except when this initial opening click is bubbling up)
  344. // we cannot just stopPropagation as it may be needed to close another instance
  345. var isOpening = true;
  346. $("html").on("click" + this.ns, function(e) {
  347. if (!isOpening) {
  348. that._closeDropdown();
  349. }
  350. isOpening = false;
  351. });
  352. // listen for up/down scrolling, enter to select, or letters to jump to country name.
  353. // use keydown as keypress doesn't fire for non-char keys and we want to catch if they
  354. // just hit down and hold it to scroll down (no keyup event).
  355. // listen on the document because that's where key events are triggered if no input has focus
  356. $(document).on("keydown" + this.ns, function(e) {
  357. // prevent down key from scrolling the whole page,
  358. // and enter key from submitting a form etc
  359. e.preventDefault();
  360. if (e.which == keys.UP || e.which == keys.DOWN) {
  361. // up and down to navigate
  362. that._handleUpDownKey(e.which);
  363. } else if (e.which == keys.ENTER) {
  364. // enter to select
  365. that._handleEnterKey();
  366. } else if (e.which == keys.ESC) {
  367. // esc to close
  368. that._closeDropdown();
  369. } else if (e.which >= keys.A && e.which <= keys.Z) {
  370. // upper case letters (note: keyup/keydown only return upper case letters)
  371. // cycle through countries beginning with that letter
  372. that._handleLetterKey(e.which);
  373. }
  374. });
  375. },
  376. // highlight the next/prev item in the list (and ensure it is visible)
  377. _handleUpDownKey: function(key) {
  378. var current = this.countryList.children(".highlight").first();
  379. var next = key == keys.UP ? current.prev() : current.next();
  380. if (next.length) {
  381. // skip the divider
  382. if (next.hasClass("divider")) {
  383. next = key == keys.UP ? next.prev() : next.next();
  384. }
  385. this._highlightListItem(next);
  386. this._scrollTo(next);
  387. }
  388. },
  389. // select the currently highlighted item
  390. _handleEnterKey: function() {
  391. var currentCountry = this.countryList.children(".highlight").first();
  392. if (currentCountry.length) {
  393. this._selectListItem(currentCountry);
  394. }
  395. },
  396. // iterate through the countries starting with the given letter
  397. _handleLetterKey: function(key) {
  398. var letter = String.fromCharCode(key);
  399. // filter out the countries beginning with that letter
  400. var countries = this.countryListItems.filter(function() {
  401. return $(this).text().charAt(0) == letter && !$(this).hasClass("preferred");
  402. });
  403. if (countries.length) {
  404. // if one is already highlighted, then we want the next one
  405. var highlightedCountry = countries.filter(".highlight").first(), listItem;
  406. // if the next country in the list also starts with that letter
  407. if (highlightedCountry && highlightedCountry.next() && highlightedCountry.next().text().charAt(0) == letter) {
  408. listItem = highlightedCountry.next();
  409. } else {
  410. listItem = countries.first();
  411. }
  412. // update highlighting and scroll
  413. this._highlightListItem(listItem);
  414. this._scrollTo(listItem);
  415. }
  416. },
  417. // update the selected flag using the input's current value
  418. _updateFlagFromInputVal: function() {
  419. var that = this;
  420. // try and extract valid dial code from input
  421. var dialCode = this._getDialCode(this.telInput.val());
  422. if (dialCode) {
  423. // check if one of the matching countries is already selected
  424. var countryCodes = this.countryCodes[dialCode.replace(/\D/g, "")], alreadySelected = false;
  425. $.each(countryCodes, function(i, c) {
  426. if (that.selectedFlagInner.hasClass(c)) {
  427. alreadySelected = true;
  428. }
  429. });
  430. if (!alreadySelected) {
  431. this._selectFlag(countryCodes[0]);
  432. }
  433. // valid international dial code found
  434. return true;
  435. }
  436. // valid international dial code not found
  437. return false;
  438. },
  439. // reset the input value to just a dial code
  440. _resetToDialCode: function(dialCode) {
  441. // if nationalMode is enabled then don't insert the dial code
  442. var value = this.options.nationalMode ? "" : "+" + dialCode + this.options.dialCodeDelimiter;
  443. this.telInput.val(value);
  444. },
  445. // remove highlighting from other list items and highlight the given item
  446. _highlightListItem: function(listItem) {
  447. this.countryListItems.removeClass("highlight");
  448. listItem.addClass("highlight");
  449. },
  450. // find the country data for the given country code
  451. // the ignoreOnlyCountriesOption is only used during init() while parsing the onlyCountries array
  452. _getCountryData: function(countryCode, ignoreOnlyCountriesOption) {
  453. var countryList = ignoreOnlyCountriesOption ? allCountries : this.countries;
  454. for (var i = 0; i < countryList.length; i++) {
  455. if (countryList[i].iso2 == countryCode) {
  456. return countryList[i];
  457. }
  458. }
  459. return null;
  460. },
  461. // update the selected flag and the active list item
  462. _selectFlag: function(countryCode) {
  463. this.selectedFlagInner.attr("class", "flag " + countryCode);
  464. // update the title attribute
  465. var countryData = this._getCountryData(countryCode);
  466. this.selectedFlagInner.parent().attr("title", countryData.name + ": +" + countryData.dialCode);
  467. // update the active list item
  468. var listItem = this.countryListItems.children(".flag." + countryCode).first().parent();
  469. this.countryListItems.removeClass("active");
  470. listItem.addClass("active");
  471. },
  472. // called when the user selects a list item from the dropdown
  473. _selectListItem: function(listItem) {
  474. // update selected flag and active list item
  475. var countryCode = listItem.attr("data-country-code");
  476. this._selectFlag(countryCode);
  477. this._closeDropdown();
  478. // update input value
  479. if (!this.options.nationalMode) {
  480. this._updateNumber("+" + listItem.attr("data-dial-code"));
  481. this.telInput.trigger("change");
  482. }
  483. // focus the input
  484. this._focus();
  485. },
  486. // close the dropdown and unbind any listeners
  487. _closeDropdown: function() {
  488. this.countryList.addClass("hide");
  489. // update the arrow
  490. this.selectedFlagInner.children(".arrow").removeClass("up");
  491. // unbind event listeners
  492. $(document).off("keydown" + this.ns);
  493. $("html").off("click" + this.ns);
  494. // unbind both hover and click listeners
  495. this.countryList.off(this.ns);
  496. },
  497. // check if an element is visible within it's container, else scroll until it is
  498. _scrollTo: function(element) {
  499. var container = this.countryList, containerHeight = container.height(), containerTop = container.offset().top, containerBottom = containerTop + containerHeight, elementHeight = element.outerHeight(), elementTop = element.offset().top, elementBottom = elementTop + elementHeight, newScrollTop = elementTop - containerTop + container.scrollTop();
  500. if (elementTop < containerTop) {
  501. // scroll up
  502. container.scrollTop(newScrollTop);
  503. } else if (elementBottom > containerBottom) {
  504. // scroll down
  505. var heightDifference = containerHeight - elementHeight;
  506. container.scrollTop(newScrollTop - heightDifference);
  507. }
  508. },
  509. // replace any existing dial code with the new one
  510. _updateNumber: function(newDialCode) {
  511. var inputVal = this.telInput.val(), prevDialCode = this._getDialCode(inputVal), newNumber;
  512. // if the previous number contained a valid dial code, replace it
  513. // (if more than just a plus character)
  514. if (prevDialCode.length > 1) {
  515. newNumber = inputVal.replace(prevDialCode, newDialCode);
  516. // if the old number was just the dial code,
  517. // then we will need to add the space again
  518. if (inputVal == prevDialCode) {
  519. newNumber += this.options.dialCodeDelimiter;
  520. }
  521. } else {
  522. // if the previous number didn't contain a dial code, we should persist it
  523. var existingNumber = inputVal && inputVal.substr(0, 1) != "+" ? $.trim(inputVal) : "";
  524. newNumber = newDialCode + this.options.dialCodeDelimiter + existingNumber;
  525. }
  526. this.telInput.val(newNumber);
  527. },
  528. // try and extract a valid international dial code from a full telephone number
  529. // Note: returns the raw string inc plus character and any whitespace/dots etc
  530. _getDialCode: function(inputVal) {
  531. var dialCode = "";
  532. inputVal = $.trim(inputVal);
  533. // only interested in international numbers (starting with a plus)
  534. if (inputVal.charAt(0) == "+") {
  535. var numericChars = "";
  536. // iterate over chars
  537. for (var i = 0; i < inputVal.length; i++) {
  538. var c = inputVal.charAt(i);
  539. // if char is number
  540. if ($.isNumeric(c)) {
  541. numericChars += c;
  542. // if current numericChars make a valid dial code
  543. if (this.countryCodes[numericChars]) {
  544. // store the actual raw string (useful for matching later)
  545. dialCode = inputVal.substring(0, i + 1);
  546. }
  547. // longest dial code is 4 chars
  548. if (numericChars.length == 4) {
  549. break;
  550. }
  551. }
  552. }
  553. }
  554. return dialCode;
  555. },
  556. /********************
  557. * PUBLIC METHODS
  558. ********************/
  559. // get the country data for the currently selected flag
  560. getSelectedCountryData: function() {
  561. // rely on the fact that we only set 2 classes on the selected flag element:
  562. // the first is "flag" and the second is the 2-char country code
  563. var countryCode = this.selectedFlagInner.attr("class").split(" ")[1];
  564. return this._getCountryData(countryCode);
  565. },
  566. // validate the input val - assumes the global function isValidNumber
  567. // pass in true if you want to allow national numbers (no country dial code)
  568. isValidNumber: function(allowNational) {
  569. var val = $.trim(this.telInput.val()), countryData = this.getSelectedCountryData(), countryCode = allowNational ? countryData.iso2 : "";
  570. return window.isValidNumber(val, countryCode);
  571. },
  572. // update the selected flag, and insert the dial code
  573. selectCountry: function(countryCode) {
  574. // check if already selected
  575. if (!this.selectedFlagInner.hasClass(countryCode)) {
  576. this._selectFlag(countryCode);
  577. if (!this.options.autoHideDialCode) {
  578. var countryData = this._getCountryData(countryCode, false);
  579. this._resetToDialCode(countryData.dialCode);
  580. }
  581. }
  582. },
  583. // set the input value and update the flag
  584. setNumber: function(number) {
  585. this.telInput.val(number);
  586. this._updateFlagFromInputVal();
  587. },
  588. // remove plugin
  589. destroy: function() {
  590. // stop listeners
  591. this.telInput.off(this.ns);
  592. this.selectedFlagInner.parent().off(this.ns);
  593. // remove markup
  594. var container = this.telInput.parent();
  595. container.before(this.telInput).remove();
  596. }
  597. };
  598. // adapted to allow public functions
  599. // using https://github.com/jquery-boilerplate/jquery-boilerplate/wiki/Extending-jQuery-Boilerplate
  600. $.fn[pluginName] = function(options) {
  601. var args = arguments;
  602. // Is the first parameter an object (options), or was omitted,
  603. // instantiate a new instance of the plugin.
  604. if (options === undefined || typeof options === "object") {
  605. return this.each(function() {
  606. if (!$.data(this, "plugin_" + pluginName)) {
  607. $.data(this, "plugin_" + pluginName, new Plugin(this, options));
  608. }
  609. });
  610. } else if (typeof options === "string" && options[0] !== "_" && options !== "init") {
  611. // If the first parameter is a string and it doesn't start
  612. // with an underscore or "contains" the `init`-function,
  613. // treat this as a call to a public method.
  614. // Cache the method call to make it possible to return a value
  615. var returns;
  616. this.each(function() {
  617. var instance = $.data(this, "plugin_" + pluginName);
  618. // Tests that there's already a plugin-instance
  619. // and checks that the requested public method exists
  620. if (instance instanceof Plugin && typeof instance[options] === "function") {
  621. // Call the method of our plugin instance,
  622. // and pass it the supplied arguments.
  623. returns = instance[options].apply(instance, Array.prototype.slice.call(args, 1));
  624. }
  625. // Allow instances to be destroyed via the 'destroy' method
  626. if (options === "destroy") {
  627. $.data(this, "plugin_" + pluginName, null);
  628. }
  629. });
  630. // If the earlier cached method gives a value back return the value,
  631. // otherwise return this to preserve chainability.
  632. return returns !== undefined ? returns : this;
  633. }
  634. };
  635. /********************
  636. * STATIC METHODS
  637. ********************/
  638. // get the country data object
  639. $.fn[pluginName].getCountryData = function() {
  640. return allCountries;
  641. };
  642. // set the country data object
  643. $.fn[pluginName].setCountryData = function(obj) {
  644. allCountries = obj;
  645. };
  646. // Tell JSHint to ignore this warning: "character may get silently deleted by one or more browsers"
  647. // jshint -W100
  648. // Array of country objects for the flag dropdown.
  649. // Each contains a name, country code (ISO 3166-1 alpha-2) and dial code.
  650. // Originally from https://github.com/mledoze/countries
  651. // then modified using the following JavaScript:
  652. /*
  653. var result = [];
  654. _.each(countries, function(c) {
  655. // ignore countries without a dial code
  656. if (c.callingCode[0].length) {
  657. result.push({
  658. // var locals contains country names with localised versions in brackets
  659. n: _.findWhere(locals, {
  660. countryCode: c.cca2
  661. }).name,
  662. i: c.cca2.toLowerCase(),
  663. d: c.callingCode[0]
  664. });
  665. }
  666. });
  667. JSON.stringify(result);
  668. */
  669. // then with a couple of manual re-arrangements to be alphabetical
  670. // then changed Kazakhstan from +76 to +7
  671. // then manually removed quotes from property names as not required
  672. // Note: using single char property names to keep filesize down
  673. // n = name
  674. // i = iso2 (2-char country code)
  675. // d = dial code
  676. var allCountries = $.each([ {
  677. n: "Afghanistan (‫افغانستان‬‎)",
  678. i: "af",
  679. d: "93"
  680. }, {
  681. n: "Åland Islands (Åland)",
  682. i: "ax",
  683. d: "358"
  684. }, {
  685. n: "Albania (Shqipëri)",
  686. i: "al",
  687. d: "355"
  688. }, {
  689. n: "Algeria (‫الجزائر‬‎)",
  690. i: "dz",
  691. d: "213"
  692. }, {
  693. n: "American Samoa",
  694. i: "as",
  695. d: "1684"
  696. }, {
  697. n: "Andorra",
  698. i: "ad",
  699. d: "376"
  700. }, {
  701. n: "Angola",
  702. i: "ao",
  703. d: "244"
  704. }, {
  705. n: "Anguilla",
  706. i: "ai",
  707. d: "1264"
  708. }, {
  709. n: "Antigua and Barbuda",
  710. i: "ag",
  711. d: "1268"
  712. }, {
  713. n: "Argentina",
  714. i: "ar",
  715. d: "54"
  716. }, {
  717. n: "Armenia (Հայաստան)",
  718. i: "am",
  719. d: "374"
  720. }, {
  721. n: "Aruba",
  722. i: "aw",
  723. d: "297"
  724. }, {
  725. n: "Australia",
  726. i: "au",
  727. d: "61"
  728. }, {
  729. n: "Austria (Österreich)",
  730. i: "at",
  731. d: "43"
  732. }, {
  733. n: "Azerbaijan (Azərbaycan)",
  734. i: "az",
  735. d: "994"
  736. }, {
  737. n: "Bahamas",
  738. i: "bs",
  739. d: "1242"
  740. }, {
  741. n: "Bahrain (‫البحرين‬‎)",
  742. i: "bh",
  743. d: "973"
  744. }, {
  745. n: "Bangladesh (বাংলাদেশ)",
  746. i: "bd",
  747. d: "880"
  748. }, {
  749. n: "Barbados",
  750. i: "bb",
  751. d: "1246"
  752. }, {
  753. n: "Belarus (Беларусь)",
  754. i: "by",
  755. d: "375"
  756. }, {
  757. n: "Belgium (België)",
  758. i: "be",
  759. d: "32"
  760. }, {
  761. n: "Belize",
  762. i: "bz",
  763. d: "501"
  764. }, {
  765. n: "Benin (Bénin)",
  766. i: "bj",
  767. d: "229"
  768. }, {
  769. n: "Bermuda",
  770. i: "bm",
  771. d: "1441"
  772. }, {
  773. n: "Bhutan (འབྲུག)",
  774. i: "bt",
  775. d: "975"
  776. }, {
  777. n: "Bolivia",
  778. i: "bo",
  779. d: "591"
  780. }, {
  781. n: "Bosnia and Herzegovina (Босна и Херцеговина)",
  782. i: "ba",
  783. d: "387"
  784. }, {
  785. n: "Botswana",
  786. i: "bw",
  787. d: "267"
  788. }, {
  789. n: "Brazil (Brasil)",
  790. i: "br",
  791. d: "55"
  792. }, {
  793. n: "British Indian Ocean Territory",
  794. i: "io",
  795. d: "246"
  796. }, {
  797. n: "British Virgin Islands",
  798. i: "vg",
  799. d: "1284"
  800. }, {
  801. n: "Brunei",
  802. i: "bn",
  803. d: "673"
  804. }, {
  805. n: "Bulgaria (България)",
  806. i: "bg",
  807. d: "359"
  808. }, {
  809. n: "Burkina Faso",
  810. i: "bf",
  811. d: "226"
  812. }, {
  813. n: "Burundi (Uburundi)",
  814. i: "bi",
  815. d: "257"
  816. }, {
  817. n: "Cambodia (កម្ពុជា)",
  818. i: "kh",
  819. d: "855"
  820. }, {
  821. n: "Cameroon (Cameroun)",
  822. i: "cm",
  823. d: "237"
  824. }, {
  825. n: "Canada",
  826. i: "ca",
  827. d: "1"
  828. }, {
  829. n: "Cape Verde (Kabu Verdi)",
  830. i: "cv",
  831. d: "238"
  832. }, {
  833. n: "Caribbean Netherlands",
  834. i: "bq",
  835. d: "5997"
  836. }, {
  837. n: "Cayman Islands",
  838. i: "ky",
  839. d: "1345"
  840. }, {
  841. n: "Central African Republic (République centrafricaine)",
  842. i: "cf",
  843. d: "236"
  844. }, {
  845. n: "Chad (Tchad)",
  846. i: "td",
  847. d: "235"
  848. }, {
  849. n: "Chile",
  850. i: "cl",
  851. d: "56"
  852. }, {
  853. n: "China (中国)",
  854. i: "cn",
  855. d: "86"
  856. }, {
  857. n: "Christmas Island",
  858. i: "cx",
  859. d: "61"
  860. }, {
  861. n: "Cocos (Keeling) Islands (Kepulauan Cocos (Keeling))",
  862. i: "cc",
  863. d: "61"
  864. }, {
  865. n: "Colombia",
  866. i: "co",
  867. d: "57"
  868. }, {
  869. n: "Comoros (‫جزر القمر‬‎)",
  870. i: "km",
  871. d: "269"
  872. }, {
  873. n: "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
  874. i: "cd",
  875. d: "243"
  876. }, {
  877. n: "Congo (Republic) (Congo-Brazzaville)",
  878. i: "cg",
  879. d: "242"
  880. }, {
  881. n: "Cook Islands",
  882. i: "ck",
  883. d: "682"
  884. }, {
  885. n: "Costa Rica",
  886. i: "cr",
  887. d: "506"
  888. }, {
  889. n: "Côte d’Ivoire",
  890. i: "ci",
  891. d: "225"
  892. }, {
  893. n: "Croatia (Hrvatska)",
  894. i: "hr",
  895. d: "385"
  896. }, {
  897. n: "Cuba",
  898. i: "cu",
  899. d: "53"
  900. }, {
  901. n: "Curaçao",
  902. i: "cw",
  903. d: "5999"
  904. }, {
  905. n: "Cyprus (Κύπρος)",
  906. i: "cy",
  907. d: "357"
  908. }, {
  909. n: "Czech Republic (Česká republika)",
  910. i: "cz",
  911. d: "420"
  912. }, {
  913. n: "Denmark (Danmark)",
  914. i: "dk",
  915. d: "45"
  916. }, {
  917. n: "Djibouti",
  918. i: "dj",
  919. d: "253"
  920. }, {
  921. n: "Dominica",
  922. i: "dm",
  923. d: "1767"
  924. }, {
  925. n: "Dominican Republic (República Dominicana)",
  926. i: "do",
  927. d: "1809"
  928. }, {
  929. n: "Ecuador",
  930. i: "ec",
  931. d: "593"
  932. }, {
  933. n: "Egypt (‫مصر‬‎)",
  934. i: "eg",
  935. d: "20"
  936. }, {
  937. n: "El Salvador",
  938. i: "sv",
  939. d: "503"
  940. }, {
  941. n: "Equatorial Guinea (Guinea Ecuatorial)",
  942. i: "gq",
  943. d: "240"
  944. }, {
  945. n: "Eritrea",
  946. i: "er",
  947. d: "291"
  948. }, {
  949. n: "Estonia (Eesti)",
  950. i: "ee",
  951. d: "372"
  952. }, {
  953. n: "Ethiopia",
  954. i: "et",
  955. d: "251"
  956. }, {
  957. n: "Falkland Islands (Islas Malvinas)",
  958. i: "fk",
  959. d: "500"
  960. }, {
  961. n: "Faroe Islands (Føroyar)",
  962. i: "fo",
  963. d: "298"
  964. }, {
  965. n: "Fiji",
  966. i: "fj",
  967. d: "679"
  968. }, {
  969. n: "Finland (Suomi)",
  970. i: "fi",
  971. d: "358"
  972. }, {
  973. n: "France",
  974. i: "fr",
  975. d: "33"
  976. }, {
  977. n: "French Guiana (Guyane française)",
  978. i: "gf",
  979. d: "594"
  980. }, {
  981. n: "French Polynesia (Polynésie française)",
  982. i: "pf",
  983. d: "689"
  984. }, {
  985. n: "Gabon",
  986. i: "ga",
  987. d: "241"
  988. }, {
  989. n: "Gambia",
  990. i: "gm",
  991. d: "220"
  992. }, {
  993. n: "Georgia (საქართველო)",
  994. i: "ge",
  995. d: "995"
  996. }, {
  997. n: "Germany (Deutschland)",
  998. i: "de",
  999. d: "49"
  1000. }, {
  1001. n: "Ghana (Gaana)",
  1002. i: "gh",
  1003. d: "233"
  1004. }, {
  1005. n: "Gibraltar",
  1006. i: "gi",
  1007. d: "350"
  1008. }, {
  1009. n: "Greece (Ελλάδα)",
  1010. i: "gr",
  1011. d: "30"
  1012. }, {
  1013. n: "Greenland (Kalaallit Nunaat)",
  1014. i: "gl",
  1015. d: "299"
  1016. }, {
  1017. n: "Grenada",
  1018. i: "gd",
  1019. d: "1473"
  1020. }, {
  1021. n: "Guadeloupe",
  1022. i: "gp",
  1023. d: "590"
  1024. }, {
  1025. n: "Guam",
  1026. i: "gu",
  1027. d: "1671"
  1028. }, {
  1029. n: "Guatemala",
  1030. i: "gt",
  1031. d: "502"
  1032. }, {
  1033. n: "Guernsey",
  1034. i: "gg",
  1035. d: "44"
  1036. }, {
  1037. n: "Guinea (Guinée)",
  1038. i: "gn",
  1039. d: "224"
  1040. }, {
  1041. n: "Guinea-Bissau (Guiné Bissau)",
  1042. i: "gw",
  1043. d: "245"
  1044. }, {
  1045. n: "Guyana",
  1046. i: "gy",
  1047. d: "592"
  1048. }, {
  1049. n: "Haiti",
  1050. i: "ht",
  1051. d: "509"
  1052. }, {
  1053. n: "Honduras",
  1054. i: "hn",
  1055. d: "504"
  1056. }, {
  1057. n: "Hong Kong (香港)",
  1058. i: "hk",
  1059. d: "852"
  1060. }, {
  1061. n: "Hungary (Magyarország)",
  1062. i: "hu",
  1063. d: "36"
  1064. }, {
  1065. n: "Iceland (Ísland)",
  1066. i: "is",
  1067. d: "354"
  1068. }, {
  1069. n: "India (भारत)",
  1070. i: "in",
  1071. d: "91"
  1072. }, {
  1073. n: "Indonesia",
  1074. i: "id",
  1075. d: "62"
  1076. }, {
  1077. n: "Iran (‫ایران‬‎)",
  1078. i: "ir",
  1079. d: "98"
  1080. }, {
  1081. n: "Iraq (‫العراق‬‎)",
  1082. i: "iq",
  1083. d: "964"
  1084. }, {
  1085. n: "Ireland",
  1086. i: "ie",
  1087. d: "353"
  1088. }, {
  1089. n: "Isle of Man",
  1090. i: "im",
  1091. d: "44"
  1092. }, {
  1093. n: "Israel (‫ישראל‬‎)",
  1094. i: "il",
  1095. d: "972"
  1096. }, {
  1097. n: "Italy (Italia)",
  1098. i: "it",
  1099. d: "39"
  1100. }, {
  1101. n: "Jamaica",
  1102. i: "jm",
  1103. d: "1876"
  1104. }, {
  1105. n: "Japan (日本)",
  1106. i: "jp",
  1107. d: "81"
  1108. }, {
  1109. n: "Jersey",
  1110. i: "je",
  1111. d: "44"
  1112. }, {
  1113. n: "Jordan (‫الأردن‬‎)",
  1114. i: "jo",
  1115. d: "962"
  1116. }, {
  1117. n: "Kazakhstan (Казахстан)",
  1118. i: "kz",
  1119. d: "7"
  1120. }, {
  1121. n: "Kenya",
  1122. i: "ke",
  1123. d: "254"
  1124. }, {
  1125. n: "Kiribati",
  1126. i: "ki",
  1127. d: "686"
  1128. }, {
  1129. n: "Kosovo (Kosovë)",
  1130. i: "xk",
  1131. d: "377"
  1132. }, {
  1133. n: "Kuwait (‫الكويت‬‎)",
  1134. i: "kw",
  1135. d: "965"
  1136. }, {
  1137. n: "Kyrgyzstan (Кыргызстан)",
  1138. i: "kg",
  1139. d: "996"
  1140. }, {
  1141. n: "Laos (ລາວ)",
  1142. i: "la",
  1143. d: "856"
  1144. }, {
  1145. n: "Latvia (Latvija)",
  1146. i: "lv",
  1147. d: "371"
  1148. }, {
  1149. n: "Lebanon (‫لبنان‬‎)",
  1150. i: "lb",
  1151. d: "961"
  1152. }, {
  1153. n: "Lesotho",
  1154. i: "ls",
  1155. d: "266"
  1156. }, {
  1157. n: "Liberia",
  1158. i: "lr",
  1159. d: "231"
  1160. }, {
  1161. n: "Libya (‫ليبيا‬‎)",
  1162. i: "ly",
  1163. d: "218"
  1164. }, {
  1165. n: "Liechtenstein",
  1166. i: "li",
  1167. d: "423"
  1168. }, {
  1169. n: "Lithuania (Lietuva)",
  1170. i: "lt",
  1171. d: "370"
  1172. }, {
  1173. n: "Luxembourg",
  1174. i: "lu",
  1175. d: "352"
  1176. }, {
  1177. n: "Macau (澳門)",
  1178. i: "mo",
  1179. d: "853"
  1180. }, {
  1181. n: "Macedonia (FYROM) (Македонија)",
  1182. i: "mk",
  1183. d: "389"
  1184. }, {
  1185. n: "Madagascar (Madagasikara)",
  1186. i: "mg",
  1187. d: "261"
  1188. }, {
  1189. n: "Malawi",
  1190. i: "mw",
  1191. d: "265"
  1192. }, {
  1193. n: "Malaysia",
  1194. i: "my",
  1195. d: "60"
  1196. }, {
  1197. n: "Maldives",
  1198. i: "mv",
  1199. d: "960"
  1200. }, {
  1201. n: "Mali",
  1202. i: "ml",
  1203. d: "223"
  1204. }, {
  1205. n: "Malta",
  1206. i: "mt",
  1207. d: "356"
  1208. }, {
  1209. n: "Marshall Islands",
  1210. i: "mh",
  1211. d: "692"
  1212. }, {
  1213. n: "Martinique",
  1214. i: "mq",
  1215. d: "596"
  1216. }, {
  1217. n: "Mauritania (‫موريتانيا‬‎)",
  1218. i: "mr",
  1219. d: "222"
  1220. }, {
  1221. n: "Mauritius (Moris)",
  1222. i: "mu",
  1223. d: "230"
  1224. }, {
  1225. n: "Mayotte",
  1226. i: "yt",
  1227. d: "262"
  1228. }, {
  1229. n: "Mexico (México)",
  1230. i: "mx",
  1231. d: "52"
  1232. }, {
  1233. n: "Micronesia",
  1234. i: "fm",
  1235. d: "691"
  1236. }, {
  1237. n: "Moldova (Republica Moldova)",
  1238. i: "md",
  1239. d: "373"
  1240. }, {
  1241. n: "Monaco",
  1242. i: "mc",
  1243. d: "377"
  1244. }, {
  1245. n: "Mongolia (Монгол)",
  1246. i: "mn",
  1247. d: "976"
  1248. }, {
  1249. n: "Montenegro (Crna Gora)",
  1250. i: "me",
  1251. d: "382"
  1252. }, {
  1253. n: "Montserrat",
  1254. i: "ms",
  1255. d: "1664"
  1256. }, {
  1257. n: "Morocco (‫المغرب‬‎)",
  1258. i: "ma",
  1259. d: "212"
  1260. }, {
  1261. n: "Mozambique (Moçambique)",
  1262. i: "mz",
  1263. d: "258"
  1264. }, {
  1265. n: "Myanmar (Burma) (မြန်မာ)",
  1266. i: "mm",
  1267. d: "95"
  1268. }, {
  1269. n: "Namibia (Namibië)",
  1270. i: "na",
  1271. d: "264"
  1272. }, {
  1273. n: "Nauru",
  1274. i: "nr",
  1275. d: "674"
  1276. }, {
  1277. n: "Nepal (नेपाल)",
  1278. i: "np",
  1279. d: "977"
  1280. }, {
  1281. n: "Netherlands (Nederland)",
  1282. i: "nl",
  1283. d: "31"
  1284. }, {
  1285. n: "New Caledonia (Nouvelle-Calédonie)",
  1286. i: "nc",
  1287. d: "687"
  1288. }, {
  1289. n: "New Zealand",
  1290. i: "nz",
  1291. d: "64"
  1292. }, {
  1293. n: "Nicaragua",
  1294. i: "ni",
  1295. d: "505"
  1296. }, {
  1297. n: "Niger (Nijar)",
  1298. i: "ne",
  1299. d: "227"
  1300. }, {
  1301. n: "Nigeria",
  1302. i: "ng",
  1303. d: "234"
  1304. }, {
  1305. n: "Niue",
  1306. i: "nu",
  1307. d: "683"
  1308. }, {
  1309. n: "Norfolk Island",
  1310. i: "nf",
  1311. d: "672"
  1312. }, {
  1313. n: "North Korea (조선 민주주의 인민 공화국)",
  1314. i: "kp",
  1315. d: "850"
  1316. }, {
  1317. n: "Northern Mariana Islands",
  1318. i: "mp",
  1319. d: "1670"
  1320. }, {
  1321. n: "Norway (Norge)",
  1322. i: "no",
  1323. d: "47"
  1324. }, {
  1325. n: "Oman (‫عُمان‬‎)",
  1326. i: "om",
  1327. d: "968"
  1328. }, {
  1329. n: "Pakistan (‫پاکستان‬‎)",
  1330. i: "pk",
  1331. d: "92"
  1332. }, {
  1333. n: "Palau",
  1334. i: "pw",
  1335. d: "680"
  1336. }, {
  1337. n: "Palestine (‫فلسطين‬‎)",
  1338. i: "ps",
  1339. d: "970"
  1340. }, {
  1341. n: "Panama (Panamá)",
  1342. i: "pa",
  1343. d: "507"
  1344. }, {
  1345. n: "Papua New Guinea",
  1346. i: "pg",
  1347. d: "675"
  1348. }, {
  1349. n: "Paraguay",
  1350. i: "py",
  1351. d: "595"
  1352. }, {
  1353. n: "Peru (Perú)",
  1354. i: "pe",
  1355. d: "51"
  1356. }, {
  1357. n: "Philippines",
  1358. i: "ph",
  1359. d: "63"
  1360. }, {
  1361. n: "Pitcairn Islands",
  1362. i: "pn",
  1363. d: "64"
  1364. }, {
  1365. n: "Poland (Polska)",
  1366. i: "pl",
  1367. d: "48"
  1368. }, {
  1369. n: "Portugal",
  1370. i: "pt",
  1371. d: "351"
  1372. }, {
  1373. n: "Puerto Rico",
  1374. i: "pr",
  1375. d: "1787"
  1376. }, {
  1377. n: "Qatar (‫قطر‬‎)",
  1378. i: "qa",
  1379. d: "974"
  1380. }, {
  1381. n: "Réunion (La Réunion)",
  1382. i: "re",
  1383. d: "262"
  1384. }, {
  1385. n: "Romania (România)",
  1386. i: "ro",
  1387. d: "40"
  1388. }, {
  1389. n: "Russia (Россия)",
  1390. i: "ru",
  1391. d: "7"
  1392. }, {
  1393. n: "Rwanda",
  1394. i: "rw",
  1395. d: "250"
  1396. }, {
  1397. n: "Saint Barthélemy (Saint-Barthélemy)",
  1398. i: "bl",
  1399. d: "590"
  1400. }, {
  1401. n: "Saint Helena",
  1402. i: "sh",
  1403. d: "290"
  1404. }, {
  1405. n: "Saint Kitts and Nevis",
  1406. i: "kn",
  1407. d: "1869"
  1408. }, {
  1409. n: "Saint Lucia",
  1410. i: "lc",
  1411. d: "1758"
  1412. }, {
  1413. n: "Saint Martin (Saint-Martin (partie française))",
  1414. i: "mf",
  1415. d: "590"
  1416. }, {
  1417. n: "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
  1418. i: "pm",
  1419. d: "508"
  1420. }, {
  1421. n: "Saint Vincent and the Grenadines",
  1422. i: "vc",
  1423. d: "1784"
  1424. }, {
  1425. n: "Samoa",
  1426. i: "ws",
  1427. d: "685"
  1428. }, {
  1429. n: "San Marino",
  1430. i: "sm",
  1431. d: "378"
  1432. }, {
  1433. n: "São Tomé and Príncipe (São Tomé e Príncipe)",
  1434. i: "st",
  1435. d: "239"
  1436. }, {
  1437. n: "Saudi Arabia (‫المملكة العربية السعودية‬‎)",
  1438. i: "sa",
  1439. d: "966"
  1440. }, {
  1441. n: "Senegal (Sénégal)",
  1442. i: "sn",
  1443. d: "221"
  1444. }, {
  1445. n: "Serbia (Србија)",
  1446. i: "rs",
  1447. d: "381"
  1448. }, {
  1449. n: "Seychelles",
  1450. i: "sc",
  1451. d: "248"
  1452. }, {
  1453. n: "Sierra Leone",
  1454. i: "sl",
  1455. d: "232"
  1456. }, {
  1457. n: "Singapore",
  1458. i: "sg",
  1459. d: "65"
  1460. }, {
  1461. n: "Sint Maarten",
  1462. i: "sx",
  1463. d: "1721"
  1464. }, {
  1465. n: "Slovakia (Slovensko)",
  1466. i: "sk",
  1467. d: "421"
  1468. }, {
  1469. n: "Slovenia (Slovenija)",
  1470. i: "si",
  1471. d: "386"
  1472. }, {
  1473. n: "Solomon Islands",
  1474. i: "sb",
  1475. d: "677"
  1476. }, {
  1477. n: "Somalia (Soomaaliya)",
  1478. i: "so",
  1479. d: "252"
  1480. }, {
  1481. n: "South Africa",
  1482. i: "za",
  1483. d: "27"
  1484. }, {
  1485. n: "South Georgia & South Sandwich Islands",
  1486. i: "gs",
  1487. d: "500"
  1488. }, {
  1489. n: "South Korea (대한민국)",
  1490. i: "kr",
  1491. d: "82"
  1492. }, {
  1493. n: "South Sudan (‫جنوب السودان‬‎)",
  1494. i: "ss",
  1495. d: "211"
  1496. }, {
  1497. n: "Spain (España)",
  1498. i: "es",
  1499. d: "34"
  1500. }, {
  1501. n: "Sri Lanka (ශ්‍රී ලංකාව)",
  1502. i: "lk",
  1503. d: "94"
  1504. }, {
  1505. n: "Sudan (‫السودان‬‎)",
  1506. i: "sd",
  1507. d: "249"
  1508. }, {
  1509. n: "Suriname",
  1510. i: "sr",
  1511. d: "597"
  1512. }, {
  1513. n: "Svalbard and Jan Mayen (Svalbard og Jan Mayen)",
  1514. i: "sj",
  1515. d: "4779"
  1516. }, {
  1517. n: "Swaziland",
  1518. i: "sz",
  1519. d: "268"
  1520. }, {
  1521. n: "Sweden (Sverige)",
  1522. i: "se",
  1523. d: "46"
  1524. }, {
  1525. n: "Switzerland (Schweiz)",
  1526. i: "ch",
  1527. d: "41"
  1528. }, {
  1529. n: "Syria (‫سوريا‬‎)",
  1530. i: "sy",
  1531. d: "963"
  1532. }, {
  1533. n: "Taiwan (台灣)",
  1534. i: "tw",
  1535. d: "886"
  1536. }, {
  1537. n: "Tajikistan",
  1538. i: "tj",
  1539. d: "992"
  1540. }, {
  1541. n: "Tanzania",
  1542. i: "tz",
  1543. d: "255"
  1544. }, {
  1545. n: "Thailand (ไทย)",
  1546. i: "th",
  1547. d: "66"
  1548. }, {
  1549. n: "Timor-Leste",
  1550. i: "tl",
  1551. d: "670"
  1552. }, {
  1553. n: "T…