@countriesdb/widget 0.1.23 → 0.1.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/dist/dom-manipulation.js +0 -2
- package/dist/event-system.d.ts +5 -1
- package/dist/event-system.js +28 -0
- package/dist/index.esm.js +59 -31
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +59 -31
- package/dist/index.js.map +1 -1
- package/dist/initialization.js +21 -7
- package/dist/types.d.ts +3 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -400,8 +400,6 @@
|
|
|
400
400
|
else {
|
|
401
401
|
select.innerHTML += `<option value="${defaultValue}" disabled>${formattedMessage}</option>`;
|
|
402
402
|
}
|
|
403
|
-
// Ensure select is enabled so users can see the error
|
|
404
|
-
select.disabled = false;
|
|
405
403
|
}
|
|
406
404
|
|
|
407
405
|
/**
|
|
@@ -435,6 +433,34 @@
|
|
|
435
433
|
});
|
|
436
434
|
select.dispatchEvent(evt);
|
|
437
435
|
}
|
|
436
|
+
/**
|
|
437
|
+
* Dispatch a custom ready event once a select has been populated.
|
|
438
|
+
*/
|
|
439
|
+
function dispatchReadyEvent(select, detail = {}) {
|
|
440
|
+
const selectedValues = select.multiple
|
|
441
|
+
? Array.from(select.selectedOptions || [])
|
|
442
|
+
.map((opt) => opt.value)
|
|
443
|
+
.filter((v) => v !== '')
|
|
444
|
+
: select.value
|
|
445
|
+
? [select.value]
|
|
446
|
+
: [];
|
|
447
|
+
const evt = new CustomEvent('countriesWidget:ready', {
|
|
448
|
+
bubbles: true,
|
|
449
|
+
detail: {
|
|
450
|
+
value: select.value || '',
|
|
451
|
+
selectedValues,
|
|
452
|
+
name: select.dataset.name || null,
|
|
453
|
+
country: select.dataset.country || null,
|
|
454
|
+
isSubdivision: select.classList.contains('subdivision-selection'),
|
|
455
|
+
type: select.classList.contains('subdivision-selection')
|
|
456
|
+
? 'subdivision'
|
|
457
|
+
: 'country',
|
|
458
|
+
phase: 'initial',
|
|
459
|
+
...detail,
|
|
460
|
+
},
|
|
461
|
+
});
|
|
462
|
+
select.dispatchEvent(evt);
|
|
463
|
+
}
|
|
438
464
|
/**
|
|
439
465
|
* Check if an event was initiated by the widget (not user)
|
|
440
466
|
*/
|
|
@@ -711,7 +737,8 @@
|
|
|
711
737
|
: null;
|
|
712
738
|
// Check if linked country select is multi-select (not allowed)
|
|
713
739
|
if (linkedCountrySelect && linkedCountrySelect.hasAttribute('multiple')) {
|
|
714
|
-
|
|
740
|
+
const defaultValue = select.dataset.defaultValue ?? '';
|
|
741
|
+
select.innerHTML = `<option value="${defaultValue}" disabled>Error: Cannot link to multi-select country. Use data-country-code instead.</option>`;
|
|
715
742
|
continue;
|
|
716
743
|
}
|
|
717
744
|
// No direct link → maybe data-country-code
|
|
@@ -721,7 +748,8 @@
|
|
|
721
748
|
await updateSubdivisionSelect(select, apiKey, backendUrl, state, config, select.dataset.countryCode);
|
|
722
749
|
}
|
|
723
750
|
else {
|
|
724
|
-
|
|
751
|
+
const defaultValue = select.dataset.defaultValue ?? '';
|
|
752
|
+
select.innerHTML += `<option value="${defaultValue}" disabled>Error: No country select present</option>`;
|
|
725
753
|
}
|
|
726
754
|
}
|
|
727
755
|
// Always dispatch an update event for user-initiated subdivision changes
|
|
@@ -767,8 +795,10 @@
|
|
|
767
795
|
// Use GeoIP only if data-preselected attribute is not set at all
|
|
768
796
|
const shouldUseGeoIP = preselectedValue === undefined || preselectedValue === null;
|
|
769
797
|
// Check if this subdivision select prefers official subdivisions
|
|
770
|
-
|
|
771
|
-
|
|
798
|
+
// Use data attribute if present, otherwise use config
|
|
799
|
+
const preferOfficial = select.hasAttribute('data-prefer-official')
|
|
800
|
+
? true
|
|
801
|
+
: config.preferOfficialSubdivisions;
|
|
772
802
|
const languageHeaders = CountriesDBClient.getLanguageHeaders(config.forcedLanguage, config.defaultLanguage);
|
|
773
803
|
const subdivisionsResult = await CountriesDBClient.fetchSubdivisions({
|
|
774
804
|
apiKey,
|
|
@@ -854,6 +884,10 @@
|
|
|
854
884
|
finally {
|
|
855
885
|
// Mark initialization as complete
|
|
856
886
|
state.isInitializing.delete(select);
|
|
887
|
+
dispatchReadyEvent(select, {
|
|
888
|
+
type: 'subdivision',
|
|
889
|
+
phase: isReload ? 'reload' : 'initial',
|
|
890
|
+
});
|
|
857
891
|
// Only fire 'reload' if this is a reload, not initial load
|
|
858
892
|
if (isReload && !valueSetByWidget) {
|
|
859
893
|
dispatchUpdateEvent(select, {
|
|
@@ -865,7 +899,8 @@
|
|
|
865
899
|
}
|
|
866
900
|
else if (!select.dataset.country ||
|
|
867
901
|
!document.querySelector(`.country-selection[data-name="${select.dataset.country}"]`)) {
|
|
868
|
-
|
|
902
|
+
const defaultValue = select.dataset.defaultValue ?? '';
|
|
903
|
+
select.innerHTML += `<option value="${defaultValue}" disabled>Error: No country select present</option>`;
|
|
869
904
|
}
|
|
870
905
|
}
|
|
871
906
|
/**
|
|
@@ -894,7 +929,8 @@
|
|
|
894
929
|
if (name && seenNames[name]) {
|
|
895
930
|
select.removeAttribute('data-name');
|
|
896
931
|
initializeSelect(select, '—');
|
|
897
|
-
|
|
932
|
+
const defaultValue = select.dataset.defaultValue ?? '';
|
|
933
|
+
select.innerHTML += `<option value="${defaultValue}" disabled>Error: Duplicate field</option>`;
|
|
898
934
|
continue;
|
|
899
935
|
}
|
|
900
936
|
if (name) {
|
|
@@ -995,6 +1031,10 @@
|
|
|
995
1031
|
finally {
|
|
996
1032
|
// Mark initialization as complete
|
|
997
1033
|
state.isInitializing.delete(select);
|
|
1034
|
+
dispatchReadyEvent(select, {
|
|
1035
|
+
type: 'country',
|
|
1036
|
+
phase: 'initial',
|
|
1037
|
+
});
|
|
998
1038
|
// If no preselected and no geoip selection happened, emit a regular update
|
|
999
1039
|
if (!valueSetByWidget) {
|
|
1000
1040
|
dispatchUpdateEvent(select, { type: 'country', reason: 'regular' });
|
|
@@ -1113,14 +1153,12 @@
|
|
|
1113
1153
|
// But only if it matches the widget pattern (not a bundled file)
|
|
1114
1154
|
if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
|
|
1115
1155
|
const src = document.currentScript.src;
|
|
1116
|
-
if (src && (src.includes('@countriesdb/widget') ||
|
|
1117
|
-
src.includes('widget/dist/index.js'))) {
|
|
1156
|
+
if (src && (src.includes('@countriesdb/widget') || src.includes('widget/dist/index.js'))) {
|
|
1118
1157
|
loaderScript = document.currentScript;
|
|
1119
1158
|
}
|
|
1120
1159
|
}
|
|
1121
1160
|
// If currentScript didn't match, search for widget script
|
|
1122
1161
|
if (!loaderScript) {
|
|
1123
|
-
// Only consider script tags that loaded the widget bundle
|
|
1124
1162
|
const scripts = Array.from(document.getElementsByTagName('script'));
|
|
1125
1163
|
loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
|
|
1126
1164
|
s.src.includes('widget/dist/index.js'))) || null;
|
|
@@ -1163,11 +1201,6 @@
|
|
|
1163
1201
|
: globalConfig?.isoCountryNames !== undefined
|
|
1164
1202
|
? globalConfig.isoCountryNames
|
|
1165
1203
|
: parseBoolean(scriptUrl?.searchParams.get('iso_country_names') ?? 'false'),
|
|
1166
|
-
preferOfficialSubdivisions: options.preferOfficialSubdivisions !== undefined
|
|
1167
|
-
? options.preferOfficialSubdivisions
|
|
1168
|
-
: globalConfig?.preferOfficialSubdivisions !== undefined
|
|
1169
|
-
? globalConfig.preferOfficialSubdivisions
|
|
1170
|
-
: parseBoolean(scriptUrl?.searchParams.get('prefer_official') ?? 'false'),
|
|
1171
1204
|
subdivisionRomanizationPreference: options.subdivisionRomanizationPreference ||
|
|
1172
1205
|
globalConfig?.subdivisionRomanizationPreference ||
|
|
1173
1206
|
scriptUrl?.searchParams.get('subdivision_romanization_preference') ||
|
|
@@ -1177,6 +1210,11 @@
|
|
|
1177
1210
|
: globalConfig?.preferLocalVariant !== undefined
|
|
1178
1211
|
? globalConfig.preferLocalVariant
|
|
1179
1212
|
: parseBoolean(scriptUrl?.searchParams.get('prefer_local_variant') ?? 'false'),
|
|
1213
|
+
preferOfficialSubdivisions: options.preferOfficialSubdivisions !== undefined
|
|
1214
|
+
? options.preferOfficialSubdivisions
|
|
1215
|
+
: globalConfig?.preferOfficialSubdivisions !== undefined
|
|
1216
|
+
? globalConfig.preferOfficialSubdivisions
|
|
1217
|
+
: parseBoolean(scriptUrl?.searchParams.get('prefer_official') ?? 'false'),
|
|
1180
1218
|
countryNameFilter: options.countryNameFilter ?? globalConfig?.countryNameFilter,
|
|
1181
1219
|
subdivisionNameFilter: options.subdivisionNameFilter ?? globalConfig?.subdivisionNameFilter,
|
|
1182
1220
|
autoInit: options.autoInit !== undefined
|
|
@@ -1214,8 +1252,7 @@
|
|
|
1214
1252
|
// But only if it matches the widget pattern (not a bundled file)
|
|
1215
1253
|
if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
|
|
1216
1254
|
const src = document.currentScript.src;
|
|
1217
|
-
if (src && (src.includes('@countriesdb/widget') ||
|
|
1218
|
-
src.includes('widget/dist/index.js'))) {
|
|
1255
|
+
if (src && (src.includes('@countriesdb/widget') || src.includes('widget/dist/index.js'))) {
|
|
1219
1256
|
loaderScript = document.currentScript;
|
|
1220
1257
|
}
|
|
1221
1258
|
}
|
|
@@ -1283,26 +1320,19 @@
|
|
|
1283
1320
|
* Show error when both follow_related and follow_upward are enabled
|
|
1284
1321
|
*/
|
|
1285
1322
|
function showParamConflictError() {
|
|
1286
|
-
const errorMessage = 'Cannot enable both follow_related and follow_upward';
|
|
1323
|
+
const errorMessage = 'Error: Cannot enable both follow_related and follow_upward';
|
|
1287
1324
|
const countrySelects = Array.from(document.querySelectorAll('.country-selection'));
|
|
1288
1325
|
for (const select of countrySelects) {
|
|
1289
|
-
|
|
1326
|
+
select.innerHTML = `<option value="${select.dataset.defaultValue ?? ''}" disabled>${errorMessage}</option>`;
|
|
1290
1327
|
}
|
|
1291
1328
|
const subdivisionSelects = Array.from(document.querySelectorAll('.subdivision-selection'));
|
|
1292
1329
|
for (const select of subdivisionSelects) {
|
|
1293
|
-
|
|
1330
|
+
select.innerHTML = `<option value="${select.dataset.defaultValue ?? ''}" disabled>${errorMessage}</option>`;
|
|
1294
1331
|
}
|
|
1295
1332
|
}
|
|
1296
1333
|
// Expose public loader
|
|
1297
1334
|
if (typeof window !== 'undefined') {
|
|
1298
1335
|
window.CountriesWidgetLoad = CountriesWidgetLoad;
|
|
1299
|
-
// Dispatch ready event to notify consumers that the widget is available
|
|
1300
|
-
// Use setTimeout(0) to ensure it fires after any synchronous code completes
|
|
1301
|
-
setTimeout(() => {
|
|
1302
|
-
if (typeof window !== 'undefined') {
|
|
1303
|
-
window.dispatchEvent(new CustomEvent('countriesWidget:ready'));
|
|
1304
|
-
}
|
|
1305
|
-
}, 0);
|
|
1306
1336
|
// Auto-init if script URL has auto_init=true (or not set, default is true)
|
|
1307
1337
|
// Use a function that waits for DOM to be ready and finds the script tag reliably
|
|
1308
1338
|
(function checkAutoInit() {
|
|
@@ -1317,14 +1347,12 @@
|
|
|
1317
1347
|
// But only if it matches the widget pattern (not a bundled file)
|
|
1318
1348
|
if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
|
|
1319
1349
|
const src = document.currentScript.src;
|
|
1320
|
-
if (src && (src.includes('@countriesdb/widget') ||
|
|
1321
|
-
src.includes('widget/dist/index.js'))) {
|
|
1350
|
+
if (src && (src.includes('@countriesdb/widget') || src.includes('widget/dist/index.js'))) {
|
|
1322
1351
|
loaderScript = document.currentScript;
|
|
1323
1352
|
}
|
|
1324
1353
|
}
|
|
1325
1354
|
// If currentScript didn't match, search for widget script
|
|
1326
1355
|
if (!loaderScript) {
|
|
1327
|
-
// Fallback: find script tag with @countriesdb/widget in src
|
|
1328
1356
|
const scripts = Array.from(document.getElementsByTagName('script'));
|
|
1329
1357
|
loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
|
|
1330
1358
|
s.src.includes('widget/dist/index.js'))) || null;
|