Search.vue 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <template>
  2. <div id="search" class="" :class="[isloading ? loading : '', wrapperClass]">
  3. <form class="search-form row">
  4. <fieldset class="" :class="['search', 'small-col-10', firstFieldsetClass]">
  5. <div>
  6. <label for="keys">Recherche</label>
  7. <input
  8. id="keys"
  9. v-model="keys"
  10. type="text"
  11. placeholder="Rechercher"
  12. @keydown.enter.prevent="submit"
  13. >
  14. <v-select
  15. id="search-type"
  16. type="select"
  17. placeholder="dans ..."
  18. append-to-body
  19. :calculate-position="dropDownMenuPos"
  20. :options="searchTypeOptions"
  21. :clearable="false"
  22. :value="searchTypeValue"
  23. @input="onSearchTypeSelected"
  24. />
  25. </div>
  26. <span
  27. v-if="!isloading"
  28. class="mdi mdi-magnify"
  29. title="rechercher"
  30. @click.prevent="submit"
  31. @keydown.enter.prevent="submit"
  32. />
  33. <span
  34. v-else
  35. class="mdi mdi-loading"
  36. title="chargement"
  37. />
  38. </fieldset>
  39. <fieldset v-if="filters.texts.length && searchOpened" class="filters filters-texts small-col-4 med-col-4 large-col-4">
  40. <v-select
  41. id="filters-texts"
  42. type="select"
  43. placeholder="Filtrer par textes"
  44. append-to-body
  45. :calculate-position="dropDownMenuPos"
  46. :options="textsOptions"
  47. :value="activeFilters.texts"
  48. @input="onFiltersTextSelected"
  49. />
  50. </fieldset>
  51. <fieldset v-if="filters.persons.length && searchOpened" class="filters filters-nominum small-col-4 med-col-2 large-col-2">
  52. <v-select
  53. id="filters-nominum"
  54. type="select"
  55. placeholder="Filtrer par personnes"
  56. append-to-body
  57. :calculate-position="dropDownMenuPos"
  58. :options="personsOptions"
  59. :value="activeFilters.persons"
  60. multiple
  61. @input="onFiltersNominumSelected"
  62. />
  63. </fieldset>
  64. <fieldset v-if="filters.places.length && searchOpened" class="filters filters-locorum small-col-4 med-col-2 large-col-2">
  65. <v-select
  66. id="filters-locorum"
  67. type="select"
  68. placeholder="Filtrer par lieux"
  69. append-to-body
  70. :calculate-position="dropDownMenuPos"
  71. :options="placesOptions"
  72. :value="activeFilters.places"
  73. multiple
  74. @input="onFiltersLocorumSelected"
  75. />
  76. </fieldset>
  77. <fieldset v-if="filters.objects.length && searchOpened" class="filters filters-operum small-col-4 med-col-2 large-col-2">
  78. <v-select
  79. id="filters-operum"
  80. type="select"
  81. placeholder="Filtrer par œuvres"
  82. append-to-body
  83. :calculate-position="dropDownMenuPos"
  84. :options="objectsOptions"
  85. :value="activeFilters.objects"
  86. multiple
  87. @input="onFiltersOperumSelected"
  88. />
  89. </fieldset>
  90. </form>
  91. </div>
  92. </template>
  93. <script>
  94. import { createPopper } from '@popperjs/core'
  95. import { mapActions, mapMutations, mapState } from 'vuex'
  96. export default {
  97. name: 'Search',
  98. data: () => ({
  99. }),
  100. computed: {
  101. // searchOpened: {
  102. // get () { return this.$store.state.Search.opened },
  103. // set (value) { this.$store.commit('Search/setOpened', value) }
  104. // },
  105. ...mapState({
  106. isloading: state => state.Search.isloading,
  107. searchTypeOptions: state => state.Search.searchTypeOptions,
  108. searchTypeValue: state => state.Search.searchTypeValue,
  109. filters: state => state.Search.filters,
  110. activeFilters: state => state.Search.activeFilters,
  111. searchOpened: state => state.Search.opened,
  112. corpusLoaded: state => state.Corpus.corpusLoaded,
  113. results: state => state.Corpus.results
  114. }),
  115. // TODO: do not synch keys instantetly (infinite loading will drop)
  116. wrapperClass () {
  117. console.log('this.$route.name', this.$route.name)
  118. if (this.$route.name === 'home' && (!this.results || !this.results.length)) {
  119. return 'small-col-11 med-col-4 large-col-4'
  120. } else {
  121. return 'med-col-11 large-col-11'
  122. }
  123. },
  124. firstFieldsetClass () {
  125. return (this.$route.name === 'home' && (!this.results || !this.results.length)) ? 'med-col-10 large-col-10' : 'med-col-4 large-col-4'
  126. },
  127. keys: {
  128. get () { return this.$store.state.Search.keys },
  129. set (value) { this.$store.commit('Search/setKeys', value) }
  130. },
  131. personsOptions () {
  132. return this.filters.persons.filter(option => !this.activeFilters.persons.includes(option))
  133. },
  134. placesOptions () {
  135. return this.filters.places.filter(option => !this.activeFilters.places.includes(option))
  136. },
  137. objectsOptions () {
  138. return this.filters.objects.filter(option => !this.activeFilters.objects.includes(option))
  139. },
  140. textsOptions () {
  141. return this.filters.texts.filter(option => !this.activeFilters.texts.includes(option))
  142. }
  143. },
  144. methods: {
  145. ...mapMutations({
  146. setSearchTypeValue: 'Search/setSearchTypeValue',
  147. setActiveFilters: 'Search/setActiveFilters'
  148. }),
  149. ...mapActions({
  150. newSearch: 'Search/newSearch',
  151. updateSearch: 'Search/updateSearch'
  152. }),
  153. submit () {
  154. // console.log('submited', this.keys)
  155. this.newSearch()
  156. },
  157. dropDownMenuPos (dropdownList, component, { width }) {
  158. /**
  159. * We need to explicitly define the dropdown width since
  160. * it is usually inherited from the parent with CSS.
  161. */
  162. dropdownList.style.width = width
  163. /**
  164. * Here we position the dropdownList relative to the $refs.toggle Element.
  165. *
  166. * The 'offset' modifier aligns the dropdown so that the $refs.toggle and
  167. * the dropdownList overlap by 1 pixel.
  168. *
  169. * The 'toggleClass' modifier adds a 'drop-up' class to the Vue Select
  170. * wrapper so that we can set some styles for when the dropdown is placed
  171. * above.
  172. */
  173. const popper = createPopper(component.$refs.toggle, dropdownList, {
  174. placement: 'top',
  175. modifiers: [
  176. {
  177. name: 'offset',
  178. options: {
  179. offset: [0, -1]
  180. }
  181. },
  182. {
  183. name: 'toggleClass',
  184. enabled: true,
  185. phase: 'write',
  186. fn ({ state }) {
  187. component.$el.classList.toggle('drop-up', state.placement === 'top')
  188. }
  189. }]
  190. })
  191. /**
  192. * To prevent memory leaks Popper needs to be destroyed.
  193. * If you return function, it will be called just before dropdown is removed from DOM.
  194. */
  195. return () => popper.destroy()
  196. },
  197. onSearchTypeSelected (e) {
  198. console.log('onSearchTypeSelected', e)
  199. this.setSearchTypeValue(e)
  200. },
  201. onFiltersNominumSelected (e) {
  202. console.log('onFiltersNominumSelected', e)
  203. this.setActiveFilters({ filter: 'persons', value: e })
  204. this.updateSearch()
  205. },
  206. onFiltersLocorumSelected (e) {
  207. console.log('onFiltersLocorumSelected', e)
  208. this.setActiveFilters({ filter: 'places', value: e })
  209. this.updateSearch()
  210. },
  211. onFiltersOperumSelected (e) {
  212. console.log('onFiltersOperumSelected', e)
  213. this.setActiveFilters({ filter: 'objects', value: e })
  214. this.updateSearch()
  215. },
  216. onFiltersTextSelected (e) {
  217. console.log('onFiltersTextSelected', e)
  218. // as texts is not multiple, convert one object value to array [e]
  219. this.setActiveFilters({ filter: 'texts', value: e ? [e] : [] })
  220. this.updateSearch()
  221. }
  222. }
  223. }
  224. </script>
  225. <style lang="scss" scoped>
  226. </style>