Skip to content
Snippets Groups Projects
DictionaryView.vue 31.2 KiB
Newer Older
Ole Voldsæter's avatar
Ole Voldsæter committed
<template>
Henrik Askjer's avatar
Henrik Askjer committed
    <div class="search_container">
Henrik Askjer's avatar
Henrik Askjer committed
      <Autocomplete v-on:submit="select_result"
                    v-on:update-lang-form="update_lang_form">
Ole Voldsæter's avatar
Ole Voldsæter committed
      </Autocomplete>
Henrik Askjer's avatar
Henrik Askjer committed
      <SearchToolbar @updatePos="update_pos"
                     @updateScope="update_scope" />

Ole Voldsæter's avatar
Ole Voldsæter committed
    </div>
Henrik Askjer's avatar
Henrik Askjer committed
    <div id="notifications"
         v-if="$route.name && !error"
         :class="$vuetify.breakpoint.name">
      <div id="suggestions"
           v-if="!article && !no_results">
        <div class="search_notification"
             v-if="inflection_suggestions && inflection_suggestions.length">
          <v-icon left
Henrik Askjer's avatar
Henrik Askjer committed
                  color="primary">info</v-icon><em>{{queryString}}</em> {{$t('notifications.inflected')}}<!--
Henrik Askjer's avatar
Henrik Askjer committed
          --><span v-for="(item,index) in inflection_suggestions"
                :key="index"><!--
Henrik Askjer's avatar
Henrik Askjer committed
            --><router-link :to="generate_path({q: item[0]})"
Henrik Askjer's avatar
Henrik Askjer committed
                         @click.native="inflection_link(item[0])">{{item[0]}}</router-link><!--
            -->{{index == inflection_suggestions.length-1? '.' : ', '}}</span>
        </div>
        <div class="search_notification"
             v-if="lang=='bm,nn' && similar && similar.length > 0 && (search_results.nn && search_results.nn.length == 0)">
          <v-icon left
                  color="primary">info</v-icon>{{$t('notifications.similar_nn')}}<!--
          --><span v-for="(item,index) in similar"
                :key="index"><!--
Henrik Askjer's avatar
Henrik Askjer committed
            --><router-link :to="generate_path({q: queryString+'|'+item[0]})"
                         @click.native="similar_link(queryString+'|'+item[0])">{{item[0]}}</router-link><!--
Henrik Askjer's avatar
Henrik Askjer committed
            -->{{index == similar.length-1? '.' : ', '}}
          </span>
        </div>
        <div class="search_notification"
             v-if="lang=='bm,nn' && similar && similar.length > 0 && (search_results.bm && search_results.bm.length == 0)">
          <v-icon left
                  color="primary">info</v-icon>{{$t('notifications.similar_bm')}}<!--
          --><span v-for="(item,index) in similar"
                :key="index"><!--
Henrik Askjer's avatar
Henrik Askjer committed
            --><router-link :to="generate_path({q: queryString+'|'+item[0]})"
                         @click.native="similar_link(queryString+'|'+item[0])">{{item[0]}}</router-link><!--
Henrik Askjer's avatar
Henrik Askjer committed
            -->{{index == similar.length-1? '.' : ', '}}
          </span>
        </div>
      </div>

      <div id="return_to_results"
Henrik Askjer's avatar
Henrik Askjer committed
           v-if="$vuetify.breakpoint.mdAndUp && article && $store.state.searchRoute">
Henrik Askjer's avatar
Henrik Askjer committed
        <router-link id="return_link"
                     :to="$store.state.searchRoute"
                     @click.native="return_to_results()">
          <v-icon left
                  class="nav_arrow">chevron_left</v-icon>{{$t("notifications.back")}}
        </router-link>
      </div>


      <div class="no_results"
           v-if="no_results && !error">
        <div>
          <p>
            <v-icon left
                    color=primary>error</v-icon> <strong>{{$t('notifications.no_results')}}<span
                    v-if="pos_selected">{{$t('notifications.no_pos_results', {pos: $t('pos_tags_plural.'+pos_selected)})}}</span></strong>
          </p>
          <p class="below-notification" v-if="!article && inflection_suggestions && inflection_suggestions.length">
Henrik Askjer's avatar
Henrik Askjer committed
            <em>{{this.queryString}}</em>{{$t('notifications.inflected')}}
Henrik Askjer's avatar
Henrik Askjer committed
            <span v-for="(item,index) in inflection_suggestions"
                  :key="index"><!--
Henrik Askjer's avatar
Henrik Askjer committed
              --><router-link :to="generate_path({q: item[0]})"
Henrik Askjer's avatar
Henrik Askjer committed
                           @click.native="inflection_link(item[0])">{{item[0]}}</router-link><!--
              -->{{index == inflection_suggestions.length-1? '.' : ', '}}</span>
            <p class="below-notification"
               v-if="lang=='bm' && suggest_other_dict">{{$t('notifications.suggest_dict[1]')}}
Henrik Askjer's avatar
Henrik Askjer committed
              <router-link :to="generate_lang_path('nn')"
Henrik Askjer's avatar
Henrik Askjer committed
                           @click.native="language_link('nn')">{{$t('dicts.nn')}}</router-link><!--
            --></p>
            <p class="below-notification"
               v-if="lang=='nn' && suggest_other_dict">{{$t('notifications.suggest_dict[0]')}}<br>{{$t('notifications.suggest_dict[1]')}}
