@countriesdb/widget 0.1.25 → 0.1.27
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.esm.js +89 -41
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +89 -41
- package/dist/index.js.map +1 -1
- package/dist/initialization.js +88 -41
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
/**
|
|
@@ -578,6 +598,11 @@ async function updateSubdivisionSelect(select, apiKey, backendUrl, state, config
|
|
|
578
598
|
const dataDefaultValue = !isMultiple
|
|
579
599
|
? select.dataset.defaultValue
|
|
580
600
|
: undefined;
|
|
601
|
+
// Preserve user's current selection before clearing innerHTML
|
|
602
|
+
// This prevents preselected values from overwriting user selections
|
|
603
|
+
const currentValue = select.value;
|
|
604
|
+
const defaultValue = select.dataset.defaultValue || '';
|
|
605
|
+
const hasUserSelection = currentValue && currentValue !== defaultValue && currentValue.trim() !== '';
|
|
581
606
|
select.innerHTML = buildSubdivisionOptionsHTML(subdivisions, select, subdivisionsLanguage, config.showSubdivisionType, config.allowParentSelection, config.subdivisionNameFilter);
|
|
582
607
|
// Restore data attributes after setting innerHTML
|
|
583
608
|
if (!isMultiple) {
|
|
@@ -588,41 +613,53 @@ async function updateSubdivisionSelect(select, apiKey, backendUrl, state, config
|
|
|
588
613
|
select.dataset.defaultValue = dataDefaultValue;
|
|
589
614
|
}
|
|
590
615
|
}
|
|
591
|
-
//
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
600
|
-
valueSetByWidget = true;
|
|
601
|
-
await triggerFollowLogic(select, apiKey, backendUrl, state, config.followRelated, config.followUpward, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, config, code), (countrySelect, key) => updateSubdivisions(countrySelect, key, backendUrl, state, config));
|
|
616
|
+
// Restore user's selection if it exists in the new options (user selection takes priority)
|
|
617
|
+
let userSelectionRestored = false;
|
|
618
|
+
if (hasUserSelection && !isMultiple) {
|
|
619
|
+
const optionExists = Array.from(select.options).some(opt => opt.value === currentValue);
|
|
620
|
+
if (optionExists) {
|
|
621
|
+
select.value = currentValue;
|
|
622
|
+
userSelectionRestored = true;
|
|
623
|
+
// Don't dispatch event here - user already selected it, no need to notify again
|
|
624
|
+
}
|
|
602
625
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
if (
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
626
|
+
// Manual preselection only if user hasn't selected anything
|
|
627
|
+
if (!userSelectionRestored) {
|
|
628
|
+
// Check if preselected value exists (applyPreselectedValue will read it from select element)
|
|
629
|
+
const hasPreselectedValue = (select.getAttribute('data-preselected') || select.dataset.preselected || select.dataset._widgetTempPreselect) !== undefined;
|
|
630
|
+
if (hasPreselectedValue) {
|
|
631
|
+
applyPreselectedValue(select, apiKey);
|
|
632
|
+
dispatchUpdateEvent(select, {
|
|
633
|
+
type: 'subdivision',
|
|
634
|
+
reason: 'preselected',
|
|
635
|
+
});
|
|
636
|
+
valueSetByWidget = true;
|
|
637
|
+
await triggerFollowLogic(select, apiKey, backendUrl, state, config.followRelated, config.followUpward, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, config, code), (countrySelect, key) => updateSubdivisions(countrySelect, key, backendUrl, state, config));
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
// Try GeoIP preselect (only if user hasn't selected anything)
|
|
641
|
+
if (shouldUseGeoIP) {
|
|
642
|
+
const preselectedSubdivision = subdivisions.find((subdivision) => subdivision.preselected);
|
|
643
|
+
if (preselectedSubdivision) {
|
|
644
|
+
const isMultiple = select.hasAttribute('multiple');
|
|
645
|
+
if (isMultiple) {
|
|
646
|
+
// For multi-select, find and select the option
|
|
647
|
+
const option = Array.from(select.options).find((opt) => opt.value === preselectedSubdivision.code);
|
|
648
|
+
if (option) {
|
|
649
|
+
option.selected = true;
|
|
650
|
+
}
|
|
614
651
|
}
|
|
652
|
+
else {
|
|
653
|
+
// Single select: set value directly
|
|
654
|
+
select.value = preselectedSubdivision.code;
|
|
655
|
+
}
|
|
656
|
+
dispatchUpdateEvent(select, {
|
|
657
|
+
type: 'subdivision',
|
|
658
|
+
reason: 'geoip',
|
|
659
|
+
});
|
|
660
|
+
valueSetByWidget = true;
|
|
661
|
+
await triggerFollowLogic(select, apiKey, backendUrl, state, config.followRelated, config.followUpward, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, config, code), (countrySelect, key) => updateSubdivisions(countrySelect, key, backendUrl, state, config));
|
|
615
662
|
}
|
|
616
|
-
else {
|
|
617
|
-
// Single select: set value directly
|
|
618
|
-
select.value = preselectedSubdivision.code;
|
|
619
|
-
}
|
|
620
|
-
dispatchUpdateEvent(select, {
|
|
621
|
-
type: 'subdivision',
|
|
622
|
-
reason: 'geoip',
|
|
623
|
-
});
|
|
624
|
-
valueSetByWidget = true;
|
|
625
|
-
await triggerFollowLogic(select, apiKey, backendUrl, state, config.followRelated, config.followUpward, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, config, code), (countrySelect, key) => updateSubdivisions(countrySelect, key, backendUrl, state, config));
|
|
626
663
|
}
|
|
627
664
|
}
|
|
628
665
|
}
|
|
@@ -745,8 +782,13 @@ async function setupCountrySelection(apiKey, backendUrl, state, config, subdivis
|
|
|
745
782
|
// Subdivisions will be loaded by event handler
|
|
746
783
|
loadedInitialSubdivisions = true;
|
|
747
784
|
}
|
|
748
|
-
//
|
|
749
|
-
|
|
785
|
+
// Remove old event handlers if they exist (for re-initialization)
|
|
786
|
+
const oldCountryHandlers = state.eventHandlers.get(select);
|
|
787
|
+
if (oldCountryHandlers?.countryChange) {
|
|
788
|
+
select.removeEventListener('change', oldCountryHandlers.countryChange);
|
|
789
|
+
}
|
|
790
|
+
// Create new country change handler
|
|
791
|
+
const countryChangeHandler = async (event) => {
|
|
750
792
|
if (isWidgetInitiatedEvent(event)) {
|
|
751
793
|
return;
|
|
752
794
|
}
|
|
@@ -768,7 +810,12 @@ async function setupCountrySelection(apiKey, backendUrl, state, config, subdivis
|
|
|
768
810
|
if (config.followUpward && !select.multiple && picked.is_subdivision_of) {
|
|
769
811
|
await handleFollowUpwardFromCountry(select, apiKey, backendUrl, state, config.followUpward, (s, key, code) => updateSubdivisionSelect(s, key, backendUrl, state, subdivisionConfig, code));
|
|
770
812
|
}
|
|
771
|
-
}
|
|
813
|
+
};
|
|
814
|
+
// Store and attach the handler
|
|
815
|
+
const countryHandlers = state.eventHandlers.get(select) || {};
|
|
816
|
+
countryHandlers.countryChange = countryChangeHandler;
|
|
817
|
+
state.eventHandlers.set(select, countryHandlers);
|
|
818
|
+
select.addEventListener('change', countryChangeHandler);
|
|
772
819
|
}
|
|
773
820
|
catch (error) {
|
|
774
821
|
console.error('Failed to fetch countries:', error);
|
|
@@ -843,6 +890,7 @@ async function CountriesWidgetLoad(options = {}) {
|
|
|
843
890
|
subdivisionsMap: new WeakMap(),
|
|
844
891
|
subdivisionsLanguageMap: new WeakMap(),
|
|
845
892
|
isInitializing: new Set(),
|
|
893
|
+
eventHandlers: new WeakMap(),
|
|
846
894
|
};
|
|
847
895
|
// Use empty string if publicKey is missing (will show error when API calls fail)
|
|
848
896
|
const apiKey = config.publicKey || '';
|