SearchHeader.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. <template>
  2. <div id="findbar" class="findbar">
  3. <div id="findbarInputContainer" class="findbar-input-container">
  4. <div class="input-container">
  5. <input type="text" autocomplete="off" :placeholder="$t('leftPanel.searchPdf')" v-model="searchValue">
  6. <EmptyInput id="emptyInput" class="empty-input" :class="!searchValue && 'hidden'" @click="clearSearchResults" />
  7. </div>
  8. <div class="button-container">
  9. <Button
  10. img="icon-previous-left"
  11. id="findPrevious"
  12. class="toolbarButton"
  13. :class="!searchResults.length && 'disabled'"
  14. :title="$t('leftPanel.previousPhrase')"
  15. @click="previousButton"
  16. ><ArrowPrev />
  17. </Button>
  18. <Button
  19. img="icon-next-right"
  20. id="findNext"
  21. class="toolbarButton"
  22. :class="!searchResults.length && 'disabled'"
  23. :title="$t('leftPanel.nextPhrase')"
  24. @click="nextButton"
  25. ><ArrowNext />
  26. </Button>
  27. </div>
  28. </div>
  29. </div>
  30. </template>
  31. <script setup>
  32. import debounce from 'lodash.debounce'
  33. import { ref, watch, computed, toRaw } from "vue"
  34. import core from '@/core'
  35. import { useDocumentStore } from '@/stores/modules/document'
  36. import { useViewerStore } from '@/stores/modules/viewer'
  37. const waitTime = 200
  38. const isSearching = ref(false)
  39. const searchValue = ref('')
  40. const useDocument = useDocumentStore()
  41. const useViewer = useViewerStore()
  42. const searchResults = ref([])
  43. const rawActiveIndex = ref(0)
  44. const previousButton = () => {
  45. const reseults = searchResults.value
  46. const activeIndex = rawActiveIndex.value
  47. if (reseults.length > 0) {
  48. const prevIndex = activeIndex <= 0 ? reseults.length - 1 : activeIndex - 1
  49. core.setActiveSearchResult(toRaw(reseults[prevIndex]), prevIndex)
  50. rawActiveIndex.value = prevIndex
  51. }
  52. }
  53. const nextButton = () => {
  54. const reseults = searchResults.value
  55. const activeIndex = rawActiveIndex.value
  56. if (reseults.length > 0) {
  57. const nextIndex = activeIndex === reseults.length - 1 ? 0 : activeIndex + 1
  58. core.setActiveSearchResult(toRaw(reseults[nextIndex]), nextIndex)
  59. rawActiveIndex.value = nextIndex
  60. }
  61. }
  62. const clearSearchResults = () => {
  63. isSearching.value = false
  64. searchValue.value = ''
  65. useDocument.setSearchResults([])
  66. core.clearSearchResults()
  67. searchResults.value = []
  68. }
  69. const debouncedSearch = debounce(async (searchValue) => {
  70. if (searchValue && searchValue.length > 0) {
  71. isSearching.value = true
  72. const results = await core.search(searchValue)
  73. useDocument.setSearchResults(results)
  74. searchResults.value = results
  75. } else {
  76. clearSearchResults()
  77. }
  78. }, waitTime)
  79. const textInputChange = (searchValue) => {
  80. debouncedSearch(searchValue)
  81. }
  82. watch(searchValue, () => {
  83. textInputChange(searchValue.value)
  84. rawActiveIndex.value = 0
  85. })
  86. const activeTab = computed(() => useViewer.getActiveElementTab('leftPanelTab'))
  87. const isLeftPanelOpen = computed(() => useViewer.isElementOpen('leftPanel'))
  88. watch([activeTab, isLeftPanelOpen], () => {
  89. if (activeTab.value !== 'SEARCH' || !isLeftPanelOpen.value) {
  90. core.clearSearchResults()
  91. searchValue.value = ''
  92. rawActiveIndex.value = 0
  93. }
  94. })
  95. </script>
  96. <style lang="scss">
  97. .findbar {
  98. padding: 8px 0 8px 8px;
  99. .findbar-input-container {
  100. display: flex;
  101. align-items: center;
  102. justify-content: space-between;
  103. }
  104. .input-container {
  105. position: relative;
  106. flex-grow: 1;
  107. display: flex;
  108. width: 180px;
  109. padding: 0 8px;
  110. border-radius: 1px;
  111. border: 1px solid var(--c-findbar-input-border);
  112. background-color: var(--c-findbar-input-bg);
  113. }
  114. input {
  115. flex-grow: 1;
  116. width: 0;
  117. height: 30px;
  118. outline: none;
  119. padding: 5px 20px 5px 0px;
  120. box-shadow: none;
  121. border: none;
  122. background-color: var(--c-findbar-input-bg);
  123. color: var(--c-findbar-text);
  124. }
  125. .empty-input {
  126. position: absolute;
  127. right: 4px;
  128. top: 7px;
  129. cursor: pointer;
  130. }
  131. .toolbarLabel {
  132. font-size: 14px;
  133. line-height: 30px;
  134. color: var(--c-findbar-text);
  135. white-space: nowrap;
  136. }
  137. .button-container {
  138. display: flex;
  139. align-items: center;
  140. button {
  141. margin-left: 8px;
  142. padding: 0;
  143. color: var(--c-findbar-text);
  144. }
  145. }
  146. }
  147. </style>