Henrik Askjer's avatar
Henrik Askjer committed
              <router-link :to="generate_lang_path('bm')"
Henrik Askjer's avatar
Henrik Askjer committed
                           @click.native="language_link('bm')">{{$t('dicts_inline.bm')}}</router-link>
            </p>
            <p class="below-notification"
               v-if="suggest_fulltext">
               {{$t('notifications.fulltext[0]')}}
Henrik Askjer's avatar
Henrik Askjer committed
               <router-link :to="generate_path({scope: scope+'f'})"
Henrik Askjer's avatar
Henrik Askjer committed
                            @click.native="fulltext_link()">
                  {{$t('notifications.fulltext[1]')}}
               </router-link>
            </p>
            <article v-if="similar && similar.length"
                     :class="'v-sheet v-card rounded-xl did_you_mean ' + $vuetify.breakpoint.name">
              <span class="dict-label">{{$t('notifications.similar')}}</span>
              <v-list>
                <template v-for="(item, index) in similar">
                  <v-list-item :key="index">
Henrik Askjer's avatar
Henrik Askjer committed
                    <router-link :to="generate_path({q: item[0]})"
Henrik Askjer's avatar
Henrik Askjer committed
                                 @click.native="similar_link(item[0])">{{item[0]}}</router-link>
                    <span class="dict-parentheses"
                          v-if="lang=='bm,nn'">&nbsp;({{["bokmål","nynorsk","bokmål, nynorsk"][item[1]-1]}})</span>
                  </v-list-item>
                </template>
              </v-list>

            </article>
Henrik Askjer's avatar
Henrik Askjer committed
      </div>

    </div>

    <SearchResults :results_bm="search_results.bm || []"
                   :results_nn="search_results.nn || []"
                   :lang="lang"
                   @article-click="article_link_click"
                   @details-click="details_click"
                   @update-page="update_page"
                   v-if="$route.name && !article && !error && !no_results" />
    <div id="spinner"
         v-if="waiting">
      <v-progress-circular indeterminate
                           color="secondary"
                           size="120"></v-progress-circular>
    </div>
    <div id="single_article_container"
Henrik Askjer's avatar
Henrik Askjer committed
         v-if="article && !error && !no_results" :class="$store.state.searchRoute && $vuetify.breakpoint.mdAndUp && lang == 'bm,nn' ? article.dictionary : null">
Henrik Askjer's avatar
Henrik Askjer committed
      <Article :key="article_key"
               :article="article"
               title_id="result0"
               @article-click="article_link_click"
               @details-click="details_click"
               articleLookup/>
Ole Voldsæter's avatar
Ole Voldsæter committed
    </div>
Henrik Askjer's avatar
Henrik Askjer committed
    <div class="welcome"
Henrik Askjer's avatar
Henrik Askjer committed
         v-show="!error && ($route.name=='/' || !$route.name)">
Henrik Askjer's avatar
Henrik Askjer committed
      <div class="monthly"
           :class="$vuetify.breakpoint.name">
Ole Voldsæter's avatar
Ole Voldsæter committed
        <div>
Henrik Askjer's avatar
Henrik Askjer committed
          <Article :article="monthly_bm"
                   title_id="result0"
                   @article-click="article_link_click"
                   @details-click="details_click" />
Ole Voldsæter's avatar
Ole Voldsæter committed
        </div>
        <div>
Henrik Askjer's avatar
Henrik Askjer committed
          <Article :article="monthly_nn"
                   title_id="result1"
                   @article-click="article_link_click"
                   @details-click="details_click" />
Ole Voldsæter's avatar
Ole Voldsæter committed
        </div>
      </div>
    </div>
Henrik Askjer's avatar
Henrik Askjer committed

    <div class="error"
         v-if="error">
      <div>
        <h1 tabindex="0"
            id="result0">{{error.title}}</h1>
        <p>{{error.description}}</p>
      </div>
Ole Voldsæter's avatar
Ole Voldsæter committed
    </div>
Ole Voldsæter's avatar
Ole Voldsæter committed
  </main>
</template>

<script>
import axios from "axios"
import entities from '../utils/entities.js'
import Article from './Article.vue'
import SearchResults from './SearchResults.vue'
import Autocomplete from './Autocomplete.vue'
Henrik Askjer's avatar
Henrik Askjer committed
import SearchToolbar from './SearchToolbar.vue'
Henrik Askjer's avatar
Henrik Askjer committed
const ENDPOINT = process.env.VUE_APP_ENDPOINT
const FALLBACK_ENDPOINT = process.env.VUE_APP_FALLBACK_ENDPOINT

