Something went wrong on our end
-
Henrik Askjer authoredHenrik Askjer authored
DictionaryView.vue 18.73 KiB
<template>
<main>
<div class="search_container">
<Autocomplete v-on:submit="select_result" :api="get_search_endpoint">
</Autocomplete>
<SearchToolbar v-if="$store.state.showSearchToolbar" @updatePos="update_pos" @updateScope="update_scope"/>
</div>
<SearchResults :results_bm="search_results.bm || []"
:results_nn="search_results.nn || []"
:lang="lang"
:key="lang"
@article-click="article_link_click"
@details-click="details_click"
@update-page="update_page"
v-if="total_results() && ! article" />
<div id="spinner" v-if="waiting">
<v-progress-circular indeterminate color="secondary" size="120"></v-progress-circular>
</div>
<div id="single_article_container" v-if="article">
<div class="return_to_results" v-if="total_results">
<router-link :to="article.source" @click.native="return_to_results()">
<v-icon left class="nav_arrow">chevron_left</v-icon>{{$t("back_to_results")}}
</router-link>
</div>
<Article :key="article_key" :article="article" @article-click="article_link_click" />
</div>
<div class="welcome" v-if="! (article || error || total_results() || waiting)">
<div class="monthly" :class="$vuetify.breakpoint.name">
<div>
<Article :article="monthly_bm" @article-click="article_link_click" />
</div>
<div>
<Article :article="monthly_nn" @article-click="article_link_click" />
</div>
</div>
</div>
<div class="error" v-if="error">
<h1>Ingen treff</h1>
<p v-if="error[0]">{{error[0]}}</p>
<p v-if="error[1]">{{error[1]}}</p>
</div>
</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'
import SearchToolbar from './SearchToolbar.vue'
import { setup } from 'axios-cache-adapter'
const SEARCH_ENDPOINT = process.env.VUE_APP_SEARCH_ENDPOINT
const ARTICLE_ENDPOINT= process.env.VUE_APP_ARTICLE_ENDPOINT
const dicts = {'nn': 'Nynorskordboka',
'bm': 'Bokmålsordboka',
'bm,nn': 'ordbøkene'}
const api = setup({
baseURL: SEARCH_ENDPOINT,
cache: {
maxAge: 15 * 60 * 1000,
exclude: {
query: false,
paths: ["articles"] // Disable caching for articles
}
}
})
function navigate_to_article(self, source) {
self.article = null
self.waiting_for_articles = true
const lang = self.$route.params.lang
axios.get(ARTICLE_ENDPOINT + lang + '/article/' + self.$route.params.id + ".json")
.then(function(response){
self.article = Object.assign(response.data, {'dictionary': lang, results: self.search_results})
self.search_results = {}
self.error = null
})
.catch(function(error){
console.log(error)
if (error.response && error.response.status == 404) {
self.error = ["Vi har ingen artikkel med id " + self.$route.params.id]
} else {
self.error = []
if (self.lang !== 'bm') self.error.push(`Noko gjekk gale...`)
if (self.lang !== 'nn') self.error.push(`Noe gikk galt...`)
}
})
.then(function(response){
self.waiting_for_articles = false
history.replaceState({article: self.article,
search_results: [],
lang: self.lang,
error: self.error,
pos_selected: self.pos_selected,
scope: self.scope,
article_info: self.article_info,
page: self.page,
perPage: self.perPage}, '')
if (source) {
self.$plausible.trackEvent('internal link incoming', {props: {origin: source}})
}
})
}
function load_articles(self, query, offset, n, dict) {
let article_IDs = self.article_info.articles[dict]
if (article_IDs)
{
if (offset > article_IDs.length) {
n = 0
}
else if (offset + n > article_IDs.length) {
n = article_IDs.length % n
}
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) => {
return axios.get(`${ARTICLE_ENDPOINT}${dict}/article/${article_id}.json`)
}))
.then((response) => {
let results = response.map((element, index) => {
return Object.assign(element.data, {
dictionary: dict
})
})
// TODO: Error handling must be moved
self.article = null
if (!results.length && offset == 0) {
if (query.match) {
self.error = []
if (self.lang !== 'bm') {
self.error.push(`Ordet «${query.match}» finst ikkje i Nynorskordboka. Bruk knappen «bokmål (bm)» om du har søkt i feil ordbok.`)
}
if (self.lang !== 'nn') self.error.push(`Ordet «${query.match}» finnes ikke i Bokmålsordboka. Bruk knappen «nynorsk (nn)» om du har søkt i feil ordbok.`)
} else {
self.error = [`Søk på «${query.q}» gir ingen treff i ${dicts[self.lang]}.`]
// If not advanced search
if (query.search != 2) self.error[0] += " Søk med * eller % dersom du er usikker på skrivemåten. Søketips kan du finne i «OM ORDBØKENE»."
if (self.lang == "bm") self.error[0] += ` Bruk knappen «nynorsk (nn)» om du har søkt i feil ordbok.`
if (self.lang == "nn") self.error[0] += ` Bruk knappen «bokmål (bm)» om du har søkt i feil ordbok.`
}
}
else {
self.error = null
}
self.search_results[dict] = results
console.log("DICT", dict, "OFFSET", offset,"N", n, "RESULTS", results)
})
.catch(error => {
self.waiting_for_articles = false
self.connection_error(error)
})
}
else {
self.search_results[dict] = []
console.log("NO")
}
}
return Promise.resolve()
}
function navigate_to_query(self, word) {
self.waiting_for_articles = true
self.max_scroll = window.window.innerHeight
let query = self.event ? self.event : {q: word}
self.query = query
// Get article IDs
let params = {w: query.match || query.q, dict: self.lang, scope: self.scope, meta: 'y'}
let offset = 0
if (self.page) {
offset = 10 * (self.page -1)
console.log("PAGE", self.page)
}
if (self.pos_selected != "ALL") params.wc = self.pos_selected
api.get('articles?', {params}).then((response) => {
self.article_info = response.data
self.search_results = {}
Promise.all([
load_articles(self, query, offset, 10, "bm"),
load_articles(self, query, offset, 10, "nn")
])
.then(() => {
self.waiting_for_articles = false
history.replaceState({
article: self.article,
lang: self.lang,
error: self.error,
pos_selected: self.pos_selected,
scope: self.scope,
article_info: self.article_info,
search_results: self.search_results,
page: self.page,
perPage: self.perPage
}, '')
})
}).catch(error =>{
self.waiting_for_articles = false
self.connection_error(error)
})
}
export default {
name: 'DictionaryView',
data: function() {
return {
article_key: 0,
search_results: [],
lang: this.$store.state.defaultDict,
waiting_for_articles: true,
waiting_for_metadata: true,
article: null,
error: null,
monthly_bm: null,
monthly_nn: null,
event: null,
previous: this.$route.fullPath,
scope: "w",
pos_selected: "ALL",
article_info: null,
page: null,
perPage: null,
}
},
computed: {
waiting: function() {
return (this.waiting_for_articles || this.waiting_for_metadata) && this.$route.name != 'root'
},
get_search_endpoint: function() {
return api
},
},
components: {
Article,
Autocomplete,
SearchResults,
SearchToolbar
},
methods: {
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
}
},
connection_error: function(error) {
console.log(error)
this.search_results = {}
if (error.response) {
this.error = []
if (this.lang !== 'bm') this.error.push(`Noko gjekk gale på serversida`)
if (this.lang !== 'nn') this.error.push(`Noe gikk galt på serversiden"`)
} else {
this.error = []
if (this.lang !== 'bm') this.error.push(`Nettverksproblem, prøv igjen`)
if (this.lang !== 'nn') this.error.push(`Nettverksproblemer, prøv igjen`)
}
},
select_result: function (event) {
this.event = event
let path = `/${this.lang}/search`
let pos = this.pos_param()
let query = {q: event.match || event.q}
console.log(pos)
if (pos != "all") query["pos"] = pos
if (this.scope) query["scope"] = this.scope
this.$router.push({path, query})
navigate_to_query(this)
// Tracking
let track_props = {query: event.q}
if (event.match) track_props.match = event.match
this.$plausible.trackEvent(event.update_lang ? "language" : 'dropdown selection', {
props: track_props
})
},
pos_param: function() {
if (this.pos_selected) return this.pos_selected.toLowerCase()
return ""
},
update_page: function() {
let q = (this.$route.query || this.$route.params).q
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
this.$router.push({path, query})
let offset = 0
if (this.page) {
offset = 10 * (this.page -1)
console.log("PAGE", this.page)
}
console.log(query.q)
console.log(this)
let self = this
Promise.all([
load_articles(this, query, offset, 10, "bm"),
load_articles(this, query, offset, 10, "nn")]).then(() => {
history.replaceState({article: self.article,
search_results: self.search_results,
lang: self.lang,
error: self.error,
pos_selected: self.pos_selected,
scope: self.scope,
article_info: self.article_info,
page: self.page,
perPage: self.perPage}, ''),
self.$forceUpdate()
}
)
},
reload_params: function() {
let q = (this.$route.query || this.$route.params).q
if (q) {
let path = `/${this.lang}/search`
let pos = this.pos_param()
let query = {q: q}
if (pos != 'all') query.pos = pos
if (this.scope) query.scope = this.scope
this.$router.push({path, query})
navigate_to_query(this, q)
}
},
update_lang_form: function (lang) {
console.log(this.article_info)
this.lang = lang
this.reload_params()
},
update_scope: function(scope) {
this.scope = scope
this.reload_params()
},
update_pos: function (pos) {
this.pos_selected = pos
this.reload_params()
},
article_link_click: function(item) {
if (this.article && this.article.article_id == item.article_id){
this.article_key++
history.replaceState({article: this.article,
search_results: this.search_results,
lang: this.lang,
error: this.error,
pos_selected: this.pos_selected,
scope: this.scope,
article_info: this.article_info,
page: this.page,
perPage: this.perPage}, '')
}else{
navigate_to_article(this, item.source)
}
},
details_click: function(item) {
item.article.source = this.previous
this.article = item.article
history.replaceState({article: this.article,
search_results: [],
lang: this.lang,
error: null,
pos_selected: this.pos_selected,
scope: this.scope,
article_info: this.article_info,
page: this.page,
perPage: this.perPage}, '')
},
return_to_results: function() {
this.article = null
}
},
watch: {
$route(to, from) {
this.previous = from.fullPath
}
},
mounted: function(){
let self = this
self.lang = self.$route.params.lang || this.$store.state.defaultDict
if (self.$route.query.pos) {
self.pos_selected = self.$route.query.pos.toUpperCase()
}
if (self.$route.query.scope) {
self.scope = self.$route.query.scope
}
if (self.$route.query.page) self.page = parseInt(self.$route.query.page)
if (self.$route.query.perPage) self.perPage = self.$route.query.perPage
Promise.all([
axios.get(ARTICLE_ENDPOINT + 'bm/concepts.json').then(function(response){
let concepts = response.data.concepts
entities.bm = concepts
}),
axios.get(ARTICLE_ENDPOINT + '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 == 'query') {
navigate_to_query(self, self.$route.query.q)
}
else if(self.$route.name == 'search') {
navigate_to_query(self, self.$route.params.query)
}
else if(self.$route.name == 'word') {
navigate_to_query(self, self.$route.params.query)
}
else if(self.$route.name == 'lookup'){
navigate_to_article(self, self.$route.path)
}
else {
self.waiting_for_articles = false
history.replaceState({article: self.article,
search_results: self.search_results,
lang: self.lang,
error: self.error,
pos_selected: self.pos_selected,
scope: self.scope,
article_info: self.article_info,
page: self.page,
perPage: self.perPage}, '')
// words of the month
axios.get(ARTICLE_ENDPOINT + 'bm/article/5607.json').then(function(response){
self.monthly_bm = Object.assign(response.data, {dictionary: 'bm'})
})
axios.get(ARTICLE_ENDPOINT + 'nn/article/78569.json').then(function(response){
self.monthly_nn = Object.assign(response.data, {dictionary: 'nn'})
})
}
}).catch(function(error){
console.log(error)
self.error = []
if (self.lang !== 'bm') self.error.push(`Eit nettverksproblem hindra lasting av sida. Prøv å laste sida på nytt`)
if (self.lang !== 'nn') self.error.push(`Et nettverksproblem hindret lasting av siden. Prøv å laste siden på nytt`)
self.waiting_for_metadata = false
self.waiting_for_articles = false
})
},
created: function() {
let self = this
window.onpopstate = function (event) {
if (event.state) {
self.article = event.state.article
self.search_results = event.state.search_results
self.lang = event.state.lang
self.pos_selected = event.pos_selected || self.pos_selected
self.scope = event.scope || self.scope
self.error = event.state.error
self.page = event.state.page,
self.perPage = event.state.perPage
}
}
/*
window.onscroll = () => {
if (window.pageYOffset > this.max_scroll && window.pageYOffset > window.window.innerHeight) {
this.max_scroll += window.window.innerHeight
if (this.max_scroll > document.body.scrollHeight - window.window.innerHeight-1) {
this.max_scroll = document.body.scrollHeight - window.window.innerHeight-1
}
let offset = 5 * this.page
this.page += 1
if (!self.waiting_for_articles) {
self.waiting_for_articles = true
Promise.all([
load_articles(this, this.query, offset, 5, "bm"),
load_articles(this, this.query, offset, 5, "nn")
]).then(() => {
self.waiting_for_articles = false
})
}
}
} */
}
}
</script>
<style>
main {
flex: 1 0 auto;
background-color: var(--v-tertiary-base);
display: flex;
flex-direction: column;
}
div.welcome {
margin-top: 1em;
flex-grow: 10;
background-image: url('../assets/books.jpg');
background-repeat: no-repeat;
}
div.welcome article {
border-style: none;
}
.search_container {
background-color: var(--v-tertiary-base);
padding-top: 10px;
}
#spinner {
margin: auto;
}
#search_results, #spinner, #single_article_container, div.welcome, div.search_container, .error {
padding-left: calc((100vw - 1200px) / 2);
padding-right: calc((100vw - 1200px) / 2);
}
.error > p {
margin-left: 15px;
}
#spinner {
padding-top: 40px;
}
div.monthly {
display: flex;
width: 100%;
}
div.monthly > div {
flex: 50%;
}
div.monthly.sm, div.monthly.xs {
flex-direction: column;
}
div.monthly article.bm .dict-label::before {
content: "fra ";
}
div.monthly article.nn .dict-label::before {
content: "frå ";
}
div.monthly details, div.monthly h3 {
display: none;
}
.v-label span {
color: var(--v-primary-base);
}
.lang_select_container {
padding-left: 10px;
}
.pos_select_container {
padding-left: 10px;
padding-right: 10px;
padding-bottom: 0px;
padding-top: 10px;
}
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;
}
.return_to_results {
padding-top: 10px;
display: table-cell;
}
.return_to_results a {
color: var(--v-primary-base) !important;
text-decoration: none;
}
.nav_arrow {
vertical-align: top !important;
margin-left: 10px;
color: var(--v-primary-base) !important;
}
.col {
padding: 10px;
}
</style>