PageSourceSearch

https://rocketlearning.org/wp-content/plugins/ultimate-addons-for-…/assets/js/countrySelect.js?ver=3.5.52

js rocketlearning.org collected 2026-10-02 14:44:21 UTC 36,857 bytes, 1,411 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.