@countriesdb/widget 0.1.24 → 0.1.26

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/dist/index.js CHANGED
@@ -752,27 +752,47 @@
752
752
  select.innerHTML += `<option value="${defaultValue}" disabled>Error: No country select present</option>`;
753
753
  }
754
754
  }
755
+ // Remove old event handlers if they exist (for re-initialization)
756
+ const oldHandlers = state.eventHandlers.get(select);
757
+ if (oldHandlers) {
758
+ if (oldHandlers.update) {
759
+ select.removeEventListener('change', oldHandlers.update);
760
+ }
761
+ if (oldHandlers.followRelated) {
762
+ select.removeEventListener('change', oldHandlers.followRelated);
763
+ }
764
+ if (oldHandlers.followUpward) {
765
+ select.removeEventListener('change', oldHandlers.followUpward);
766
+ }
767
+ }
768
+ // Create new event handlers
769
+ const handlers = {};
755
770
  // Always dispatch an update event for user-initiated subdivision changes
756
- select.addEventListener('change', (event) => {
771
+ handlers.update = (event) => {
757
772
  if (isWidgetInitiatedEvent(event)) {
758
773
  return;
759
774
  }
760
775
  dispatchUpdateEvent(select, { type: 'subdivision', reason: 'regular' });
761
- });
776
+ };
777
+ select.addEventListener('change', handlers.update);
762
778
  // --- follow_related (forward direction) ---
763
- select.addEventListener('change', async (event) => {
779
+ handlers.followRelated = async (event) => {
764
780
  if (isWidgetInitiatedEvent(event)) {
765
781
  return;
766
782
  }
767
783
  await handleFollowRelatedFromSubdivision(select, apiKey, backendUrl, state, config.followRelated, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, config, code));
768
- });
784
+ };
785
+ select.addEventListener('change', handlers.followRelated);
769
786
  // --- follow_upward (reverse direction) ---
770
- select.addEventListener('change', async (event) => {
787
+ handlers.followUpward = async (event) => {
771
788
  if (isWidgetInitiatedEvent(event)) {
772
789
  return;
773
790
  }
774
791
  await handleFollowUpwardFromSubdivision(select, apiKey, backendUrl, state, config.followUpward, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, config, code));
775
- });
792
+ };
793
+ select.addEventListener('change', handlers.followUpward);
794
+ // Store handlers for future cleanup
795
+ state.eventHandlers.set(select, handlers);
776
796
  }
777
797
  }
778
798
  /**
@@ -991,8 +1011,13 @@
991
1011
  // Subdivisions will be loaded by event handler
992
1012
  loadedInitialSubdivisions = true;
993
1013
  }
994
- // On change => update subdivisions
995
- select.addEventListener('change', async (event) => {
1014
+ // Remove old event handlers if they exist (for re-initialization)
1015
+ const oldCountryHandlers = state.eventHandlers.get(select);
1016
+ if (oldCountryHandlers?.countryChange) {
1017
+ select.removeEventListener('change', oldCountryHandlers.countryChange);
1018
+ }
1019
+ // Create new country change handler
1020
+ const countryChangeHandler = async (event) => {
996
1021
  if (isWidgetInitiatedEvent(event)) {
997
1022
  return;
998
1023
  }
@@ -1014,7 +1039,12 @@
1014
1039
  if (config.followUpward && !select.multiple && picked.is_subdivision_of) {
1015
1040
  await handleFollowUpwardFromCountry(select, apiKey, backendUrl, state, config.followUpward, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, subdivisionConfig, code));
1016
1041
  }
1017
- });
1042
+ };
1043
+ // Store and attach the handler
1044
+ const countryHandlers = state.eventHandlers.get(select) || {};
1045
+ countryHandlers.countryChange = countryChangeHandler;
1046
+ state.eventHandlers.set(select, countryHandlers);
1047
+ select.addEventListener('change', countryChangeHandler);
1018
1048
  }
1019
1049
  catch (error) {
1020
1050
  console.error('Failed to fetch countries:', error);
@@ -1089,6 +1119,7 @@
1089
1119
  subdivisionsMap: new WeakMap(),
1090
1120
  subdivisionsLanguageMap: new WeakMap(),
1091
1121
  isInitializing: new Set(),
1122
+ eventHandlers: new WeakMap(),
1092
1123
  };
1093
1124
  // Use empty string if publicKey is missing (will show error when API calls fail)
1094
1125
  const apiKey = config.publicKey || '';
@@ -1141,23 +1172,27 @@
1141
1172
  * Get configuration from options or script URL parameters
1142
1173
  */
