@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/README.md CHANGED
@@ -78,7 +78,6 @@ import { CountriesWidgetLoad } from '@countriesdb/widget';
78
78
 
79
79
  CountriesWidgetLoad({
80
80
  publicKey: 'YOUR_PUBLIC_KEY',
81
- backendUrl: 'https://api.countriesdb.com',
82
81
  defaultLanguage: 'en',
83
82
  enableGeolocation: true
84
83
  });
package/dist/index.esm.js CHANGED
@@ -506,27 +506,47 @@ async function setupSubdivisionSelection(apiKey, backendUrl, state, config) {
506
506
  select.innerHTML += `<option value="${defaultValue}" disabled>Error: No country select present</option>`;
507
507
  }
508
508
  }
509
+ // Remove old event handlers if they exist (for re-initialization)
510
+ const oldHandlers = state.eventHandlers.get(select);
511
+ if (oldHandlers) {
512
+ if (oldHandlers.update) {
513
+ select.removeEventListener('change', oldHandlers.update);
514
+ }
515
+ if (oldHandlers.followRelated) {
516
+ select.removeEventListener('change', oldHandlers.followRelated);
517
+ }
518
+ if (oldHandlers.followUpward) {
519
+ select.removeEventListener('change', oldHandlers.followUpward);
520
+ }
521
+ }
522
+ // Create new event handlers
523
+ const handlers = {};
509
524
  // Always dispatch an update event for user-initiated subdivision changes
510
- select.addEventListener('change', (event) => {
525
+ handlers.update = (event) => {
511
526
  if (isWidgetInitiatedEvent(event)) {
512
527
  return;
513
528
  }
514
529
  dispatchUpdateEvent(select, { type: 'subdivision', reason: 'regular' });
515
- });
530
+ };
531
+ select.addEventListener('change', handlers.update);
516
532
  // --- follow_related (forward direction) ---
517
- select.addEventListener('change', async (event) => {
533
+ handlers.followRelated = async (event) => {
518
534
  if (isWidgetInitiatedEvent(event)) {
519
535
  return;
520
536
  }
521
537
  await handleFollowRelatedFromSubdivision(select, apiKey, backendUrl, state, config.followRelated, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, config, code));
522
- });
538
+ };
539
+ select.addEventListener('change', handlers.followRelated);
523
540
  // --- follow_upward (reverse direction) ---
524
- select.addEventListener('change', async (event) => {
541
+ handlers.followUpward = async (event) => {
525
542
  if (isWidgetInitiatedEvent(event)) {
526
543
  return;
527
544
  }
528
545
  await handleFollowUpwardFromSubdivision(select, apiKey, backendUrl, state, config.followUpward, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, config, code));
529
- });
546
+ };
547
+ select.addEventListener('change', handlers.followUpward);
548
+ // Store handlers for future cleanup
549
+ state.eventHandlers.set(select, handlers);
530
550
  }
531
551
  }
532
552
  /**
@@ -745,8 +765,13 @@ async function setupCountrySelection(apiKey, backendUrl, state, config, subdivis
745
765
  // Subdivisions will be loaded by event handler
746
766
  loadedInitialSubdivisions = true;
747
767
  }
748
- // On change => update subdivisions
749
- select.addEventListener('change', async (event) => {
768
+ // Remove old event handlers if they exist (for re-initialization)
769
+ const oldCountryHandlers = state.eventHandlers.get(select);
770
+ if (oldCountryHandlers?.countryChange) {
771
+ select.removeEventListener('change', oldCountryHandlers.countryChange);
772
+ }
773
+ // Create new country change handler
774
+ const countryChangeHandler = async (event) => {
750
775
  if (isWidgetInitiatedEvent(event)) {
751
776
  return;
752
777
  }
@@ -768,7 +793,12 @@ async function setupCountrySelection(apiKey, backendUrl, state, config, subdivis
768
793
  if (config.followUpward && !select.multiple && picked.is_subdivision_of) {
769
794
  await handleFollowUpwardFromCountry(select, apiKey, backendUrl, state, config.followUpward, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, subdivisionConfig, code));
770
795
  }
771
- });
796
+ };
797
+ // Store and attach the handler
798
+ const countryHandlers = state.eventHandlers.get(select) || {};
799
+ countryHandlers.countryChange = countryChangeHandler;
800
+ state.eventHandlers.set(select, countryHandlers);
801
+ select.addEventListener('change', countryChangeHandler);
772
802
  }
773
803
  catch (error) {
774
804
  console.error('Failed to fetch countries:', error);
@@ -843,6 +873,7 @@ async function CountriesWidgetLoad(options = {}) {
843
873
  subdivisionsMap: new WeakMap(),
844
874
  subdivisionsLanguageMap: new WeakMap(),
845
875
  isInitializing: new Set(),
876
+ eventHandlers: new WeakMap(),
846
877
  };
847
878
  // Use empty string if publicKey is missing (will show error when API calls fail)
848
879
  const apiKey = config.publicKey || '';
@@ -895,23 +926,27 @@ async function CountriesWidgetLoad(options = {}) {
895
926
  * Get configuration from options or script URL parameters
896
927
  */
