Skip to content
Snippets Groups Projects
Autocomplete.vue 7.44 KiB
Newer Older
<template>
  <div class="autocomplete-container" :class="$vuetify.breakpoint.name">
Henrik Askjer's avatar
Henrik Askjer committed
    <v-combobox
Ole Voldsæter's avatar
Ole Voldsæter committed
        v-model="select"
        :loading="loading"
        :items="items"
        :search-input.sync="search"
Henrik Askjer's avatar
Henrik Askjer committed
        item-text="match"
Henrik Askjer's avatar
Henrik Askjer committed
        :menu-props="{maxHeight: $vuetify.breakpoint.name === 'xs' ? 190 : 500, transition: 'fade-transition', allowOverflow: true}"
Ole Voldsæter's avatar
Ole Voldsæter committed
        prepend-inner-icon="search"
        return-object
        rounded
Henrik Askjer's avatar
Henrik Askjer committed
        clearable
Ole Voldsæter's avatar
Ole Voldsæter committed
        hide-no-data
        no-filter
Henrik Askjer's avatar
Henrik Askjer committed
        auto-select-first
Ole Voldsæter's avatar
Ole Voldsæter committed
        hide-details
Henrik Askjer's avatar
Henrik Askjer committed
        :label="$t('search_placeholder')"
Ole Voldsæter's avatar
Ole Voldsæter committed
        solo
Henrik Askjer's avatar
Henrik Askjer committed
        :placeholder="$t('search_placeholder')"
Ole Voldsæter's avatar
Ole Voldsæter committed
        ref="autocomplete"
Henrik Askjer's avatar
Henrik Askjer committed
        :dense="$vuetify.breakpoint.mdAndDown"
Ole Voldsæter's avatar
Ole Voldsæter committed
      >
Henrik Askjer's avatar
Henrik Askjer committed
      <template v-slot:append>
        <div v-if="!$parent.error && $parent.lang=='bm,nn'">
        <a v-if="$parent.search_results.bm && $parent.search_results.bm.length > 0" href="#result0" class="accessibility_link" tabindex="0">{{$t('accessibility.bm')}}</a>
        <a v-if="$parent.search_results.nn && $parent.search_results.nn.length > 0" :href="'#result'+($parent.search_results.bm? $parent.search_results.bm.length : 0)" class="accessibility_link" tabindex="0">{{$t('accessibility.nn')}}</a>
        </div>
        <div v-else>
          <a href="#result0" class="accessibility_link" tabindex="0">{{$t('accessibility.main_content')}}</a>
        </div>
                <a href="#top_menu" class="accessibility_link"
                   @click="$store.commit('toggleMenu')">
            {{$t('accessibility.menu')}}</a>

        <v-divider vertical/>
Henrik Askjer's avatar
Henrik Askjer committed
        <v-menu allowOverflow: true offsetY v-model="dictMenuOpened">
Henrik Askjer's avatar
Henrik Askjer committed
          
        <template v-slot:activator="{ on, attrs }">
       <v-btn  class="search-field-button"
               v-bind="attrs"
               v-on="on"
               plain
               depressed 
               color = "primary" 
               text 
               @click.native="items=[]">
               
          <v-icon left>book</v-icon>
Henrik Askjer's avatar
Henrik Askjer committed
          <span v-if="$vuetify.breakpoint.mdAndUp">
Henrik Askjer's avatar
Henrik Askjer committed
          {{$t(`dicts.${$parent.lang}`)}}
Henrik Askjer's avatar
Henrik Askjer committed
          <v-icon right>{{ dictMenuOpened? 'expand_less' : 'expand_more'}}</v-icon>
Henrik Askjer's avatar
Henrik Askjer committed
          </span><span v-if="$vuetify.breakpoint.smAndDown">{{$t(`dicts_short.${$parent.lang}`)}}</span></v-btn>
                </template>
        <v-list>
          <v-list-item  v-for="item in ['bm,nn','bm','nn'].map(l => {return {label: $t(`dicts.${l}`), tag: l}})" :key="item.tag"
Henrik Askjer's avatar
Henrik Askjer committed
          active-class="v-list-item--active" @click="update_lang_form(item.tag)">
                <v-list-item-icon v-if="$parent.lang == item.tag"><v-icon color="primary">radio_button_checked</v-icon></v-list-item-icon>
                <v-list-item-icon v-else><v-icon>radio_button_unchecked</v-icon></v-list-item-icon>
Henrik Askjer's avatar
Henrik Askjer committed
                <v-list-item-title >{{ item.label }}</v-list-item-title>
          </v-list-item>

        </v-list>

        </v-menu>
      </template>

Ole Voldsæter's avatar
Ole Voldsæter committed
      <template v-slot:item="data">
Henrik Askjer's avatar
Henrik Askjer committed
        <span v-if="!data.item.lang">
          Søk: <strong>{{data.item.match}}</strong> </span>

       <span v-if="data.item.lang">
               <span class="searchLemma">
        {{data.item.match}}
Henrik Askjer's avatar
Henrik Askjer committed
      </span>
Henrik Askjer's avatar
Henrik Askjer committed
        <span class="dict-parentheses" v-if="(get_lang()=='bm,nn')">
             ({{["bokmål","nynorsk","bokmål, nynorsk"][data.item.lang-1]}})
        </span>
Henrik Askjer's avatar
Henrik Askjer committed
       </span>

Henrik Askjer's avatar
Henrik Askjer committed
      </template>
Henrik Askjer's avatar
Henrik Askjer committed
    </v-combobox>