Henrik Askjer's avatar
Henrik Askjer committed
function navigate_to_article(self, origin) {
Henrik Askjer's avatar
Henrik Askjer committed
  self.article = null
  self.waiting_for_articles = true
Henrik Askjer's avatar
Henrik Askjer committed
  const lang = self.$route.params.lang
Henrik Askjer's avatar
Henrik Askjer committed
  self.api.get(lang + '/article/' + self.$route.params.id + ".json")
  //self.api.get("https://httpstat.us/502")
Ole Voldsæter's avatar
Ole Voldsæter committed
  .then(function(response){
    self.article = Object.assign(response.data, {'dictionary': lang, results: self.search_results})
Ole Voldsæter's avatar
Ole Voldsæter committed
    self.error = null
Ole Voldsæter's avatar
Ole Voldsæter committed
  })
  .catch(function(error){
Henrik Askjer's avatar
Henrik Askjer committed
    self.handle_error(error, {retry: navigate_to_article, arg: origin, article: true})
Ole Voldsæter's avatar
Ole Voldsæter committed
  })
  .then(function(response){
    self.waiting_for_articles = false
Henrik Askjer's avatar
Henrik Askjer committed
    self.replace_history()
Henrik Askjer's avatar
Henrik Askjer committed
    //if (origin) self.$plausible.trackEvent('internal link incoming', {props: {origin}})
Henrik Askjer's avatar
Henrik Askjer committed
async function load_articles(self, query, offset, n, dict) {
  let article_IDs = self.article_info.articles[dict]
  if (article_IDs)
  {
  if (offset > article_IDs.length) {
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
    n = 0
  }
  else if (offset + n > article_IDs.length) {
    n = article_IDs.length % n
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
  }

  if (n > 0 && (self.lang == dict || self.lang == "bm,nn")) {
    article_IDs = article_IDs.slice(offset, offset + n)

    return Promise.all(article_IDs.map((article_id) => {
Henrik Askjer's avatar
Henrik Askjer committed
      return self.api.get(`${dict}/article/${article_id}.json`)
     //return self.api.get(`https://httpstat.us/502`)

Henrik Askjer's avatar
Henrik Askjer committed

    }))
    .then((response) => {
      let results = response.map((element, index) => {
        return Object.assign(element.data, {
          dictionary: dict
        })
      })
      self.article = null
      self.search_results[dict] = results
    })
    .catch(error => {
Henrik Askjer's avatar
Henrik Askjer committed
      self.handle_error(error, {})
Henrik Askjer's avatar
Henrik Askjer committed
    })
  }
    else {
    self.search_results[dict] = []
  }
  }
    return Promise.resolve()
Henrik Askjer's avatar
Henrik Askjer committed


function navigate_to_query(self, word, keep_page) {
  self.error = null
  self.no_results = null
Henrik Askjer's avatar
Henrik Askjer committed
  self.waiting_for_articles = true
Henrik Askjer's avatar
Henrik Askjer committed
  self.inflection_suggestions = []
  self.similar = []
  self.suggest_fulltext = false
  self.suggest_other_dict = false

  if (!self.event) {
    self.event = {match: word}
  }
  let  query = self.event
  let q = query.match

  if (!keep_page) {
    self.page = 1
  }
Henrik Askjer's avatar
Henrik Askjer committed
  let advanced_search = /[?_*%|]/.test(q)
Henrik Askjer's avatar
Henrik Askjer committed

  // Get inflections
Henrik Askjer's avatar
Henrik Askjer committed
  if (!advanced_search && self.$route.name == 'search') {
Henrik Askjer's avatar
Henrik Askjer committed
    let params = {q, dict: self.lang, dform: 'int', include: "i", meta: 'n', wc: self.pos_selected}
Henrik Askjer's avatar
Henrik Askjer committed
    self.api.get('api/suggest?', {params})
    //self.api.get('https://httpstat.us/502')
Henrik Askjer's avatar
Henrik Askjer committed
      .then((response) => {
Henrik Askjer's avatar
Henrik Askjer committed
                    self.inflection_suggestions = response.data.a.inflect
Henrik Askjer's avatar
Henrik Askjer committed
              }).catch(error =>{
Henrik Askjer's avatar
Henrik Askjer committed
                    self.handle_error(error, {retry: navigate_to_query, arg: q})
Henrik Askjer's avatar
Henrik Askjer committed
                    self.replace_history()
Henrik Askjer's avatar
Henrik Askjer committed
                })
Henrik Askjer's avatar
Henrik Askjer committed
    }
Henrik Askjer's avatar
Henrik Askjer committed
  // Get article IDs
Henrik Askjer's avatar
Henrik Askjer committed
  let params = {w: query.match, dict: self.lang, scope: self.scope}
Henrik Askjer's avatar
Henrik Askjer committed
  let offset = 0
  if (self.page) {
    offset = self.perPage * (self.page -1)
  }
  if (self.pos_selected) params.wc = self.pos_selected
Henrik Askjer's avatar
Henrik Askjer committed
    self.api.get('api/articles?', {params}).then((response) => {
    //self.api.get('https://httpstat.us/502', {params}).then((response) => {

Henrik Askjer's avatar
Henrik Askjer committed
            self.article_info = response.data
            self.search_results = {}

            let bm_length = response.data.articles.bm ? response.data.articles.bm.length : 0
            let nn_length = response.data.articles.nn ? response.data.articles.nn.length : 0
            let total_length = bm_length + nn_length
            let dict = self.lang

          // Similar
          if (bm_length == 0 || nn_length == 0) {
              if (!advanced_search) {
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
                if (dict == 'bm,nn' && total_length > 0) {
                  dict = bm_length == 0? 'bm' : 'nn'
                }
                let params = {q, dict, dform: 'int', include: "s", wc: self.pos_selected}
Henrik Askjer's avatar
Henrik Askjer committed
                self.api.get('api/suggest?', {params})
Henrik Askjer's avatar
Henrik Askjer committed
                //axios.get('https://httpstat.us/502')
Henrik Askjer's avatar
Henrik Askjer committed
                  .then((response) => {
Henrik Askjer's avatar
Henrik Askjer committed
                    self.similar = response.data.a.similar
Henrik Askjer's avatar
Henrik Askjer committed
                    self.replace_history()
Henrik Askjer's avatar
Henrik Askjer committed
                  }).catch(error => {
Henrik Askjer's avatar
Henrik Askjer committed
                    self.handle_error(error, {retry: navigate_to_query, arg: q})
Henrik Askjer's avatar
Henrik Askjer committed
                    self.replace_history()
Henrik Askjer's avatar
Henrik Askjer committed
                  })
            } else {
              self.similar = []
            }
          }

          if (total_length == 0) {
            self.waiting_for_articles = false
            self.no_results = true
            if (!self.scope.includes('f')) {
              let params = {q, dict, n: 1, dform: 'int', include: 'f', wc: self.pos_selected}
Henrik Askjer's avatar
Henrik Askjer committed
              self.api.get('api/suggest?', {params}).then((response) => {
Henrik Askjer's avatar
Henrik Askjer committed
                      self.suggest_fulltext = response.data.cnt > 0
                    }).catch(error => {
Henrik Askjer's avatar
Henrik Askjer committed
                      self.handle_error(error, {retry: navigate_to_query, arg: q})
Henrik Askjer's avatar
Henrik Askjer committed
                      self.replace_history()
Henrik Askjer's avatar
Henrik Askjer committed
                    })
            }
            if (dict != 'bm,nn') {
              let params = {q, n: 1, dict: dict=='bm'?'nn':'bm', dform: 'int', include: 'e', wc: self.pos_selected}
Henrik Askjer's avatar
Henrik Askjer committed
              self.api.get('api/suggest?', {params}).then((response) => {
Henrik Askjer's avatar
Henrik Askjer committed
                      self.suggest_other_dict = response.data.cnt > 0 && response.data.a.exact[0][0] == q
                    }).catch(error => {
Henrik Askjer's avatar
Henrik Askjer committed
                      self.handle_error(error, {retry: navigate_to_query, arg: q})
Henrik Askjer's avatar
Henrik Askjer committed
                      self.replace_history()
Henrik Askjer's avatar
Henrik Askjer committed
                    })
            }
            self.replace_history() // fixes routing bug when going back from suggested search
          }
          else {
            self.no_results = false
            Promise.all([
              load_articles(self, query, offset, self.perPage, "bm"),
              load_articles(self, query, offset, self.perPage, "nn")
            ])
Henrik Askjer's avatar
Henrik Askjer committed
            .then(() => {
              self.waiting_for_articles = false
Henrik Askjer's avatar
Henrik Askjer committed
              self.$store.commit('setSearchRoute', self.$route.fullPath)
              self.replace_history()
Henrik Askjer's avatar
Henrik Askjer committed
            })
Henrik Askjer's avatar
Henrik Askjer committed
          }
        }).catch(error =>{
Henrik Askjer's avatar
Henrik Askjer committed
            self.handle_error(error, {retry: navigate_to_query, arg: q})
Henrik Askjer's avatar
Henrik Askjer committed
            self.replace_history()
        })
}

export default {
  name: 'DictionaryView',
  data: function() {
    return {
Henrik Askjer's avatar
Henrik Askjer committed
      api: null,
      fallback: false,
Henrik Askjer's avatar
Henrik Askjer committed
      search_results: {},
      lang: this.$store.state.defaultDict,
      waiting_for_articles: true,
      waiting_for_metadata: true,
      article: null,
      error: null,
Henrik Askjer's avatar
Henrik Askjer committed
      no_results: false,
      monthly_bm: null,
      monthly_nn: null,
      event: null,
Henrik Askjer's avatar
Henrik Askjer committed
      scope: "ei",
      pos_selected: "ALL",
      article_info: null,
      page: 1,
      perPage: 10,
      inflection_suggestions: null,
      similar: null,
      selected: null,
      suggest_fulltext: false,
      suggest_other_dict: false
Henrik Askjer's avatar
Henrik Askjer committed
    queryString: function() {
      return this.$route.query.q || this.$route.params.q
    },
    waiting: function() {
      return (this.waiting_for_articles || this.waiting_for_metadata) && this.$route.name != 'root'
Henrik Askjer's avatar
Henrik Askjer committed
    }
  },
  metaInfo() {
    if (this.no_results) {
      return {meta: [{name: "robots", content: 'none'}]}
    }
Henrik Askjer's avatar
Henrik Askjer committed
    let q = ""
Henrik Askjer's avatar
Henrik Askjer committed
    if (this.queryString) {
      q =  this.queryString + (this.lang == 'bm,nn' ? ' - ' : ' | ')
Henrik Askjer's avatar
Henrik Askjer committed
    }
Henrik Askjer's avatar
Henrik Askjer committed
    let desc = " viser skrivemåte og bøying i tråd med norsk rettskriving. Språkrådet og Universitetet i Bergen står bak ordbøkene."
    switch (this.lang) {
      case 'bm,nn': return {title: q+'ordbøkene.no',
                            meta: [{name: "description", vmid: 'description', content: "Bokmålsordboka og Nynorskordboka"+desc}]}
      case 'bm': return {title: q+"Bokmålsordboka",
                          meta: [{name: "description", vmid: 'description', content: "Bokmålsordboka"+desc}]}
      case 'nn': return {title: q+"Nynorskordboka",
                        meta: [{name: "description", vmid: 'description', content: "Nynorskordboka"+desc}] }
Henrik Askjer's avatar
Henrik Askjer committed
    }
Henrik Askjer's avatar
Henrik Askjer committed


  },
  components: {
    Article,
    Autocomplete,
Henrik Askjer's avatar
Henrik Askjer committed
    SearchResults,
    SearchToolbar
Henrik Askjer's avatar
Henrik Askjer committed
      load_welcome_and_metadata: function() {
      let self = this
        Promise.all([
      self.api.get('bm/concepts.json').then(function(response){
        let concepts = response.data.concepts
        entities.bm = concepts
      }),
      self.api.get('nn/concepts.json').then(function(response){
        let concepts = response.data.concepts
        entities.nn = concepts
      })
    ]).then(function(_) {
      self.waiting_for_metadata = false
      if (self.$route.name == 'search') {
        navigate_to_query(self, self.$route.query.q, true)
      }
Henrik Askjer's avatar
Henrik Askjer committed
      else if(self.$route.name == 'word') {
        self.scope = 'e'
        self.pos = null
        navigate_to_query(self, self.$route.params.q, true)
      }
Henrik Askjer's avatar
Henrik Askjer committed
      else if(self.$route.name == 'lookup'){
        navigate_to_article(self, self.$route.path)
      }
      else {
        self.waiting_for_articles = false
        self.replace_history()
        self.load_monthly_bm()
        self.load_monthly_nn()

      }
    }).catch(function(error){
Henrik Askjer's avatar
Henrik Askjer committed
      self.api = axios.create({baseURL: FALLBACK_ENDPOINT})
      if (!self.error || !self.error.response) {
        if (self.fallback) {
          if (error.response) {
            self.error = {title: self.$t('error.server.title'), description: self.$t('error.server.description', {code: error.response.status}), response: error.response}
          }
          else if (error.message == "Network Error") {
            self.error = {title: self.$t('error.network.title'), description: self.$t('error.network.description')}
          }
          else {
            self.error = {title: self.$t('error.generic.title'), description: self.$t('error.generic.description')}
          }
          self.waiting_for_metadata = false
          self.waiting_for_articles = false
Henrik Askjer's avatar
Henrik Askjer committed
        }
        else {
Henrik Askjer's avatar
Henrik Askjer committed
          self.fallback = true
          self.load_welcome_and_metadata()
Henrik Askjer's avatar
Henrik Askjer committed
        }
      }
    })
    },

Henrik Askjer's avatar
Henrik Askjer committed
    replace_history: function() {
Henrik Askjer's avatar
Henrik Askjer committed
          history.replaceState({article: this.article,
                              search_results: this.search_results,
Henrik Askjer's avatar
Henrik Askjer committed
                              article_info: this.article_info,
Henrik Askjer's avatar
Henrik Askjer committed
                              lang: this.lang,
Henrik Askjer's avatar
Henrik Askjer committed
                              error: this.error,
                              no_results: this.no_results,
                              pos_selected: this.pos_selected,
                              scope: this.scope,
                              page: this.page,
                              perPage: this.perPage,
                              inflection_suggestions: this.inflection_suggestions,
                              similar: this.similar,
                              suggest_fulltext: this.suggest_fulltext,
                              suggest_other_dict: this.suggest_other_dict}, '')


    },
    total_results: function() {
      if (this.article_info) {
        let total = 0
        if (this.article_info.articles.bm) {
          total += this.article_info.articles.bm.length
        }
        if (this.article_info.articles.nn) {
          total += this.article_info.articles.nn.length
        }

        return total
      }
    },
    load_monthly_bm: function() {
      let self = this
Henrik Askjer's avatar
Henrik Askjer committed
      this.api.get('bm/article/502.json').then(function(response){
Henrik Askjer's avatar
Henrik Askjer committed
        self.monthly_bm = Object.assign(response.data, {dictionary: 'bm'})
      })
Henrik Askjer's avatar
Henrik Askjer committed
    },
Henrik Askjer's avatar
Henrik Askjer committed
    load_monthly_nn: function() {
      let self = this
Henrik Askjer's avatar
Henrik Askjer committed
      this.api.get('nn/article/493.json').then(function(response){
Henrik Askjer's avatar
Henrik Askjer committed
        self.monthly_nn = Object.assign(response.data, {dictionary: 'nn'})
      })
    },
Henrik Askjer's avatar
Henrik Askjer committed
    handle_error: function(error, retry_params) {
Henrik Askjer's avatar
Henrik Askjer committed
      this.waiting_for_articles = false
      this.no_results = false
      this.search_results = {}
      this.inflection_suggestions = []
      this.similar = []
      this.suggest_fulltext = false
      this.suggest_other_dict = false
Henrik Askjer's avatar
Henrik Askjer committed
      this.api = axios.create({baseURL: FALLBACK_ENDPOINT})
Henrik Askjer's avatar
Henrik Askjer committed
      if (!this.error || !this.error.response) {
        if (this.fallback || !retry_params.retry) {
          this.fallback = true
          if (error.response) {
            if (error.response.status == 404) {
              if (retry_params.article) {
                this.error = {title: this.$t('error.404.title'), description: this.$t('error.no_article', {id: this.$route.params.id}), article: true, response: error.response}
              }
              else {
                this.error = {title: this.$t('error.404.title'), description: this.$t('error.404.description'), article: retry_params.article, response: error.response}
              }
            }
            else if (error.response.status == 503) {
              this.error = {title: this.$t('error.503.title'), description: this.$t('error.503.description'), article: retry_params.article, response: error.response}
            }
            else if (String(error.response.status)[0] == "5") {
              this.error = {title: this.$t('error.server.title'), description: this.$t('error.server.description', {code: error.response.status}), article: retry_params.article, response: error.response}
Henrik Askjer's avatar
Henrik Askjer committed
            }
            else {
Henrik Askjer's avatar
Henrik Askjer committed
              this.error = {title: this.$t('error.generic_code.title'), description: this.$t('error.generic_code.description', {code: error.response.status}), article: retry_params.article, response: error.response}
Henrik Askjer's avatar
Henrik Askjer committed
            }
Henrik Askjer's avatar
Henrik Askjer committed
          } else if (error.message == "Network Error") {
            this.error = {title: this.$t('error.network.title'), description: this.$t('error.network.description'), article: retry_params.article, response: error.response}
Henrik Askjer's avatar
Henrik Askjer committed
          }
          else {
Henrik Askjer's avatar
Henrik Askjer committed
            this.error = {title: this.$t('error.generic.title'), description: this.$t('error.generic.description'), article: retry_params.article, response: error.response}
Henrik Askjer's avatar
Henrik Askjer committed
          }
Henrik Askjer's avatar
Henrik Askjer committed
        } else {
          this.fallback = true
          retry_params.retry(this, retry_params.arg)
Henrik Askjer's avatar
Henrik Askjer committed
        }
      }
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
    },
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
    inflection_link: function (word) {
Henrik Askjer's avatar
Henrik Askjer committed
      //this.$plausible.trackEvent('inflection link', {props: {lang: this.previous.params.lang, from: this.previous.query.q, to: word}})
Henrik Askjer's avatar
Henrik Askjer committed
      this.event = null
      navigate_to_query(this, word)
    },
    similar_link: function (word) {
Henrik Askjer's avatar
Henrik Askjer committed
      //this.$plausible.trackEvent('similar link', {props: {lang: this.previous.params.lang, from: this.previous.query.q, to: word}})
Henrik Askjer's avatar
Henrik Askjer committed
      this.event = null
      navigate_to_query(this, word)
    },
    fulltext_link: function () {
      this.event = null
      this.scope = this.scope + "f"
Henrik Askjer's avatar
Henrik Askjer committed
      navigate_to_query(this, this.queryString)
Henrik Askjer's avatar
Henrik Askjer committed
    },
    language_link: function (lang) {
      this.lang = lang
      this.event = null
Henrik Askjer's avatar
Henrik Askjer committed
      navigate_to_query(this, this.queryString)
Henrik Askjer's avatar
Henrik Askjer committed

    select_result: function (event) {
        this.event = event
Henrik Askjer's avatar
Henrik Askjer committed
        let path = `/${this.lang}/search`
        let pos = this.pos_param()
        let query = {q: event.match || event.q}
        if (pos) query["pos"] = pos
        if (this.scope) query["scope"] = this.scope
        this.$router.push({path, query})
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
        let track_props = {query: event.q}
        if (event.match) track_props.match = event.match
Henrik Askjer's avatar
Henrik Askjer committed
        //this.$plausible.trackEvent('dropdown selection', { props: track_props })
Henrik Askjer's avatar
Henrik Askjer committed
      },
Henrik Askjer's avatar
Henrik Askjer committed

      pos_param: function() {
        if (this.pos_selected) return this.pos_selected.toLowerCase()
        return null
      },
      update_page: function() {
        this.waiting_for_articles = true
Henrik Askjer's avatar
Henrik Askjer committed
        let q = this.queryString
Henrik Askjer's avatar
Henrik Askjer committed
        let path = `/${this.lang}/search`
        let pos = this.pos_param()
        let query = {q: q, page: this.page}
        if (pos != 'all') query.pos = pos
        if (this.scope) query.scope = this.scope
        if (this.perPage) query.perPage = this.perPage
        this.$router.push({path, query})
        let offset = 0
        if (this.page) {
          offset = this.perPage * (this.page -1)
        }

      let self = this
      Promise.all([
      load_articles(this, query, offset, this.perPage, "bm"),
      load_articles(this, query, offset, this.perPage, "nn")]).then(() => {
         self.replace_history()
         self.$forceUpdate()
Henrik Askjer's avatar
Henrik Askjer committed
         /*
         // Debugging
         if (self.page < Math.ceil(Math.max(self.article_info.articles.bm.length, self.article_info.articles.nn.length)/self.perPage)) {
          self.page+=1
          self.update_page()
         }
         */
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
      }
      ).then(() => {
        this.$store.commit('setSearchRoute', this.$route.fullPath)
        this.waiting_for_articles = false
      })
      },

        generate_path: function(params) {
Henrik Askjer's avatar
Henrik Askjer committed
          if (this.$route.name == "word") {
            return this.$router.resolve({name: "search", query: {q: this.$route.params.q, ...params}}).href
          }
          else {
            return this.$router.resolve({query: {...this.$route.query, ...params}}).href
          }

Henrik Askjer's avatar
Henrik Askjer committed
      },

      generate_lang_path: function(dict) {
        return this.$route.fullPath.replace(/\/(bm|nn|bm,nn)\//, "/"+dict+"/")
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
      },

      reload_params: function() {
Henrik Askjer's avatar
Henrik Askjer committed
        let q = this.queryString
Henrik Askjer's avatar
Henrik Askjer committed
        if (q) {
          let path = `/${this.lang}/search`
          let pos = this.pos_param()
Henrik Askjer's avatar
Henrik Askjer committed
          let query = {q}
Henrik Askjer's avatar
Henrik Askjer committed
          if (pos) query.pos = pos
          if (this.scope) query.scope = this.scope
Henrik Askjer's avatar
Henrik Askjer committed
          if (this.scope) query.scope = this.scope
          if (this.perPage) query.perPage = this.perPage
Henrik Askjer's avatar
Henrik Askjer committed
          this.$router.push({path, query})
          navigate_to_query(this, q)
Henrik Askjer's avatar
Henrik Askjer committed
        }
      update_lang_form: function (lang) {
        this.lang = lang
Henrik Askjer's avatar
Henrik Askjer committed
        this.$store.commit("setDefaultDict", lang)
Henrik Askjer's avatar
Henrik Askjer committed
        this.page = 1
      },
      update_scope: function(scope) {
        this.scope = scope
        this.page = 1
        this.reload_params()
Henrik Askjer's avatar
Henrik Askjer committed
      },
Henrik Askjer's avatar
Henrik Askjer committed
      update_pos: function (pos) {
        this.pos_selected = pos
        this.page = 1
        this.reload_params()
      },
Henrik Askjer's avatar
Henrik Askjer committed
      update_per_page: function(perPage) {
        this.perPage = perPage
        this.$store.commit('setPerPage', this.perPage)
        this.page = 1
        this.reload_params()
      },
Henrik Askjer's avatar
Henrik Askjer committed

Ole Voldsæter's avatar
Ole Voldsæter committed
    article_link_click: function(item) {
Henrik Askjer's avatar
Henrik Askjer committed
      let event = window.event
      if (!(event.ctrlKey || event.shiftKey)) {
        if (this.article && this.article.article_id == item.article_id){
          this.article_key++
          this.replace_history()

        }else{
          navigate_to_article(this, item.source)
        }
Ole Voldsæter's avatar
Ole Voldsæter committed
      }
    },
    details_click: function(item) {
Henrik Askjer's avatar
Henrik Askjer committed
      let event = window.event
      if (!(event.ctrlKey || event.shiftKey)) {
        this.article = item.article
        this.replace_history()
      }
    },
    return_to_results: function() {
      this.article = null
Henrik Askjer's avatar
Henrik Askjer committed
      this.replace_history()
Henrik Askjer's avatar
Henrik Askjer committed
    },
    set_fulltext_highlight: function() {
      if (this.$route.query.q && this.scope.includes("f")) {
        let q = this.$route.query.q
Henrik Askjer's avatar
Henrik Askjer committed
        q = q.replace(/\*|%/, "[^\\s]*")
        q = q.replace(/_|\?/, "[^\\s]")
Henrik Askjer's avatar
Henrik Askjer committed
        this.$store.commit('setFulltextHighlight', q)
      }
      else {
        this.$store.commit('setFulltextHighlight', false)
      }
Ole Voldsæter's avatar
Ole Voldsæter committed
  mounted: function(){
Henrik Askjer's avatar
Henrik Askjer committed
    this.api = axios.create({baseURL: ENDPOINT})

    this.lang = this.$route.params.lang || this.$store.state.defaultDict || 'bm,nn'
    if (this.$route.query.pos) {
    this.pos_selected = this.$route.query.pos.toUpperCase()
    } else this.pos_selected = null

    if (this.$route.query.scope) {
      this.scope = this.$route.query.scope
      this.set_fulltext_highlight()
Henrik Askjer's avatar
Henrik Askjer committed
    }
Henrik Askjer's avatar
Henrik Askjer committed
    if (this.$route.query.page) this.page = parseInt(this.$route.query.page)
    if (this.$route.query.perPage) {
      this.perPage = parseInt(this.$route.query.perPage)
Henrik Askjer's avatar
Henrik Askjer committed
    }
    else {
Henrik Askjer's avatar
Henrik Askjer committed
      this.perPage = parseInt(this.$store.state.perPage)
Henrik Askjer's avatar
Henrik Askjer committed
    }
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
    this.load_welcome_and_metadata()
Ole Voldsæter's avatar
Ole Voldsæter committed
  },
Henrik Askjer's avatar
Henrik Askjer committed
  watch: {
    $route(to, from) {
      this.previous = from
Henrik Askjer's avatar
Henrik Askjer committed
      if (to.fullPath == "/") {
Henrik Askjer's avatar
Henrik Askjer committed
        this.load_monthly_bm()
        this.load_monthly_nn()
      }
      if (to.name == 'lookup' && from.fullPath == '/') {
        this.$store.commit('setSearchRoute', null)
      }

Henrik Askjer's avatar
Henrik Askjer committed
      if (to.name == 'search') {
Henrik Askjer's avatar
Henrik Askjer committed
        this.set_fulltext_highlight()
      }
    }
  },
Ole Voldsæter's avatar
Ole Voldsæter committed
  created: function() {
    let self = this
    window.onpopstate = function (event) {
      if (event.state) {
Henrik Askjer's avatar
Henrik Askjer committed
        if (event.state.lang) {
            self.article = event.state.article
            self.search_results = event.state.search_results
            self.article_info = event.state.article_info
            self.lang = event.state.lang
            self.pos_selected = event.state.pos_selected
            self.scope = event.state.scope
            self.error = event.state.error
            self.no_results = event.state.no_results
            self.page = event.state.page,
            self.perPage = event.state.perPage
            self.inflection_suggestions = event.state.inflection_suggestions,
            self.similar = event.state.similar,
            self.suggest_fulltext = event.state.suggest_fulltext,
            self.suggest_other_dict = event.state.suggest_other_dict

            if (!self.$route.hash && self.$route.name != 'search') {
              history.scrollRestoration = 'manual'
              window.scrollTo(0,0)
              }
            else {
              history.scrollRestoration = 'auto'
            }
        }
        else {
          console.log("Navigation errror")
        }
Ole Voldsæter's avatar
Ole Voldsæter committed
      }
    }
  }
}
</script>

<style>
main {
  flex: 1 0 auto;
  background-color: var(--v-tertiary-base);
  display: flex;
  flex-direction: column;
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
  padding-top: 10px;
Henrik Askjer's avatar
Henrik Askjer committed
  background-image: url('../assets/cate-brodersen-b7ukrYhnt8c-unsplash.webp');
Ole Voldsæter's avatar
Ole Voldsæter committed
  background-repeat: no-repeat;
  background-position-x: center;
Henrik Askjer's avatar
Henrik Askjer committed
  background-position-y: -380px;
Henrik Askjer's avatar
Henrik Askjer committed
  padding-bottom: 10px;
div.welcome article {
  border-style: none;
}

.search_container {
  background-color: var(--v-tertiary-base);
Henrik Askjer's avatar
Henrik Askjer committed
  padding-top: 10px;
Henrik Askjer's avatar
Henrik Askjer committed
#spinner {
  margin: auto;
}

Henrik Askjer's avatar
Henrik Askjer committed
#search_results, #spinner, #notifications, #single_article_container, div.search_container, .error {
  padding-left: calc((100vw - 1200px) / 2);
  padding-right: calc((100vw - 1200px) / 2);
Henrik Askjer's avatar
Henrik Askjer committed
div.welcome {
  padding-left: calc((100vw - 917px) / 2);
  padding-right: calc((100vw - 917px) / 2);
}
Henrik Askjer's avatar
Henrik Askjer committed

Henrik Askjer's avatar
Henrik Askjer committed
#single_article_container {
  box-shadow: 0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
  background-color: white;
  height: 100%;
Henrik Askjer's avatar
Henrik Askjer committed
#single_article_container.nn {
  justify-content: flex-end !important;
  display: flex;
}

#single_article_container.nn article, #single_article_container.bm article{
  width: 50%;

}

Henrik Askjer's avatar
Henrik Askjer committed
#notifications .search_notification {
Henrik Askjer's avatar
Henrik Askjer committed
  padding-top: 10px;
Henrik Askjer's avatar
Henrik Askjer committed
  padding-bottom: 0px;
  margin-left: 10px;
  font-size: 18px;
}


#suggestions {
  padding-left: 10px;
}


.error p, .no_results p {
  margin-left: 15px;
}

Henrik Askjer's avatar
Henrik Askjer committed
.no_results {
  padding-top: 24px;
}

.error div{
  padding: 10px;
  padding-top: 24px;
}

Ole Voldsæter's avatar
Ole Voldsæter committed
#spinner {
  padding-top: 40px;
}

div.monthly {
  display: flex;
  width: 100%;
}

div.monthly > div {
  flex: 50%;
}

div.monthly.sm, div.monthly.xs {
div.monthly details, div.monthly h3 {
  display: none;
}

Ole Voldsæter's avatar
Ole Voldsæter committed
.v-label span {
  color: var(--v-primary-base);
}

.lang_select_container {
Henrik Askjer's avatar
Henrik Askjer committed
.pos_select_container {
  padding-left: 10px;
  padding-right: 10px;
  padding-bottom: 0px;
  padding-top: 10px;
}

Ole Voldsæter's avatar
Ole Voldsæter committed
li.suggestion {
  font-weight: bold;
  padding-left: 20px;
  padding-top: 5px;
  padding-bottom: 5px;
  border: 0px;
  background-image: none;
}

::selection {
  background: var(--v-secondary-base);
  color: white;
}

Henrik Askjer's avatar
Henrik Askjer committed
#return_to_results {
  padding-left: 10px;
  padding-top: 10px;
Henrik Askjer's avatar
Henrik Askjer committed
  padding-bottom: 10px;
Ole Voldsæter's avatar
Ole Voldsæter committed
  display: table-cell;
}

Henrik Askjer's avatar
Henrik Askjer committed
#return_to_results a {
  color: var(--v-text-base) !important;
Henrik Askjer's avatar
Henrik Askjer committed
  text-decoration: none;
Ole Voldsæter's avatar
Ole Voldsæter committed
.nav_arrow {
  color: var(--v-primary-base) !important;
}

Henrik Askjer's avatar
Henrik Askjer committed
.col {
  padding: 10px;
}

.below-notification {
  padding-left: 10px;
}

.did_you_mean.md, .did_you_mean.lg, .did_you_mean.xl {
  max-width: 40%;
}

.dict-parentheses {
  color: rgba(0,0,0,0.6);
  font-size: 85%;
}

Ole Voldsæter's avatar
Ole Voldsæter committed
</style>