1143
1174
  function getConfigFromOptionsOrScript(options) {
1175
+ // Check for global config first (for bundled widgets that need config before auto-init)
1176
+ const globalConfig = typeof window !== 'undefined' && window.CountriesDBConfig
1177
+ ? window.CountriesDBConfig
1178
+ : null;
1144
1179
  // Try to get config from script URL (for backward compatibility with widget.blade.php)
1145
1180
  let scriptUrl = null;
1146
1181
  try {
1147
1182
  let loaderScript = null;
1148
1183
  // First try document.currentScript (works during script execution)
1184
+ // But only if it matches the widget pattern (not a bundled file)
1149
1185
  if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
1150
- loaderScript = document.currentScript;
1186
+ const src = document.currentScript.src;
1187
+ if (src && (src.includes('@countriesdb/widget') || src.includes('widget/dist/index.js'))) {
1188
+ loaderScript = document.currentScript;
1189
+ }
1151
1190
  }
1152
- else {
1153
- // Fallback: find script tag with @countriesdb/widget in src
1191
+ // If currentScript didn't match, search for widget script
1192
+ if (!loaderScript) {
1154
1193
  const scripts = Array.from(document.getElementsByTagName('script'));
1155
1194
  loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
1156
1195
  s.src.includes('widget/dist/index.js'))) || null;
1157
- // If still not found, try the last script with src
1158
- if (!loaderScript) {
1159
- loaderScript = scripts.filter((s) => s.src).pop() || null;
1160
- }
1161
1196
  }
1162
1197
  if (loaderScript && loaderScript.src) {
1163
1198
  scriptUrl = new URL(loaderScript.src);
@@ -1167,39 +1202,57 @@
1167
1202
  // Ignore errors
1168
1203
  }
1169
1204
  const config = {
1170
- publicKey: options.publicKey || scriptUrl?.searchParams.get('public_key') || '',
1171
- backendUrl: options.backendUrl || scriptUrl?.searchParams.get('backend_url') || getBackendUrlFromScript(),
1172
- defaultLanguage: options.defaultLanguage || scriptUrl?.searchParams.get('default_language') || undefined,
1173
- forcedLanguage: options.forcedLanguage || scriptUrl?.searchParams.get('forced_language') || undefined,
1205
+ // Priority: options > globalConfig > scriptUrl params > defaults
1206
+ publicKey: options.publicKey ?? globalConfig?.publicKey ?? scriptUrl?.searchParams.get('public_key') ?? '',
1207
+ backendUrl: options.backendUrl ?? globalConfig?.backendUrl ?? scriptUrl?.searchParams.get('backend_url') ?? getBackendUrlFromScript(),
1208
+ defaultLanguage: options.defaultLanguage ?? globalConfig?.defaultLanguage ?? scriptUrl?.searchParams.get('default_language') ?? undefined,
1209
+ forcedLanguage: options.forcedLanguage ?? globalConfig?.forcedLanguage ?? scriptUrl?.searchParams.get('forced_language') ?? undefined,
1174
1210
  showSubdivisionType: options.showSubdivisionType !== undefined
1175
1211
  ? options.showSubdivisionType
1176
- : parseBoolean(scriptUrl?.searchParams.get('show_subdivision_type') ?? '1'),
1212
+ : globalConfig?.showSubdivisionType !== undefined
1213
+ ? globalConfig.showSubdivisionType
1214
+ : parseBoolean(scriptUrl?.searchParams.get('show_subdivision_type') ?? '1'),
1177
1215
  followRelated: options.followRelated !== undefined
1178
1216
  ? options.followRelated
1179
- : parseBoolean(scriptUrl?.searchParams.get('follow_related') ?? 'false'),
1217
+ : globalConfig?.followRelated !== undefined
1218
+ ? globalConfig.followRelated
1219
+ : parseBoolean(scriptUrl?.searchParams.get('follow_related') ?? 'false'),
1180
1220
  followUpward: options.followUpward !== undefined
1181
1221
  ? options.followUpward
1182
- : parseBoolean(scriptUrl?.searchParams.get('follow_upward') ?? 'false'),
1222
+ : globalConfig?.followUpward !== undefined
1223
+ ? globalConfig.followUpward
1224
+ : parseBoolean(scriptUrl?.searchParams.get('follow_upward') ?? 'false'),
1183
1225
  allowParentSelection: options.allowParentSelection !== undefined
1184
1226
  ? options.allowParentSelection
1185
- : parseBoolean(scriptUrl?.searchParams.get('allow_parent_selection') ?? 'false'),
1227
+ : globalConfig?.allowParentSelection !== undefined
1228
+ ? globalConfig.allowParentSelection
1229
+ : parseBoolean(scriptUrl?.searchParams.get('allow_parent_selection') ?? 'false'),
1186
1230
  isoCountryNames: options.isoCountryNames !== undefined
1187
1231
  ? options.isoCountryNames
1188
- : parseBoolean(scriptUrl?.searchParams.get('iso_country_names') ?? 'false'),
1232
+ : globalConfig?.isoCountryNames !== undefined
1233
+ ? globalConfig.isoCountryNames
1234
+ : parseBoolean(scriptUrl?.searchParams.get('iso_country_names') ?? 'false'),
1189
1235
  subdivisionRomanizationPreference: options.subdivisionRomanizationPreference ||
1236
+ globalConfig?.subdivisionRomanizationPreference ||
1190
1237
  scriptUrl?.searchParams.get('subdivision_romanization_preference') ||
1191
1238
  undefined,
1192
1239
  preferLocalVariant: options.preferLocalVariant !== undefined
1193
1240
  ? options.preferLocalVariant
1194
- : parseBoolean(scriptUrl?.searchParams.get('prefer_local_variant') ?? 'false'),
1241
+ : globalConfig?.preferLocalVariant !== undefined
1242
+ ? globalConfig.preferLocalVariant
1243
+ : parseBoolean(scriptUrl?.searchParams.get('prefer_local_variant') ?? 'false'),
1195
1244
  preferOfficialSubdivisions: options.preferOfficialSubdivisions !== undefined
1196
1245
  ? options.preferOfficialSubdivisions
1197
- : parseBoolean(scriptUrl?.searchParams.get('prefer_official') ?? 'false'),
1198
- countryNameFilter: options.countryNameFilter,
1199
- subdivisionNameFilter: options.subdivisionNameFilter,
1246
+ : globalConfig?.preferOfficialSubdivisions !== undefined
1247
+ ? globalConfig.preferOfficialSubdivisions
1248
+ : parseBoolean(scriptUrl?.searchParams.get('prefer_official') ?? 'false'),
1249
+ countryNameFilter: options.countryNameFilter ?? globalConfig?.countryNameFilter,
1250
+ subdivisionNameFilter: options.subdivisionNameFilter ?? globalConfig?.subdivisionNameFilter,
1200
1251
  autoInit: options.autoInit !== undefined
1201
1252
  ? options.autoInit
1202
- : parseBoolean(scriptUrl?.searchParams.get('auto_init') ?? 'true'),
1253
+ : globalConfig?.autoInit !== undefined
1254
+ ? globalConfig.autoInit
1255
+ : parseBoolean(scriptUrl?.searchParams.get('auto_init') ?? 'true'),
1203
1256
  };