Ole Voldsæter's avatar
Ole Voldsæter committed
  </div>
</template>

<script>
  export default {
    data: function() {
      return {
        loading: false,
        items: [],
        search: null,
Henrik Askjer's avatar
Henrik Askjer committed
        select: this.$route.query? this.$route.query.q : null,
Henrik Askjer's avatar
Henrik Askjer committed
        suggesting: null,
Henrik Askjer's avatar
Henrik Askjer committed
        menuDialog: false,
        dictMenuOpened: false
      }
    },
    watch: {
      search (val) {
        if (! val) {
          this.items = []
        } else {
Henrik Askjer's avatar
Henrik Askjer committed
        if (item) {
Henrik Askjer's avatar
Henrik Askjer committed
          if (typeof item != 'string') {
Henrik Askjer's avatar
Henrik Askjer committed
          this.items = []
          this.suggesting = false
          

          this.submit(item)
Henrik Askjer's avatar
Henrik Askjer committed
        }
Henrik Askjer's avatar
Henrik Askjer committed
      },
      $route (to, from) {
        this.select = to.query.q
Henrik Askjer's avatar
Henrik Askjer committed
      update_lang_form(lang) {
        this.$emit('update-lang-form', lang)
        // Submit if switching on front page
         if (this.search && this.search!=this.$route.query.q && !this.items[0]) {
          this.submit({q: this.search, match: this.search, time: Date.now()})
        }
        else {
          this.$parent.reload_params()
        }
       
      },
      get_lang() {
        return this.$parent.lang
      },
Henrik Askjer's avatar
Henrik Askjer committed
        q = q.trim()

Henrik Askjer's avatar
Henrik Askjer committed
        if (this.items[0]) {
          if (this.items[0].time < time) {
Henrik Askjer's avatar
Henrik Askjer committed
            // Whitespace necessary in case option already exists in dropdown
Henrik Askjer's avatar
Henrik Askjer committed
            this.items.splice(0,1, {q, match: q, time})
Henrik Askjer's avatar
Henrik Askjer committed
          this.items.push({q, match: q, time})
Henrik Askjer's avatar
Henrik Askjer committed

        this.suggesting = true
        
          let self = this
          let params = {q, dict: self.get_lang(), n: 6, dform: 'int', meta: 'n', include: "e", wc: self.$parent.pos_selected}
Henrik Askjer's avatar
Henrik Askjer committed
          this.$parent.api.get('api/suggest?', {params})
Henrik Askjer's avatar
Henrik Askjer committed
            .then(async (response) => {
Henrik Askjer's avatar
Henrik Askjer committed
                        if (self.$refs.autocomplete.searchInput == q & self.suggesting) {
Henrik Askjer's avatar
Henrik Askjer committed
                          let suggestions = []
                          if (response.data.a.exact) {
                            suggestions = response.data.a.exact.map(item => ({q: q, match: item[0], time: time, lang: [item[1]], w: true}))
Henrik Askjer's avatar
Henrik Askjer committed
                          }
Henrik Askjer's avatar
Henrik Askjer committed

                          if (suggestions.length) {
                            if (suggestions[0].q != suggestions[0].match) {
                              suggestions.unshift({q, match: q, time})
                            }
Henrik Askjer's avatar
Henrik Askjer committed
                            self.items = suggestions
                          }
Henrik Askjer's avatar
Henrik Askjer committed
                          else {
                            self.items = [{q, match: q, time}]
                          }
Henrik Askjer's avatar
Henrik Askjer committed
      },
Henrik Askjer's avatar
Henrik Askjer committed
      submit(item) {
          this.$emit('submit', item)
          let self = this
Henrik Askjer's avatar
Henrik Askjer committed
          setTimeout(() => {
Henrik Askjer's avatar
Henrik Askjer committed
          if (!self.$store.state.noMouse && this.$vuetify.breakpoint.mdAndUp) self.$refs.autocomplete.$refs.input.select()
          else self.$refs.autocomplete.$refs.input.blur()
          self.suggesting = false
Henrik Askjer's avatar
Henrik Askjer committed
    mounted: function() { 
Henrik Askjer's avatar
Henrik Askjer committed
      if (!this.$route.hash) {
        if(!this.$store.state.noMouse && this.$vuetify.breakpoint.mdAndUp) {
          this.$refs.autocomplete.$refs.input.focus()
        }
      }
Henrik Askjer's avatar
Henrik Askjer committed

      document.addEventListener("keyup", e => {
          if (e.key !== "/") return;
          if (e.altKey || e.ctrlKey || e.metaKey);
          if (/^(?:input|textarea|select)$/i.test(e.target.tagName)) return;
          this.$refs.autocomplete.$refs.input.focus()
        });
Henrik Askjer's avatar
Henrik Askjer committed
    }
<style scoped>
Henrik Askjer's avatar
Henrik Askjer committed

  .searchResult {
    margin-right: 5px;
Henrik Askjer's avatar
Henrik Askjer committed
  }

  .searchLemma {
    color: var(--v-primary-base);
Henrik Askjer's avatar
Henrik Askjer committed
    font-weight: bold;

Ole Voldsæter's avatar
Ole Voldsæter committed

  .autocomplete-container {
Henrik Askjer's avatar
Henrik Askjer committed

 .search-field-button {
    padding-right: 0px !important;
  }

  .accessibility_link {
  display: inline;
  position: absolute;
  left: -10000px;
  }

  .accessibility_link:focus {
    position: absolute;
    left: 48px;
    top : 48px;
    background-color: white;
    padding: 10px;
    z-index: 10000;
  }

  
</style>