PageSourceSearch

https://erda.org/wp-content/plugins/country-state-city-auto-dropdown/assets/js/script.js?ver=2.8.2

js erda.org collected 2026-10-08 17:00:58 UTC 5,616 bytes, 209 lines download raw bytes

1/* Cascading country/state/city — cache, loading states, optional city. */
2jQuery(function ($) {
3	var i18n = (tc_csca_auto_ajax && tc_csca_auto_ajax.i18n) ? tc_csca_auto_ajax.i18n : {};
4	var cache = { states: {}, cities: {} };
5
6	function t(key, fallback) {
7		return i18n[key] || fallback;
8	}
9
10	function isEmptyId(id) {
11		return !id || id === "0" || id === 0 || id === "0001";
12	}
13
14	function emptyLabel($el, key, fallback) {
15		return $el.attr("data-placeholder") || t(key, fallback);
16	}
17
18	function optionHtml(value, dataId, label) {
19		return "<option value='" + value + "' data-id='" + dataId + "'>" + label + "</option>";
20	}
21
22	function setLoading($el) {
23		$el.prop("disabled", true).attr("aria-busy", "true");
24		$el.html(optionHtml("0001", "0001", t("loading", "Loading...")));
25	}
26
27	function setEmpty($el, label, disable) {
28		$el.attr("aria-busy", "false");
29		$el.html(optionHtml("0", "0", label));
30		$el.prop("disabled", !!disable);
31	}
32
33	function fillOptions($el, rows, emptyLbl) {
34		$el.attr("aria-busy", "false").prop("disabled", false);
35		$el.html(optionHtml("0", "0", emptyLbl));
36		if (!rows || !rows.length) {
37			return false;
38		}
39		for (var i = 0; i < rows.length; i++) {
40			$el.append(optionHtml(rows[i].name, rows[i].id, rows[i].name));
41		}
42		return true;
43	}
44
45	/**
46	 * Resolve paired select:
47	 * 1) data-tc-group
48	 * 2) same index in form
49	 * 3) first match (legacy)
50	 */
51	function findPaired($el, typeClass) {
52		var $form = $el.closest("form");
53		var group = $el.attr("data-tc-group");
54		if (group) {
55			var $byGroup = $form.find("select." + typeClass + '[data-tc-group="' + group + '"]');
56			if ($byGroup.length) {
57				return $byGroup.first();
58			}
59		}
60
61		var fromClass = $el.hasClass("country_auto")
62			? "country_auto"
63			: $el.hasClass("state_auto")
64				? "state_auto"
65				: "city_auto";
66
67		var $fromAll = $form.find("select." + fromClass);
68		var idx = $fromAll.index($el);
69		var $targets = $form.find("select." + typeClass);
70
71		if (idx >= 0 && $targets.eq(idx).length) {
72			return $targets.eq(idx);
73		}
74		return $targets.first();
75	}
76
77	function fetchStates(cnt, done) {
78		if (cache.states[cnt]) {
79			done(cache.states[cnt]);
80			return;
81		}
82		$.ajax({
83			url: tc_csca_auto_ajax.ajax_url,
84			type: "post",
85			dataType: "json",
86			data: {
87				action: "tc_csca_get_states",
88				nonce_ajax: tc_csca_auto_ajax.nonce,
89				cnt: cnt
90			}
91		})
92			.done(function (response) {
93				var rows = response && response.length ? response : [];
94				cache.states[cnt] = rows;
95				done(rows);
96			})
97			.fail(function () {
98				done(null);
99			});
100	}
101
102	function fetchCities(sid, done) {
103		if (cache.cities[sid]) {
104			done(cache.cities[sid]);
105			return;
106		}
107		$.ajax({
108			url: tc_csca_auto_ajax.ajax_url,
109			type: "post",
110			dataType: "json",
111			data: {
112				action: "tc_csca_get_cities",
113				nonce_ajax: tc_csca_auto_ajax.nonce,
114				sid: sid
115			}
116		})
117			.done(function (response) {
118				var rows = response && response.length ? response : [];
119				cache.cities[sid] = rows;
120				done(rows);
121			})
122			.fail(function () {
123				done(null);
124			});
125	}
126
127	// Country → State (+ reset City if present). City field is optional.
128	$(document).on("change", "select.country_auto", function () {
129		var $country = $(this);
130		var $state = findPaired($country, "state_auto");
131		var $city = findPaired($country, "city_auto");
132
133		if (!$state.length) {
134			return;
135		}
136
137		var cnt = $country.children("option:selected").attr("data-id");
138		var stateLbl = emptyLabel($state, "select_state", "Select State");
139		var cityLbl = $city.length ? emptyLabel($city, "select_city", "Select City") : "";
140
141		if ($city.length) {
142			setEmpty($city, cityLbl, true);
143		}
144
145		if (isEmptyId(cnt)) {
146			setEmpty($state, stateLbl, true);
147			return;
148		}
149
150		setLoading($state);
151		fetchStates(cnt, function (rows) {
152			if (rows === null) {
153				setEmpty($state, t("state_not_found", "State list not found"), false);
154				return;
155			}
156			if (!fillOptions($state, rows, stateLbl)) {
157				setEmpty($state, t("state_not_found", "State list not found"), false);
158			}
159		});
160	});
161
162	// State → City (no-op if form has country+state only).
163	$(document).on("change", "select.state_auto", function () {
164		var $state = $(this);
165		var $city = findPaired($state, "city_auto");
166
167		if (!$city.length) {
168			return;
169		}
170
171		var sid = $state.children("option:selected").attr("data-id");
172		var cityLbl = emptyLabel($city, "select_city", "Select City");
173
174		if (isEmptyId(sid)) {
175			setEmpty($city, cityLbl, true);
176			return;
177		}
178
179		setLoading($city);
180		fetchCities(sid, function (rows) {
181			if (rows === null) {
182				setEmpty($city, t("city_not_found", "City list not found"), false);
183				return;
184			}
185			if (!fillOptions($city, rows, cityLbl)) {
186				setEmpty($city, t("city_not_found", "City list not found"), false);
187			}
188		});
189	});
190
191	// Initial: disable empty dependent fields (city optional).
192	$("select.state_auto, select.city_auto").each(function () {
193		var $el = $(this);
194		if (isEmptyId($el.children("option:selected").attr("data-id"))) {
195			$el.prop("disabled", true);
196		}
197	});
198
199	// Disabled fields are omitted from submit — re-enable so CF7 still receives values.
200	function reenableDependent(form) {
201		$(form).find("select.state_auto, select.city_auto").prop("disabled", false);
202	}
203	$(document).on("submit", "form.wpcf7-form", function () {
204		reenableDependent(this);
205	});
206	$(document).on("wpcf7beforesubmit", "form.wpcf7-form", function () {
207		reenableDependent(this);
208	});
209});

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.