@countriesdb/widget 0.1.23 → 0.1.24
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 -2
- 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 +84 -89
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +84 -89
- 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/README.md
CHANGED
|
@@ -89,7 +89,6 @@ CountriesWidgetLoad({
|
|
|
89
89
|
### Options
|
|
90
90
|
|
|
91
91
|
- `publicKey` (required): Your CountriesDB public API key. [Get your API key](https://countriesdb.com) by creating an account.
|
|
92
|
-
- `backendUrl` (optional): Backend API URL (defaults to script origin or `https://api.countriesdb.com`)
|
|
93
92
|
- `defaultLanguage` (optional): Default language for country/subdivision names
|
|
94
93
|
- `forcedLanguage` (optional): Force a specific language
|
|
95
94
|
- `showSubdivisionType` (optional): Show subdivision type names (default: `true`)
|
|
@@ -99,6 +98,7 @@ CountriesWidgetLoad({
|
|
|
99
98
|
- `isoCountryNames` (optional): Use ISO country names (default: `false`)
|
|
100
99
|
- `subdivisionRomanizationPreference` (optional): Preferred romanization system
|
|
101
100
|
- `preferLocalVariant` (optional): Prefer local name variants (default: `false`)
|
|
101
|
+
- `preferOfficialSubdivisions` (optional): Prefer official ISO subdivisions (default: `false`)
|
|
102
102
|
- `countryNameFilter` (optional): Custom function to filter/transform country names
|
|
103
103
|
- `subdivisionNameFilter` (optional): Custom function to filter/transform subdivision names
|
|
104
104
|
- `autoInit` (optional): Auto-initialize on load (default: `true`)
|
|
@@ -143,6 +143,25 @@ document.addEventListener('countriesWidget:update', (event) => {
|
|
|
143
143
|
});
|
|
144
144
|
```
|
|
145
145
|
|
|
146
|
+
It also emits `countriesWidget:ready` whenever a country or subdivision select
|
|
147
|
+
finishes loading options (initial load and subsequent reloads, like when a country
|
|
148
|
+
changes). Listen once on `document` to react as soon as the widget is fully wired:
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
document.addEventListener('countriesWidget:ready', (event) => {
|
|
152
|
+
console.log('Select ready:', event.detail);
|
|
153
|
+
// {
|
|
154
|
+
// value: 'US',
|
|
155
|
+
// selectedValues: ['US'],
|
|
156
|
+
// name: 'country1',
|
|
157
|
+
// country: null,
|
|
158
|
+
// isSubdivision: false,
|
|
159
|
+
// type: 'country' | 'subdivision',
|
|
160
|
+
// phase: 'initial' | 'reload'
|
|
161
|
+
// }
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
146
165
|
## Examples
|
|
147
166
|
|
|
148
167
|
### Basic Usage
|
|
@@ -196,7 +215,7 @@ For complete API documentation, visit [countriesdb.com/docs](https://countriesdb
|
|
|
196
215
|
|
|
197
216
|
## License
|
|
198
217
|
|
|
199
|
-
PROPRIETARY - Copyright (c) NAYEE LLC. See [LICENSE](LICENSE) for details.
|
|
218
|
+
PROPRIETARY - Copyright (c) NAYEE LLC. See [LICENSE](https://github.com/countriesdb/countriesdb/blob/main/packages/npm/widget/LICENSE) for details.
|
|
200
219
|
|
|
201
220
|
**Developed by [NAYEE LLC](https://nayee.net)**
|
|
202
221
|
|
package/dist/dom-manipulation.js
CHANGED
|
@@ -153,8 +153,6 @@ export function handleApiError(select, errorMessage, replace = false) {
|
|
|
153
153
|
else {
|
|
154
154
|
select.innerHTML += `<option value="${defaultValue}" disabled>${formattedMessage}</option>`;
|
|
155
155
|
}
|
|
156
|
-
// Ensure select is enabled so users can see the error
|
|
157
|
-
select.disabled = false;
|
|
158
156
|
}
|
|
159
157
|
/**
|
|
160
158
|
* Parse boolean from string value
|
package/dist/event-system.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Event system for widget updates
|
|
3
3
|
*/
|
|
4
|
-
import type { SelectElement, UpdateEventDetail } from './types';
|
|
4
|
+
import type { ReadyEventDetail, SelectElement, UpdateEventDetail } from './types';
|
|
5
5
|
/**
|
|
6
6
|
* Dispatch a custom update event for widget changes
|
|
7
7
|
*/
|
|
8
8
|
export declare function dispatchUpdateEvent(select: SelectElement, detail?: Partial<UpdateEventDetail>): void;
|
|
9
|
+
/**
|
|
10
|
+
* Dispatch a custom ready event once a select has been populated.
|
|
11
|
+
*/
|
|
12
|
+
export declare function dispatchReadyEvent(select: SelectElement, detail?: Partial<ReadyEventDetail>): void;
|
|
9
13
|
/**
|
|
10
14
|
* Check if an event was initiated by the widget (not user)
|
|
11
15
|
*/
|
package/dist/event-system.js
CHANGED
|
@@ -29,6 +29,34 @@ export function dispatchUpdateEvent(select, detail = {}) {
|
|
|
29
29
|
});
|
|
30
30
|
select.dispatchEvent(evt);
|
|
31
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Dispatch a custom ready event once a select has been populated.
|
|
34
|
+
*/
|
|
35
|
+
export function dispatchReadyEvent(select, detail = {}) {
|
|
36
|
+
const selectedValues = select.multiple
|
|
37
|
+
? Array.from(select.selectedOptions || [])
|
|
38
|
+
.map((opt) => opt.value)
|
|
39
|
+
.filter((v) => v !== '')
|
|
40
|
+
: select.value
|
|
41
|
+
? [select.value]
|
|
42
|
+
: [];
|
|
43
|
+
const evt = new CustomEvent('countriesWidget:ready', {
|
|
44
|
+
bubbles: true,
|
|
45
|
+
detail: {
|
|
46
|
+
value: select.value || '',
|
|
47
|
+
selectedValues,
|
|
48
|
+
name: select.dataset.name || null,
|
|
49
|
+
country: select.dataset.country || null,
|
|
50
|
+
isSubdivision: select.classList.contains('subdivision-selection'),
|
|
51
|
+
type: select.classList.contains('subdivision-selection')
|
|
52
|
+
? 'subdivision'
|
|
53
|
+
: 'country',
|
|
54
|
+
phase: 'initial',
|
|
55
|
+
...detail,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
select.dispatchEvent(evt);
|
|
59
|
+
}
|
|
32
60
|
/**
|
|
33
61
|
* Check if an event was initiated by the widget (not user)
|
|
34
62
|
*/
|
package/dist/index.esm.js
CHANGED
|
@@ -154,8 +154,6 @@ function handleApiError(select, errorMessage, replace = false) {
|
|
|
154
154
|
else {
|
|
155
155
|
select.innerHTML += `<option value="${defaultValue}" disabled>${formattedMessage}</option>`;
|
|
156
156
|
}
|
|
157
|
-
// Ensure select is enabled so users can see the error
|
|
158
|
-
select.disabled = false;
|
|
159
157
|
}
|
|
160
158
|
|
|
161
159
|
/**
|
|
@@ -189,6 +187,34 @@ function dispatchUpdateEvent(select, detail = {}) {
|
|
|
189
187
|
});
|
|
190
188
|
select.dispatchEvent(evt);
|
|
191
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* Dispatch a custom ready event once a select has been populated.
|
|
192
|
+
*/
|
|
193
|
+
function dispatchReadyEvent(select, detail = {}) {
|
|
194
|
+
const selectedValues = select.multiple
|
|
195
|
+
? Array.from(select.selectedOptions || [])
|
|
196
|
+
.map((opt) => opt.value)
|
|
197
|
+
.filter((v) => v !== '')
|
|
198
|
+
: select.value
|
|
199
|
+
? [select.value]
|
|
200
|
+
: [];
|
|
201
|
+
const evt = new CustomEvent('countriesWidget:ready', {
|
|
202
|
+
bubbles: true,
|
|
203
|
+
detail: {
|
|
204
|
+
value: select.value || '',
|
|
205
|
+
selectedValues,
|
|
206
|
+
name: select.dataset.name || null,
|
|
207
|
+
country: select.dataset.country || null,
|
|
208
|
+
isSubdivision: select.classList.contains('subdivision-selection'),
|
|
209
|
+
type: select.classList.contains('subdivision-selection')
|
|
210
|
+
? 'subdivision'
|
|
211
|
+
: 'country',
|
|
212
|
+
phase: 'initial',
|
|
213
|
+
...detail,
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
select.dispatchEvent(evt);
|
|
217
|
+
}
|
|
192
218
|
/**
|
|
193
219
|
* Check if an event was initiated by the widget (not user)
|
|
194
220
|
*/
|
|
@@ -465,7 +491,8 @@ async function setupSubdivisionSelection(apiKey, backendUrl, state, config) {
|
|
|
465
491
|
: null;
|
|
466
492
|
// Check if linked country select is multi-select (not allowed)
|
|
467
493
|
if (linkedCountrySelect && linkedCountrySelect.hasAttribute('multiple')) {
|
|
468
|
-
|
|
494
|
+
const defaultValue = select.dataset.defaultValue ?? '';
|
|
495
|
+
select.innerHTML = `<option value="${defaultValue}" disabled>Error: Cannot link to multi-select country. Use data-country-code instead.</option>`;
|
|
469
496
|
continue;
|
|
470
497
|
}
|
|
471
498
|
// No direct link → maybe data-country-code
|
|
@@ -475,7 +502,8 @@ async function setupSubdivisionSelection(apiKey, backendUrl, state, config) {
|
|
|
475
502
|
await updateSubdivisionSelect(select, apiKey, backendUrl, state, config, select.dataset.countryCode);
|
|
476
503
|
}
|
|
477
504
|
else {
|
|
478
|
-
|
|
505
|
+
const defaultValue = select.dataset.defaultValue ?? '';
|
|
506
|
+
select.innerHTML += `<option value="${defaultValue}" disabled>Error: No country select present</option>`;
|
|
479
507
|
}
|
|
480
508
|
}
|
|
481
509
|
// Always dispatch an update event for user-initiated subdivision changes
|
|
@@ -521,8 +549,10 @@ async function updateSubdivisionSelect(select, apiKey, backendUrl, state, config
|
|
|
521
549
|
// Use GeoIP only if data-preselected attribute is not set at all
|
|
522
550
|
const shouldUseGeoIP = preselectedValue === undefined || preselectedValue === null;
|
|
523
551
|
// Check if this subdivision select prefers official subdivisions
|
|
524
|
-
|
|
525
|
-
|
|
552
|
+
// Use data attribute if present, otherwise use config
|
|
553
|
+
const preferOfficial = select.hasAttribute('data-prefer-official')
|
|
554
|
+
? true
|
|
555
|
+
: config.preferOfficialSubdivisions;
|
|
526
556
|
const languageHeaders = CountriesDBClient.getLanguageHeaders(config.forcedLanguage, config.defaultLanguage);
|
|
527
557
|
const subdivisionsResult = await CountriesDBClient.fetchSubdivisions({
|
|
528
558
|
apiKey,
|
|
@@ -608,6 +638,10 @@ async function updateSubdivisionSelect(select, apiKey, backendUrl, state, config
|
|
|
608
638
|
finally {
|
|
609
639
|
// Mark initialization as complete
|
|
610
640
|
state.isInitializing.delete(select);
|
|
641
|
+
dispatchReadyEvent(select, {
|
|
642
|
+
type: 'subdivision',
|
|
643
|
+
phase: isReload ? 'reload' : 'initial',
|
|
644
|
+
});
|
|
611
645
|
// Only fire 'reload' if this is a reload, not initial load
|
|
612
646
|
if (isReload && !valueSetByWidget) {
|
|
613
647
|
dispatchUpdateEvent(select, {
|
|
@@ -619,7 +653,8 @@ async function updateSubdivisionSelect(select, apiKey, backendUrl, state, config
|
|
|
619
653
|
}
|
|
620
654
|
else if (!select.dataset.country ||
|
|
621
655
|
!document.querySelector(`.country-selection[data-name="${select.dataset.country}"]`)) {
|
|
622
|
-
|
|
656
|
+
const defaultValue = select.dataset.defaultValue ?? '';
|
|
657
|
+
select.innerHTML += `<option value="${defaultValue}" disabled>Error: No country select present</option>`;
|
|
623
658
|
}
|
|
624
659
|
}
|
|
625
660
|
/**
|
|
@@ -648,7 +683,8 @@ async function setupCountrySelection(apiKey, backendUrl, state, config, subdivis
|
|
|
648
683
|
if (name && seenNames[name]) {
|
|
649
684
|
select.removeAttribute('data-name');
|
|
650
685
|
initializeSelect(select, '—');
|
|
651
|
-
|
|
686
|
+
const defaultValue = select.dataset.defaultValue ?? '';
|
|
687
|
+
select.innerHTML += `<option value="${defaultValue}" disabled>Error: Duplicate field</option>`;
|
|
652
688
|
continue;
|
|
653
689
|
}
|
|
654
690
|
if (name) {
|
|
@@ -749,6 +785,10 @@ async function setupCountrySelection(apiKey, backendUrl, state, config, subdivis
|
|
|
749
785
|
finally {
|
|
750
786
|
// Mark initialization as complete
|
|
751
787
|
state.isInitializing.delete(select);
|
|
788
|
+
dispatchReadyEvent(select, {
|
|
789
|
+
type: 'country',
|
|
790
|
+
phase: 'initial',
|
|
791
|
+
});
|
|
752
792
|
// If no preselected and no geoip selection happened, emit a regular update
|
|
753
793
|
if (!valueSetByWidget) {
|
|
754
794
|
dispatchUpdateEvent(select, { type: 'country', reason: 'regular' });
|
|
@@ -855,29 +895,23 @@ async function CountriesWidgetLoad(options = {}) {
|
|
|
855
895
|
* Get configuration from options or script URL parameters
|
|
856
896
|
*/
|
|
857
897
|
function getConfigFromOptionsOrScript(options) {
|
|
858
|
-
// Check for global config first (for bundled widgets that need config before auto-init)
|
|
859
|
-
const globalConfig = typeof window !== 'undefined' && window.CountriesDBConfig
|
|
860
|
-
? window.CountriesDBConfig
|
|
861
|
-
: null;
|
|
862
898
|
// Try to get config from script URL (for backward compatibility with widget.blade.php)
|
|
863
899
|
let scriptUrl = null;
|
|
864
900
|
try {
|
|
865
901
|
let loaderScript = null;
|
|
866
902
|
// First try document.currentScript (works during script execution)
|
|
867
|
-
// But only if it matches the widget pattern (not a bundled file)
|
|
868
903
|
if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
|
|
869
|
-
|
|
870
|
-
if (src && (src.includes('@countriesdb/widget') ||
|
|
871
|
-
src.includes('widget/dist/index.js'))) {
|
|
872
|
-
loaderScript = document.currentScript;
|
|
873
|
-
}
|
|
904
|
+
loaderScript = document.currentScript;
|
|
874
905
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
// Only consider script tags that loaded the widget bundle
|
|
906
|
+
else {
|
|
907
|
+
// Fallback: find script tag with @countriesdb/widget in src
|
|
878
908
|
const scripts = Array.from(document.getElementsByTagName('script'));
|
|
879
909
|
loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
|
|
880
910
|
s.src.includes('widget/dist/index.js'))) || null;
|
|
911
|
+
// If still not found, try the last script with src
|
|
912
|
+
if (!loaderScript) {
|
|
913
|
+
loaderScript = scripts.filter((s) => s.src).pop() || null;
|
|
914
|
+
}
|
|
881
915
|
}
|
|
882
916
|
if (loaderScript && loaderScript.src) {
|
|
883
917
|
scriptUrl = new URL(loaderScript.src);
|
|
@@ -887,57 +921,39 @@ function getConfigFromOptionsOrScript(options) {
|
|
|
887
921
|
// Ignore errors
|
|
888
922
|
}
|
|
889
923
|
const config = {
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
forcedLanguage: options.forcedLanguage ?? globalConfig?.forcedLanguage ?? scriptUrl?.searchParams.get('forced_language') ?? undefined,
|
|
924
|
+
publicKey: options.publicKey || scriptUrl?.searchParams.get('public_key') || '',
|
|
925
|
+
backendUrl: options.backendUrl || scriptUrl?.searchParams.get('backend_url') || getBackendUrlFromScript(),
|
|
926
|
+
defaultLanguage: options.defaultLanguage || scriptUrl?.searchParams.get('default_language') || undefined,
|
|
927
|
+
forcedLanguage: options.forcedLanguage || scriptUrl?.searchParams.get('forced_language') || undefined,
|
|
895
928
|
showSubdivisionType: options.showSubdivisionType !== undefined
|
|
896
929
|
? options.showSubdivisionType
|
|
897
|
-
:
|
|
898
|
-
? globalConfig.showSubdivisionType
|
|
899
|
-
: parseBoolean(scriptUrl?.searchParams.get('show_subdivision_type') ?? '1'),
|
|
930
|
+
: parseBoolean(scriptUrl?.searchParams.get('show_subdivision_type') ?? '1'),
|
|
900
931
|
followRelated: options.followRelated !== undefined
|
|
901
932
|
? options.followRelated
|
|
902
|
-
:
|
|
903
|
-
? globalConfig.followRelated
|
|
904
|
-
: parseBoolean(scriptUrl?.searchParams.get('follow_related') ?? 'false'),
|
|
933
|
+
: parseBoolean(scriptUrl?.searchParams.get('follow_related') ?? 'false'),
|
|
905
934
|
followUpward: options.followUpward !== undefined
|
|
906
935
|
? options.followUpward
|
|
907
|
-
:
|
|
908
|
-
? globalConfig.followUpward
|
|
909
|
-
: parseBoolean(scriptUrl?.searchParams.get('follow_upward') ?? 'false'),
|
|
936
|
+
: parseBoolean(scriptUrl?.searchParams.get('follow_upward') ?? 'false'),
|
|
910
937
|
allowParentSelection: options.allowParentSelection !== undefined
|
|
911
938
|
? options.allowParentSelection
|
|
912
|
-
:
|
|
913
|
-
? globalConfig.allowParentSelection
|
|
914
|
-
: parseBoolean(scriptUrl?.searchParams.get('allow_parent_selection') ?? 'false'),
|
|
939
|
+
: parseBoolean(scriptUrl?.searchParams.get('allow_parent_selection') ?? 'false'),
|
|
915
940
|
isoCountryNames: options.isoCountryNames !== undefined
|
|
916
941
|
? options.isoCountryNames
|
|
917
|
-
:
|
|
918
|
-
? globalConfig.isoCountryNames
|
|
919
|
-
: parseBoolean(scriptUrl?.searchParams.get('iso_country_names') ?? 'false'),
|
|
920
|
-
preferOfficialSubdivisions: options.preferOfficialSubdivisions !== undefined
|
|
921
|
-
? options.preferOfficialSubdivisions
|
|
922
|
-
: globalConfig?.preferOfficialSubdivisions !== undefined
|
|
923
|
-
? globalConfig.preferOfficialSubdivisions
|
|
924
|
-
: parseBoolean(scriptUrl?.searchParams.get('prefer_official') ?? 'false'),
|
|
942
|
+
: parseBoolean(scriptUrl?.searchParams.get('iso_country_names') ?? 'false'),
|
|
925
943
|
subdivisionRomanizationPreference: options.subdivisionRomanizationPreference ||
|
|
926
|
-
globalConfig?.subdivisionRomanizationPreference ||
|
|
927
944
|
scriptUrl?.searchParams.get('subdivision_romanization_preference') ||
|
|
928
945
|
undefined,
|
|
929
946
|
preferLocalVariant: options.preferLocalVariant !== undefined
|
|
930
947
|
? options.preferLocalVariant
|
|
931
|
-
:
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
948
|
+
: parseBoolean(scriptUrl?.searchParams.get('prefer_local_variant') ?? 'false'),
|
|
949
|
+
preferOfficialSubdivisions: options.preferOfficialSubdivisions !== undefined
|
|
950
|
+
? options.preferOfficialSubdivisions
|
|
951
|
+
: parseBoolean(scriptUrl?.searchParams.get('prefer_official') ?? 'false'),
|
|
952
|
+
countryNameFilter: options.countryNameFilter,
|
|
953
|
+
subdivisionNameFilter: options.subdivisionNameFilter,
|
|
936
954
|
autoInit: options.autoInit !== undefined
|
|
937
955
|
? options.autoInit
|
|
938
|
-
:
|
|
939
|
-
? globalConfig.autoInit
|
|
940
|
-
: parseBoolean(scriptUrl?.searchParams.get('auto_init') ?? 'true'),
|
|
956
|
+
: parseBoolean(scriptUrl?.searchParams.get('auto_init') ?? 'true'),
|
|
941
957
|
};
|
|
942
958
|
// Resolve filter functions from global scope if specified by name
|
|
943
959
|
if (scriptUrl) {
|
|
@@ -965,20 +981,18 @@ function getBackendUrlFromScript() {
|
|
|
965
981
|
try {
|
|
966
982
|
let loaderScript = null;
|
|
967
983
|
// First try document.currentScript (works during script execution)
|
|
968
|
-
// But only if it matches the widget pattern (not a bundled file)
|
|
969
984
|
if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
|
|
970
|
-
|
|
971
|
-
if (src && (src.includes('@countriesdb/widget') ||
|
|
972
|
-
src.includes('widget/dist/index.js'))) {
|
|
973
|
-
loaderScript = document.currentScript;
|
|
974
|
-
}
|
|
985
|
+
loaderScript = document.currentScript;
|
|
975
986
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
// Only consider script tags that loaded the widget bundle
|
|
987
|
+
else {
|
|
988
|
+
// Fallback: find script tag with @countriesdb/widget in src
|
|
979
989
|
const scripts = Array.from(document.getElementsByTagName('script'));
|
|
980
990
|
loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
|
|
981
991
|
s.src.includes('widget/dist/index.js'))) || null;
|
|
992
|
+
// If still not found, try the last script with src
|
|
993
|
+
if (!loaderScript) {
|
|
994
|
+
loaderScript = scripts.filter((s) => s.src).pop() || null;
|
|
995
|
+
}
|
|
982
996
|
}
|
|
983
997
|
if (loaderScript && loaderScript.src) {
|
|
984
998
|
const scriptUrl = new URL(loaderScript.src);
|
|
@@ -1037,26 +1051,19 @@ function parseBoolean(value) {
|
|
|
1037
1051
|
* Show error when both follow_related and follow_upward are enabled
|
|
1038
1052
|
*/
|
|
1039
1053
|
function showParamConflictError() {
|
|
1040
|
-
const errorMessage = 'Cannot enable both follow_related and follow_upward';
|
|
1054
|
+
const errorMessage = 'Error: Cannot enable both follow_related and follow_upward';
|
|
1041
1055
|
const countrySelects = Array.from(document.querySelectorAll('.country-selection'));
|
|
1042
1056
|
for (const select of countrySelects) {
|
|
1043
|
-
|
|
1057
|
+
select.innerHTML = `<option value="${select.dataset.defaultValue ?? ''}" disabled>${errorMessage}</option>`;
|
|
1044
1058
|
}
|
|
1045
1059
|
const subdivisionSelects = Array.from(document.querySelectorAll('.subdivision-selection'));
|
|
1046
1060
|
for (const select of subdivisionSelects) {
|
|
1047
|
-
|
|
1061
|
+
select.innerHTML = `<option value="${select.dataset.defaultValue ?? ''}" disabled>${errorMessage}</option>`;
|
|
1048
1062
|
}
|
|
1049
1063
|
}
|
|
1050
1064
|
// Expose public loader
|
|
1051
1065
|
if (typeof window !== 'undefined') {
|
|
1052
1066
|
window.CountriesWidgetLoad = CountriesWidgetLoad;
|
|
1053
|
-
// Dispatch ready event to notify consumers that the widget is available
|
|
1054
|
-
// Use setTimeout(0) to ensure it fires after any synchronous code completes
|
|
1055
|
-
setTimeout(() => {
|
|
1056
|
-
if (typeof window !== 'undefined') {
|
|
1057
|
-
window.dispatchEvent(new CustomEvent('countriesWidget:ready'));
|
|
1058
|
-
}
|
|
1059
|
-
}, 0);
|
|
1060
1067
|
// Auto-init if script URL has auto_init=true (or not set, default is true)
|
|
1061
1068
|
// Use a function that waits for DOM to be ready and finds the script tag reliably
|
|
1062
1069
|
(function checkAutoInit() {
|
|
@@ -1068,16 +1075,10 @@ if (typeof window !== 'undefined') {
|
|
|
1068
1075
|
// Find the script tag that loaded this widget
|
|
1069
1076
|
let loaderScript = null;
|
|
1070
1077
|
// First try document.currentScript (works during script execution)
|
|
1071
|
-
// But only if it matches the widget pattern (not a bundled file)
|
|
1072
1078
|
if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
|
|
1073
|
-
|
|
1074
|
-
if (src && (src.includes('@countriesdb/widget') ||
|
|
1075
|
-
src.includes('widget/dist/index.js'))) {
|
|
1076
|
-
loaderScript = document.currentScript;
|
|
1077
|
-
}
|
|
1079
|
+
loaderScript = document.currentScript;
|
|
1078
1080
|
}
|
|
1079
|
-
|
|
1080
|
-
if (!loaderScript) {
|
|
1081
|
+
else {
|
|
1081
1082
|
// Fallback: find script tag with @countriesdb/widget in src
|
|
1082
1083
|
const scripts = Array.from(document.getElementsByTagName('script'));
|
|
1083
1084
|
loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
|
|
@@ -1085,13 +1086,7 @@ if (typeof window !== 'undefined') {
|
|
|
1085
1086
|
}
|
|
1086
1087
|
// Default to auto-init = true (only disable if explicitly set to false)
|
|
1087
1088
|
let shouldAutoInit = true;
|
|
1088
|
-
|
|
1089
|
-
? window.CountriesDBConfig || null
|
|
1090
|
-
: null;
|
|
1091
|
-
if (globalConfig && typeof globalConfig.autoInit !== 'undefined') {
|
|
1092
|
-
shouldAutoInit = !!globalConfig.autoInit;
|
|
1093
|
-
}
|
|
1094
|
-
else if (loaderScript && loaderScript.src) {
|
|
1089
|
+
if (loaderScript && loaderScript.src) {
|
|
1095
1090
|
try {
|
|
1096
1091
|
const scriptUrl = new URL(loaderScript.src);
|
|
1097
1092
|
const autoInit = scriptUrl.searchParams.get('auto_init');
|