1204
1257
  // Resolve filter functions from global scope if specified by name
1205
1258
  if (scriptUrl) {
@@ -1227,18 +1280,19 @@
1227
1280
  try {
1228
1281
  let loaderScript = null;
1229
1282
  // First try document.currentScript (works during script execution)
1283
+ // But only if it matches the widget pattern (not a bundled file)
1230
1284
  if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
1231
- loaderScript = document.currentScript;
1285
+ const src = document.currentScript.src;
1286
+ if (src && (src.includes('@countriesdb/widget') || src.includes('widget/dist/index.js'))) {
1287
+ loaderScript = document.currentScript;
1288
+ }
1232
1289
  }
1233
- else {
1234
- // Fallback: find script tag with @countriesdb/widget in src
1290
+ // If currentScript didn't match, search for widget script
1291
+ if (!loaderScript) {
1292
+ // Only consider script tags that loaded the widget bundle
1235
1293
  const scripts = Array.from(document.getElementsByTagName('script'));
1236
1294
  loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
1237
1295
  s.src.includes('widget/dist/index.js'))) || null;
1238
- // If still not found, try the last script with src
1239
- if (!loaderScript) {
1240
- loaderScript = scripts.filter((s) => s.src).pop() || null;
1241
- }
1242
1296
  }
1243
1297
  if (loaderScript && loaderScript.src) {
1244
1298
  const scriptUrl = new URL(loaderScript.src);
@@ -1321,18 +1375,28 @@
1321
1375
  // Find the script tag that loaded this widget
1322
1376
  let loaderScript = null;
1323
1377
  // First try document.currentScript (works during script execution)
1378
+ // But only if it matches the widget pattern (not a bundled file)
1324
1379
  if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
1325
- loaderScript = document.currentScript;
1380
+ const src = document.currentScript.src;
1381
+ if (src && (src.includes('@countriesdb/widget') || src.includes('widget/dist/index.js'))) {
1382
+ loaderScript = document.currentScript;
1383
+ }
1326
1384
  }
1327
- else {
1328
- // Fallback: find script tag with @countriesdb/widget in src
1385
+ // If currentScript didn't match, search for widget script
1386
+ if (!loaderScript) {
1329
1387
  const scripts = Array.from(document.getElementsByTagName('script'));
1330
1388
  loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
1331
1389
  s.src.includes('widget/dist/index.js'))) || null;
1332
1390
  }
1333
1391
  // Default to auto-init = true (only disable if explicitly set to false)
1334
1392
  let shouldAutoInit = true;
1335
- if (loaderScript && loaderScript.src) {
1393
+ const globalConfig = typeof window !== 'undefined'
1394
+ ? window.CountriesDBConfig || null
1395
+ : null;
1396
+ if (globalConfig && typeof globalConfig.autoInit !== 'undefined') {
1397
+ shouldAutoInit = !!globalConfig.autoInit;
1398
+ }
1399
+ else if (loaderScript && loaderScript.src) {
1336
1400
  try {
1337
1401
  const scriptUrl = new URL(loaderScript.src);
1338
1402
  const autoInit = scriptUrl.searchParams.get('auto_init');