search.vue 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <template lang="pug">
  2. .nav-item
  3. p.control(v-bind:class='{ "is-loading": searchload > 0 }')
  4. input.input#search-input(type='text', v-model='searchq', autofocus, @keyup.esc='closeSearch', @keyup.down='moveDownSearch', @keyup.up='moveUpSearch', @keyup.enter='moveSelectSearch', debounce='400', v-bind:placeholder='$t("search.placeholder")')
  5. transition(name='searchresults')
  6. .searchresults(v-show='searchactive', v-cloak)
  7. p.searchresults-label {{ $t('search.results') }}
  8. ul.searchresults-list
  9. li(v-if='searchres.length === 0')
  10. a: em {{ $t('search.nomatch') }}
  11. li(v-for='sres in searchres', v-bind:class='{ "is-active": searchmovekey === "res." + sres.entryPath }')
  12. a(v-bind:href='sres.entryPath') {{ sres.title }}
  13. p.searchresults-label(v-if='searchsuggest.length > 0') {{ $t('search.didyoumean') }}
  14. ul.searchresults-list(v-if='searchsuggest.length > 0')
  15. li(v-for='sug in searchsuggest', v-bind:class='{ "is-active": searchmovekey === "sug." + sug }')
  16. a(v-on:click='useSuggestion(sug)') {{ sug }}
  17. </template>
  18. <script>
  19. /* global siteRoot, socket, $ */
  20. export default {
  21. data() {
  22. return {
  23. searchq: '',
  24. searchres: [],
  25. searchsuggest: [],
  26. searchload: 0,
  27. searchactive: false,
  28. searchmoveidx: 0,
  29. searchmovekey: '',
  30. searchmovearr: []
  31. }
  32. },
  33. watch: {
  34. searchq: function (val, oldVal) {
  35. let self = this
  36. self.searchmoveidx = 0
  37. if (val.length >= 3) {
  38. self.searchactive = true
  39. self.searchload++
  40. socket.emit('search', { terms: val }, (data) => {
  41. self.searchres = self._.map(data.match, m => {
  42. m.entryPath = `${siteRoot}/${m.entryPath}`
  43. return m
  44. })
  45. self.searchsuggest = data.suggest
  46. self.searchmovearr = self._.concat([], self.searchres, self.searchsuggest)
  47. if (self.searchload > 0) { self.searchload-- }
  48. })
  49. } else {
  50. self.searchactive = false
  51. self.searchres = []
  52. self.searchsuggest = []
  53. self.searchmovearr = []
  54. self.searchload = 0
  55. }
  56. },
  57. searchmoveidx: function (val, oldVal) {
  58. if (val > 0) {
  59. this.searchmovekey = (this.searchmovearr[val - 1]) ?
  60. 'res.' + this.searchmovearr[val - 1].entryPath :
  61. 'sug.' + this.searchmovearr[val - 1]
  62. } else {
  63. this.searchmovekey = ''
  64. }
  65. }
  66. },
  67. methods: {
  68. useSuggestion: function (sug) {
  69. this.searchq = sug
  70. },
  71. closeSearch: function () {
  72. this.searchq = ''
  73. },
  74. moveSelectSearch: function () {
  75. if (this.searchmoveidx < 1) { return }
  76. let i = this.searchmoveidx - 1
  77. if (this.searchmovearr[i]) {
  78. window.location.assign(this.searchmovearr[i].entryPath)
  79. } else {
  80. this.searchq = this.searchmovearr[i]
  81. }
  82. },
  83. moveDownSearch: function () {
  84. if (this.searchmoveidx < this.searchmovearr.length) {
  85. this.searchmoveidx++
  86. }
  87. },
  88. moveUpSearch: function () {
  89. if (this.searchmoveidx > 0) {
  90. this.searchmoveidx--
  91. }
  92. }
  93. },
  94. mounted: function () {
  95. let self = this
  96. $('main').on('click', self.closeSearch)
  97. }
  98. }
  99. </script>