897
928
  function getConfigFromOptionsOrScript(options) {
929
+ // Check for global config first (for bundled widgets that need config before auto-init)
930
+ const globalConfig = typeof window !== 'undefined' && window.CountriesDBConfig
931
+ ? window.CountriesDBConfig
932
+ : null;
898
933
  // Try to get config from script URL (for backward compatibility with widget.blade.php)
899
934
  let scriptUrl = null;
900
935
  try {
901
936
  let loaderScript = null;
902
937
  // First try document.currentScript (works during script execution)
938
+ // But only if it matches the widget pattern (not a bundled file)
903
939
  if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
904
- loaderScript = document.currentScript;
940
+ const src = document.currentScript.src;
941
+ if (src && (src.includes('@countriesdb/widget') || src.includes('widget/dist/index.js'))) {
942
+ loaderScript = document.currentScript;
943
+ }
905
944
  }
906
- else {
907
- // Fallback: find script tag with @countriesdb/widget in src
945
+ // If currentScript didn't match, search for widget script
946
+ if (!loaderScript) {
908
947
  const scripts = Array.from(document.getElementsByTagName('script'));
909
948
  loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
910
949
  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
- }
915
950
  }
916
951
  if (loaderScript && loaderScript.src) {
917
952
  scriptUrl = new URL(loaderScript.src);
@@ -921,39 +956,57 @@ function getConfigFromOptionsOrScript(options) {
921
956
  // Ignore errors
922
957
  }
923
958
  const config = {
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,
959
+ // Priority: options > globalConfig > scriptUrl params > defaults
960
+ publicKey: options.publicKey ?? globalConfig?.publicKey ?? scriptUrl?.searchParams.get('public_key') ?? '',
961
+ backendUrl: options.backendUrl ?? globalConfig?.backendUrl ?? scriptUrl?.searchParams.get('backend_url') ?? getBackendUrlFromScript(),
962
+ defaultLanguage: options.defaultLanguage ?? globalConfig?.defaultLanguage ?? scriptUrl?.searchParams.get('default_language') ?? undefined,
963
+ forcedLanguage: options.forcedLanguage ?? globalConfig?.forcedLanguage ?? scriptUrl?.searchParams.get('forced_language') ?? undefined,
928
964
  showSubdivisionType: options.showSubdivisionType !== undefined
929
965
  ? options.showSubdivisionType
930
- : parseBoolean(scriptUrl?.searchParams.get('show_subdivision_type') ?? '1'),
966
+ : globalConfig?.showSubdivisionType !== undefined
967
+ ? globalConfig.showSubdivisionType
968
+ : parseBoolean(scriptUrl?.searchParams.get('show_subdivision_type') ?? '1'),
931
969
  followRelated: options.followRelated !== undefined
932
970
  ? options.followRelated
933
- : parseBoolean(scriptUrl?.searchParams.get('follow_related') ?? 'false'),
971
+ : globalConfig?.followRelated !== undefined
972
+ ? globalConfig.followRelated
973
+ : parseBoolean(scriptUrl?.searchParams.get('follow_related') ?? 'false'),
934
974
  followUpward: options.followUpward !== undefined
935
975
  ? options.followUpward
936
- : parseBoolean(scriptUrl?.searchParams.get('follow_upward') ?? 'false'),
976
+ : globalConfig?.followUpward !== undefined
977
+ ? globalConfig.followUpward
978
+ : parseBoolean(scriptUrl?.searchParams.get('follow_upward') ?? 'false'),
937
979
  allowParentSelection: options.allowParentSelection !== undefined
938
980
  ? options.allowParentSelection
939
- : parseBoolean(scriptUrl?.searchParams.get('allow_parent_selection') ?? 'false'),
981
+ : globalConfig?.allowParentSelection !== undefined
982
+ ? globalConfig.allowParentSelection
983
+ : parseBoolean(scriptUrl?.searchParams.get('allow_parent_selection') ?? 'false'),
940
984
  isoCountryNames: options.isoCountryNames !== undefined
941
985
  ? options.isoCountryNames
942
- : parseBoolean(scriptUrl?.searchParams.get('iso_country_names') ?? 'false'),
986
+ : globalConfig?.isoCountryNames !== undefined
987
+ ? globalConfig.isoCountryNames
988
+ : parseBoolean(scriptUrl?.searchParams.get('iso_country_names') ?? 'false'),
943
989
  subdivisionRomanizationPreference: options.subdivisionRomanizationPreference ||
990
+ globalConfig?.subdivisionRomanizationPreference ||
944
991
  scriptUrl?.searchParams.get('subdivision_romanization_preference') ||
945
992
  undefined,
946
993
  preferLocalVariant: options.preferLocalVariant !== undefined
947
994
  ? options.preferLocalVariant
948
- : parseBoolean(scriptUrl?.searchParams.get('prefer_local_variant') ?? 'false'),
995
+ : globalConfig?.preferLocalVariant !== undefined
996
+ ? globalConfig.preferLocalVariant
997
+ : parseBoolean(scriptUrl?.searchParams.get('prefer_local_variant') ?? 'false'),
949
998
  preferOfficialSubdivisions: options.preferOfficialSubdivisions !== undefined
950
999
  ? options.preferOfficialSubdivisions
951
- : parseBoolean(scriptUrl?.searchParams.get('prefer_official') ?? 'false'),
952
- countryNameFilter: options.countryNameFilter,
953
- subdivisionNameFilter: options.subdivisionNameFilter,
1000
+ : globalConfig?.preferOfficialSubdivisions !== undefined
1001
+ ? globalConfig.preferOfficialSubdivisions
1002
+ : parseBoolean(scriptUrl?.searchParams.get('prefer_official') ?? 'false'),
1003
+ countryNameFilter: options.countryNameFilter ?? globalConfig?.countryNameFilter,
1004
+ subdivisionNameFilter: options.subdivisionNameFilter ?? globalConfig?.subdivisionNameFilter,
954
1005
  autoInit: options.autoInit !== undefined
955
1006
  ? options.autoInit
956
- : parseBoolean(scriptUrl?.searchParams.get('auto_init') ?? 'true'),
1007
+ : globalConfig?.autoInit !== undefined
1008
+ ? globalConfig.autoInit
1009
+ : parseBoolean(scriptUrl?.searchParams.get('auto_init') ?? 'true'),
957
1010
  };
958
1011
  // Resolve filter functions from global scope if specified by name
959
1012
  if (scriptUrl) {
@@ -981,18 +1034,19 @@ function getBackendUrlFromScript() {
981
1034
  try {
982
1035
  let loaderScript = null;
983
1036
  // First try document.currentScript (works during script execution)
1037
+ // But only if it matches the widget pattern (not a bundled file)
984
1038
  if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
985
- loaderScript = document.currentScript;
1039
+ const src = document.currentScript.src;
1040
+ if (src && (src.includes('@countriesdb/widget') || src.includes('widget/dist/index.js'))) {
1041
+ loaderScript = document.currentScript;
1042
+ }
986
1043
  }
987
- else {
988
- // Fallback: find script tag with @countriesdb/widget in src
1044
+ // If currentScript didn't match, search for widget script
1045
+ if (!loaderScript) {
1046
+ // Only consider script tags that loaded the widget bundle
989
1047
  const scripts = Array.from(document.getElementsByTagName('script'));
990
1048
  loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
991
1049
  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
- }
996
1050
  }
997
1051
  if (loaderScript && loaderScript.src) {
998
1052
  const scriptUrl = new URL(loaderScript.src);
@@ -1075,18 +1129,28 @@ if (typeof window !== 'undefined') {
1075
1129
  // Find the script tag that loaded this widget
1076
1130
  let loaderScript = null;
1077
1131
  // First try document.currentScript (works during script execution)
1132
+ // But only if it matches the widget pattern (not a bundled file)
1078
1133
  if (document.currentScript && document.currentScript instanceof HTMLScriptElement) {
1079
- loaderScript = document.currentScript;
1134
+ const src = document.currentScript.src;
1135
+ if (src && (src.includes('@countriesdb/widget') || src.includes('widget/dist/index.js'))) {
1136
+ loaderScript = document.currentScript;
1137
+ }
1080
1138
  }
1081
- else {
1082
- // Fallback: find script tag with @countriesdb/widget in src
1139
+ // If currentScript didn't match, search for widget script
1140
+ if (!loaderScript) {
1083
1141
  const scripts = Array.from(document.getElementsByTagName('script'));
1084
1142
  loaderScript = scripts.find((s) => s.src && (s.src.includes('@countriesdb/widget') ||
1085
1143
  s.src.includes('widget/dist/index.js'))) || null;
1086
1144
  }
1087
1145
  // Default to auto-init = true (only disable if explicitly set to false)
1088
1146
  let shouldAutoInit = true;
1089
- if (loaderScript && loaderScript.src) {
1147
+ const globalConfig = typeof window !== 'undefined'
1148
+ ? window.CountriesDBConfig || null
1149
+ : null;
1150
+ if (globalConfig && typeof globalConfig.autoInit !== 'undefined') {
1151
+ shouldAutoInit = !!globalConfig.autoInit;
1152
+ }
1153
+ else if (loaderScript && loaderScript.src) {
1090
1154
  try {
1091
1155
  const scriptUrl = new URL(loaderScript.src);
1092
1156
  const autoInit = scriptUrl.searchParams.get('auto_init');