@underpostnet/underpost 2.97.0 → 2.97.1

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.
@@ -34,6 +34,7 @@ import { Badge } from './Badge.js';
34
34
  import { Worker } from './Worker.js';
35
35
  import { Scroll } from './Scroll.js';
36
36
  import { windowGetH, windowGetW } from './windowGetDimensions.js';
37
+ import { SearchBox } from './SearchBox.js';
37
38
 
38
39
  const logger = loggerFactory(import.meta, { trace: true });
39
40
 
@@ -549,6 +550,9 @@ const Modal = {
549
550
  const inputInfoNode = s(`.input-info-${inputSearchBoxId}`).cloneNode(true);
550
551
  s(`.input-info-${inputSearchBoxId}`).remove();
551
552
  {
553
+ // Inject SearchBox base styles
554
+ SearchBox.injectStyles();
555
+
552
556
  const id = 'search-box-history';
553
557
  const searchBoxHistoryId = id;
554
558
  const formDataInfoNode = [
@@ -591,6 +595,7 @@ const Modal = {
591
595
 
592
596
  const renderSearchResult = async (results) => {
593
597
  htmls(`.html-${searchBoxHistoryId}`, '');
598
+
594
599
  if (results.length === 0) {
595
600
  append(
596
601
  `.html-${searchBoxHistoryId}`,
@@ -609,108 +614,61 @@ const Modal = {
609
614
  }),
610
615
  }),
611
616
  );
617
+ return;
612
618
  }
613
- let indexResult = -1;
614
- for (const result of results) {
615
- indexResult++;
616
- const indexRender = indexResult;
617
- append(
618
- `.html-${searchBoxHistoryId}`,
619
- await BtnIcon.Render({
620
- label: `${
621
- result.fontAwesomeIcon
622
- ? html`<i class="${result.fontAwesomeIcon.classList.toString()}"></i> `
623
- : result.imgElement
624
- ? html`<img
625
- class="inl"
626
- src="${result.imgElement.src}"
627
- style="${renderCssAttr({ style: { width: '25px', height: '25px' } })}"
628
- />`
629
- : ''
630
- } ${Translate.Render(result.routerId)}`,
631
- class: `wfa search-result-btn-${result.routerId} ${
632
- indexResult === currentKeyBoardSearchBoxIndex ? 'main-btn-menu-active' : ''
633
- } search-result-btn-${indexResult}`,
634
- style: renderCssAttr({
635
- style: { padding: '3px', margin: '2px', 'text-align': 'left' },
636
- }),
637
- }),
638
- );
639
- s(`.search-result-btn-${result.routerId}`).onclick = () => {
640
- if (!s(`.html-${searchBoxHistoryId}`) || !s(`.html-${searchBoxHistoryId}`).hasChildNodes()) return;
641
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.remove(
642
- `main-btn-menu-active`,
643
- );
644
- currentKeyBoardSearchBoxIndex = indexRender;
645
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.add(
646
- `main-btn-menu-active`,
647
- );
648
- setSearchValue(`.search-result-btn-${result.routerId}`);
649
- };
650
- }
619
+
620
+ // Use SearchBox component for rendering results
621
+ const searchContext = {
622
+ RouterInstance: Worker.RouterInstance,
623
+ options: options,
624
+ onResultClick: () => {
625
+ // Dismiss search box on result click
626
+ if (s(`.${searchBoxHistoryId}`)) {
627
+ Modal.removeModal(searchBoxHistoryId);
628
+ }
629
+ },
630
+ };
631
+
632
+ SearchBox.renderResults(results, `html-${searchBoxHistoryId}`, searchContext);
651
633
  };
652
634
 
653
- const getResultSearchBox = (validatorData) => {
654
- if (!s(`.html-${searchBoxHistoryId}`) || !s(`.html-${searchBoxHistoryId}`).hasChildNodes()) return;
635
+ const getResultSearchBox = async (validatorData) => {
636
+ if (!s(`.html-${searchBoxHistoryId}`)) return;
655
637
  const { model, id } = validatorData;
638
+
656
639
  switch (model) {
657
640
  case 'search-box':
658
641
  {
659
- if (
660
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex] &&
661
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList
662
- )
663
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.remove(
664
- `main-btn-menu-active`,
665
- );
666
642
  currentKeyBoardSearchBoxIndex = 0;
667
- if (
668
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex] &&
669
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList
670
- )
671
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.add(
672
- `main-btn-menu-active`,
673
- );
674
643
  results = [];
675
- const routerInstance = Worker.RouterInstance.Routes();
676
- for (const _routerId of Object.keys(routerInstance)) {
677
- const routerId = _routerId.slice(1);
678
- if (routerId) {
679
- if (
680
- s(`.main-btn-${routerId}`) &&
681
- (routerId.toLowerCase().match(s(`.${id}`).value.toLowerCase()) ||
682
- (Translate.Data[routerId] &&
683
- Object.keys(Translate.Data[routerId]).filter((keyLang) =>
684
- Translate.Data[routerId][keyLang]
685
- .toLowerCase()
686
- .match(s(`.${id}`).value.toLowerCase()),
687
- ).length > 0))
688
- ) {
689
- const fontAwesomeIcon = getAllChildNodes(s(`.main-btn-${routerId}`)).find((e) => {
690
- return (
691
- e.classList &&
692
- Array.from(e.classList).find((e) => e.match('fa-') && !e.match('fa-grip-vertical'))
693
- );
694
- });
695
- const imgElement = getAllChildNodes(s(`.main-btn-${routerId}`)).find((e) => {
696
- return (
697
- e.classList &&
698
- Array.from(e.classList).find((e) =>
699
- options.searchCustomImgClass
700
- ? e.match(options.searchCustomImgClass)
701
- : e.match('img-btn-square-menu'),
702
- )
703
- );
704
- });
705
- if (imgElement || fontAwesomeIcon) {
706
- results.push({
707
- routerId,
708
- fontAwesomeIcon: fontAwesomeIcon,
709
- imgElement,
710
- });
711
- }
644
+
645
+ const query = s(`.${id}`) ? s(`.${id}`).value : '';
646
+ const trimmedQuery = query.trim();
647
+
648
+ // Use SearchBox component for extensible search
649
+ const searchContext = {
650
+ RouterInstance: Worker.RouterInstance,
651
+ options: options,
652
+ minQueryLength: options?.minSearchQueryLength || 1, // Allow single character search by default
653
+ onResultClick: () => {
654
+ // Dismiss search box on result click
655
+ if (s(`.${searchBoxHistoryId}`)) {
656
+ Modal.removeModal(searchBoxHistoryId);
712
657
  }
713
- }
658
+ },
659
+ };
660
+
661
+ // Check minimum query length (default: 1 character)
662
+ const minLength = searchContext.minQueryLength;
663
+ if (trimmedQuery.length >= minLength) {
664
+ results = await SearchBox.search(trimmedQuery, searchContext);
665
+ renderSearchResult(results);
666
+ } else if (trimmedQuery.length === 0) {
667
+ // Show history when query is empty
668
+ renderSearchResult(historySearchBox);
669
+ } else {
670
+ // Query is too short - show nothing or a hint
671
+ renderSearchResult([]);
714
672
  }
715
673
  }
716
674
  break;
@@ -718,8 +676,6 @@ const Modal = {
718
676
  default:
719
677
  break;
720
678
  }
721
- if (s(`.${inputSearchBoxId}`).value.trim()) renderSearchResult(results);
722
- else renderSearchResult(historySearchBox);
723
679
  };
724
680
 
725
681
  const searchBoxCallBack = async (validatorData) => {
@@ -745,25 +701,19 @@ const Modal = {
745
701
  const getDefaultSearchBoxSelector = () => `.search-result-btn-${currentKeyBoardSearchBoxIndex}`;
746
702
 
747
703
  const updateSearchBoxValue = (selector) => {
748
- if (!selector) selector = getDefaultSearchBoxSelector();
749
- // check exist childNodes
750
- if (!s(selector) || !s(selector).hasChildNodes()) return;
751
-
752
- if (s(selector).childNodes) {
753
- if (
754
- s(selector).childNodes[s(selector).childNodes.length - 1] &&
755
- s(selector).childNodes[s(selector).childNodes.length - 1].data &&
756
- s(selector).childNodes[s(selector).childNodes.length - 1].data.trim()
757
- ) {
758
- s(`.${inputSearchBoxId}`).value =
759
- s(selector).childNodes[s(selector).childNodes.length - 1].data.trim();
760
- } else if (
761
- s(selector).childNodes[s(selector).childNodes.length - 2] &&
762
- s(selector).childNodes[s(selector).childNodes.length - 2].outerText &&
763
- s(selector).childNodes[s(selector).childNodes.length - 2].outerText.trim()
764
- ) {
765
- s(`.${inputSearchBoxId}`).value =
766
- s(selector).childNodes[s(selector).childNodes.length - 2].outerText.trim();
704
+ if (!selector) {
705
+ // Get the currently active search result item
706
+ const activeItem = s(`.html-${searchBoxHistoryId} .search-result-item.active-search-result`);
707
+ if (activeItem) {
708
+ const titleEl = activeItem.querySelector('.search-result-title');
709
+ if (titleEl && titleEl.textContent) {
710
+ s(`.${inputSearchBoxId}`).value = titleEl.textContent.trim();
711
+ }
712
+ }
713
+ } else if (s(selector)) {
714
+ const titleEl = s(selector).querySelector('.search-result-title');
715
+ if (titleEl && titleEl.textContent) {
716
+ s(`.${inputSearchBoxId}`).value = titleEl.textContent.trim();
767
717
  }
768
718
  }
769
719
  checkHistoryBoxTitleStatus();
@@ -771,17 +721,29 @@ const Modal = {
771
721
  };
772
722
 
773
723
  const setSearchValue = (selector) => {
774
- if (!selector) selector = getDefaultSearchBoxSelector();
724
+ // Get all search result items
725
+ const allItems = sa(`.html-${searchBoxHistoryId} .search-result-item`);
726
+ if (!allItems || allItems.length === 0) return;
775
727
 
776
- // check exist childNodes
777
- if (!s(selector) || !s(selector).hasChildNodes()) return;
728
+ const activeItem = allItems[currentKeyBoardSearchBoxIndex];
729
+ if (!activeItem) return;
778
730
 
779
- historySearchBox = historySearchBox.filter(
780
- (h) => h.routerId !== results[currentKeyBoardSearchBoxIndex].routerId,
781
- );
782
- historySearchBox.unshift(results[currentKeyBoardSearchBoxIndex]);
783
- updateSearchBoxValue(selector);
784
- s(`.main-btn-${results[currentKeyBoardSearchBoxIndex].routerId}`).click();
731
+ const resultId = activeItem.getAttribute('data-result-id');
732
+ const resultType = activeItem.getAttribute('data-result-type');
733
+
734
+ if (resultType === 'route' && results[currentKeyBoardSearchBoxIndex]) {
735
+ historySearchBox = historySearchBox.filter(
736
+ (h) => h.routerId !== results[currentKeyBoardSearchBoxIndex].routerId,
737
+ );
738
+ historySearchBox.unshift(results[currentKeyBoardSearchBoxIndex]);
739
+ updateSearchBoxValue();
740
+ if (s(`.main-btn-${resultId}`)) {
741
+ s(`.main-btn-${resultId}`).click();
742
+ }
743
+ } else {
744
+ // Trigger click on custom result
745
+ activeItem.click();
746
+ }
785
747
  Modal.removeModal(searchBoxHistoryId);
786
748
  };
787
749
  let boxHistoryDelayRender = 0;
@@ -879,27 +841,29 @@ const Modal = {
879
841
  keys: ['ArrowUp'],
880
842
  eventCallBack: () => {
881
843
  if (s(`.${id}`)) {
882
- if (
883
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex] &&
884
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex - 1]
885
- ) {
886
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.remove(
887
- `main-btn-menu-active`,
888
- );
844
+ const allItems = sa(`.html-${searchBoxHistoryId} .search-result-item`);
845
+ if (!allItems || allItems.length === 0) return;
846
+
847
+ // Remove active class from current
848
+ if (allItems[currentKeyBoardSearchBoxIndex]) {
849
+ allItems[currentKeyBoardSearchBoxIndex].classList.remove('active-search-result');
850
+ }
851
+
852
+ // Navigate up
853
+ if (currentKeyBoardSearchBoxIndex > 0) {
889
854
  currentKeyBoardSearchBoxIndex--;
890
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.add(
891
- `main-btn-menu-active`,
892
- );
893
855
  } else {
894
- if (s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex])
895
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.remove(
896
- `main-btn-menu-active`,
897
- );
898
- currentKeyBoardSearchBoxIndex = s(`.html-${searchBoxHistoryId}`).childNodes.length - 1;
899
- if (s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex])
900
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.add(
901
- `main-btn-menu-active`,
902
- );
856
+ currentKeyBoardSearchBoxIndex = allItems.length - 1;
857
+ }
858
+
859
+ // Add active class to new and ensure visibility
860
+ if (allItems[currentKeyBoardSearchBoxIndex]) {
861
+ allItems[currentKeyBoardSearchBoxIndex].classList.add('active-search-result');
862
+ // Use optimized scroll method to ensure item is always visible
863
+ const container = s(`.html-${searchBoxHistoryId}`);
864
+ if (container) {
865
+ SearchBox.scrollIntoViewIfNeeded(allItems[currentKeyBoardSearchBoxIndex], container);
866
+ }
903
867
  }
904
868
  updateSearchBoxValue();
905
869
  }
@@ -912,27 +876,29 @@ const Modal = {
912
876
  keys: ['ArrowDown'],
913
877
  eventCallBack: () => {
914
878
  if (s(`.${id}`)) {
915
- if (
916
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex] &&
917
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex + 1]
918
- ) {
919
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.remove(
920
- `main-btn-menu-active`,
921
- );
879
+ const allItems = sa(`.html-${searchBoxHistoryId} .search-result-item`);
880
+ if (!allItems || allItems.length === 0) return;
881
+
882
+ // Remove active class from current
883
+ if (allItems[currentKeyBoardSearchBoxIndex]) {
884
+ allItems[currentKeyBoardSearchBoxIndex].classList.remove('active-search-result');
885
+ }
886
+
887
+ // Navigate down
888
+ if (currentKeyBoardSearchBoxIndex < allItems.length - 1) {
922
889
  currentKeyBoardSearchBoxIndex++;
923
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.add(
924
- `main-btn-menu-active`,
925
- );
926
890
  } else {
927
- if (s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex])
928
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.remove(
929
- `main-btn-menu-active`,
930
- );
931
891
  currentKeyBoardSearchBoxIndex = 0;
932
- if (s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex])
933
- s(`.html-${searchBoxHistoryId}`).childNodes[currentKeyBoardSearchBoxIndex].classList.add(
934
- `main-btn-menu-active`,
935
- );
892
+ }
893
+
894
+ // Add active class to new and ensure visibility
895
+ if (allItems[currentKeyBoardSearchBoxIndex]) {
896
+ allItems[currentKeyBoardSearchBoxIndex].classList.add('active-search-result');
897
+ // Use optimized scroll method to ensure item is always visible
898
+ const container = s(`.html-${searchBoxHistoryId}`);
899
+ if (container) {
900
+ SearchBox.scrollIntoViewIfNeeded(allItems[currentKeyBoardSearchBoxIndex], container);
901
+ }
936
902
  }
937
903
  updateSearchBoxValue();
938
904
  }