Newer
Older
<template>
<div id="app">
<main>
<header>
<h1><a href="/">Ordbøkene <span style="color: #bbbbbb;">(BETA)</span></a></h1>
<p class="about-link"><a href="#">OM ORDBØKENE</a></p>
<p class="sub-title"><a href="/">Bokmålsordboka og Nynorskordboka</a></p>
<p class="mission-statement"><a href="/">Skrivemåte og bøying i tråd med norsk rettskriving </a></p>
</header>
<div class="search_container">
<autocomplete :debounceTime="100" :auto-select="true" :search="search" @submit="select_result" placeholder="søk..." ref="search">
<template #result="{result, props}">
<li class="suggestion" v-bind="props">{{result.label}}</li>
</template>
</autocomplete>
<div class="lang_select_container">
<select class="lang_select" name="lang" v-model="lang">
<option value="bob,nob">Begge målformer </option>
<option value="bob">Bokmål</option>
<option value="nob">Nynorsk</option>
</select>
</div>
<img id="spinner" :class="waiting ? 'show' : 'hide'" src="./assets/spinner.gif" alt="Venter på innhold" />
<SearchResults :hits="search_results" :lang="lang" @article-click="article_link_click" v-show="! waiting" />
<div id="single_article_container">
<Article :key="article_key" :article="article" @article-click="article_link_click" />
</div>
<div class="welcome" v-show="! (article.error || article.lemmas.length || search_results.length || waiting)">
</div>
</main>
<footer>
<div>
<img id="uiblogo" src="./assets/uib-logo.svg" alt="">
<p>Ordbøkene eies av Universitetet i Bergen sammen med Språkrådet, under ledelse frå Språksamlingane</p>
<p><strong>REDAKTØRANSVAR: HF-FAKULTETET VED UiB</strong></p>
</div>
<div>
<img id="srlogo" src="./assets/Sprakradet_logo_neg.png" alt="">
<p> Språkrådet er statens fagorgan i språkspørsmål og følger opp den norske språkpolitikken på oppdrag fra Kulturdepartementet.
Språkrådet forvalter rettskrivningen i nynorsk og bokmål.</p>
</div>
</footer>
import entities from './utils/entities.js'
import SearchResults from './components/SearchResults.vue'
import Autocomplete from '@trevoreyre/autocomplete-vue'
import '@trevoreyre/autocomplete-vue/dist/style.css'
var api_endpoint = 'https://beta.ordbok.uib.no/api/dict'
axios.interceptors.request.use(function (config) {
config.headers["x-api-key"] = "ZkYiyRVXxH86ijsvhx3cH4SY5Iik2ijI3BKVJGMm"
return config;
}, function (error) {
return Promise.reject(error);
});
window.onpopstate = function (event) {
if (event.state) {
app.__vue__._data.search_results = event.state.search_results
function navigate_to_article(self, source) {
axios.get(api_endpoint + '/' + self.$route.params.lang + '/article/' + self.$route.params.id)
.then(function(response){
})
.catch(function(error){
if (error.response && error.response.status == 404) {
self.article = {
lemmas: [],
error: "Vi har ingen artikkel med id " + article_id
}
} else {
self.article = {
lemmas: [],
error: "Noe gikk galt..."
}
console.log(error)
}
})
.then(function(response){
self.waiting_for_articles = false
history.replaceState({article: self.article, search_results: [], lang: self.lang}, '')
if (source) {
self.$plausible.trackEvent('internal link incoming', {props: {origin: source}})
}
})
}
function navigate_to_search(self, query) {
axios.get(self.api_pref + 'search?q=' + query)
.then(function(response){
self.search_results = response.data
self.waiting_for_articles = false
history.replaceState({article: self.article, search_results: self.search_results, lang: self.lang}, '')
})
}
function navigate_to_word(self, word) {
axios.get(self.api_pref + 'suggest?q=' + word)
.then(function(response){
self.search_results = response.data.filter(result => result.match.length == word.length)
self.waiting_for_articles = false
history.replaceState({article: self.article, search_results: self.search_results, lang: self.lang}, '')
})
}
article_key: 0,
waiting_for_articles: true,
waiting_for_metadata: true,
article: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
waiting: function() {
return this.waiting_for_articles || this.waiting_for_metadata
},
api_pref: function() {
return api_endpoint + '/' + this.lang + '/article/'
},
search: function() {
let self = this
return function(q) {
return new Promise(resolve => {
return axios.get(self.api_pref + 'suggest?q=' + q).then(
function(response) {
if (! hits[0] || hits[0].word != item.match) {
hits.splice(0, 0, {q: q, lang_set: new Set(), word: item.match, articles: []})
hits[0].lang_set.add(item.dictionary == 'bob' ? 'bm' : 'nn')
hits.forEach(function (hit) {
if (hit.lang_set) {
hit.label = `${hit.word} (${Array.from(hit.lang_set).sort().join(', ')})`
hits = hits.slice(0, 8)
if (q) {
hits.push({q: q, label: q + ' (fritekstsøk)'})
}
resolve(hits)
},
methods: {
select_result: function(event) {
this.$refs.search.value = ''
document.activeElement.blur()
this.$router.push('/' + this.lang + '/w/' + event.word)
this.search_results = event.articles
this.article = {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
history.replaceState({article: this.article, search_results: this.search_results, lang: this.lang}, '')
this.$plausible.trackEvent('dropdown selection', {props: {query: event.q, match: event.match}})
this.waiting_for_articles = true
this.article = {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
navigate_to_search(this, event.q)
this.$plausible.trackEvent('dropdown selection', {props: {query: event.q, match: '<fritekstsøk>'}})
if (this.article.article_id == item.article_id){
this.article_key++
history.replaceState({article: this.article, search_results: this.search_results, lang: this.lang}, '')
}else{
this.article = {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
this.waiting_for_articles = true
navigate_to_article(this, item.source)
}
let self = this
Promise.all([
axios.get(api_endpoint + '/bob').then(function(response){
let concepts = response.data.concepts
entities.bob = concepts
}),
axios.get(api_endpoint + '/nob').then(function(response){
let concepts = response.data.concepts
entities.nob = concepts
})
]).then(function(_) {
self.waiting_for_metadata = false
if(self.$route.name == 'word') {
navigate_to_word(self, self.$route.params.word)
}
else if(self.$route.name == 'lookup'){
navigate_to_article(self, self.$route.params.id)
}
self.lang = self.$route.params.lang
navigate_to_search(self, self.$route.params.query)
else {
self.waiting_for_articles = false
history.replaceState({article: self.article, search_results: self.search_results, lang: self.lang}, '')
}
})
},
watch: {
$route() {
this.$plausible.trackEvent('language', {props: {code: this.$route.params.lang}})
}
@import url('https://fonts.googleapis.com/css2?family=Inria+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Inria+Serif:ital,wght@0,400;0,700;1,400;1,700&family=Noto+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap');
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: #2c3e50;
h1 {
font-family: Inria Serif;
font-size: 36px;
color: #560027;
}
header > h1 {
color: #BC477B;
font-size: 40px;
margin: 0px;
}
p.about-link {
text-align: right;
margin: 0px;
header a {
color: inherit;
text-decoration: none;
}
p.about-link > a{
text-decoration: none;
border-bottom: solid #BC477B 4px;
font-size: 12px;
color: #FDF4F5;
}
background-image: url('./assets/books.jpg');
background-repeat: no-repeat;
background-attachment: fixed;
}
header, #search_results, #spinner, #single_article_container, footer, div.welcome, div.search_container {
padding-left: calc((100vw - 1000px) / 2);
padding-right: calc((100vw - 1000px) / 2);
header {
padding-bottom: 20px;
}
div.welcome {
font-size: 20px;
}
.top {
color: #560027;
font-weight: bold;
font-size: smaller;
border-bottom: solid;
border-color: #BC477B;
}
.mission-statement {
font-size: 16px;
margin: 0px;
color: #FDF4F5;
.sub-title {
font-size: 20px;
margin: 0px;
color: #FDF4F5;
}
.show {
display: block;
}
.hide {
display: none;
}
border-bottom: solid #BC477B;
border-radius: 0px;
.autocomplete-input {
border-radius: 0px;
background-color: #FFFFFF;
.autocomplete-result-list {
max-height: 500px;
}
.lang-select-intro {
font-size: smaller;
font-weight: bold;
}
footer {
font-size: smaller;
display: flex;
flex-direction: row;
background-color: #570B27;
color: #ffffff;
padding-bottom: 20px;
}
.search_container {
display: flex;
flex-direction: row;
}
li.suggestion {
font-weight: bold;
padding-top: 5px;
padding-bottom: 5px;
border: 0px;
footer p {
padding-left: 20px;
padding-right: 20px;
margin: 0px;
}
#srlogo {
height: 20px;
padding-top: 50px;
padding-left: 20px;
}
#uiblogo {
height: 60px;
padding: 10px;
padding-left: 20px;
}
select.lang_select {
appearance: none;
border: none;
padding: 0 1em 0 0;
width: 100%;
height: 100%;
font-family: inherit;
font-size: inherit;
font-weight: bold;
cursor: inherit;
line-height: inherit;
background-image: url('./assets/down_arrow.png');
background-position: 98% center;
background-repeat: no-repeat;
background-size: 10%;