Skip to content
Snippets Groups Projects
Commit 14ba1789 authored by Ole Voldsæter's avatar Ole Voldsæter
Browse files

Merge branch 'routing_minus' into 'master'

Routing

See merge request spraksamlingane/beta.ordbok.uib.no!4
parents e6f2c36a 3a309978
No related branches found
No related tags found
No related merge requests found
......@@ -2,54 +2,10 @@
<v-app id="app">
<header>
<h1><a href="/">Ordbøkene <span class="beta">(BETA)</span></a></h1>
<p class="about-link"><a href="#">OM ORDBØKENE</a></p>
<p class="sub-title"><a href="/">Bokmålsordboka | Nynorskordboka – rett norsk</a></p>
<p class="about-link"><router-link to="/om">OM ORDBØKENE</router-link></p>
<p class="sub-title"><router-link to="/">Bokmålsordboka | Nynorskordboka – rett norsk</router-link></p>
</header>
<main :class="(article.error || article.lemmas.length || search_results.length || waiting) ? '' : 'welcome '">
<div class="search_container">
<div class="lang_select_container">
<v-radio-group row v-model="lang">
<template v-slot:label>
<span>VIS TREFF I</span>
</template>
<v-radio value="bob,nob" color="secondary">
<template v-slot:label>
<span>begge<span class="verbose"> ordbøkene</span></span>
</template>
</v-radio>
<v-radio value="bob" color="secondary">
<template v-slot:label>
<span>bokmål (bm)</span>
</template>
</v-radio>
<v-radio value="nob" color="secondary">
<template v-slot:label>
<span>nynorsk (nn)</span>
</template>
</v-radio>
</v-radio-group>
</div>
<Autocomplete @submit="select_result" :endpoint="api_pref">
</Autocomplete>
</div>
<div id="spinner">
<v-progress-circular indeterminate color="secondary" size="120" v-show="waiting"></v-progress-circular>
</div>
<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 class="monthly">
<div>
<Article :article="monthly_bm" @article-click="article_link_click" />
</div>
<div>
<Article :article="monthly_nn" @article-click="article_link_click" />
</div>
</div>
</div>
</main>
<router-view :uggabuga="1"></router-view>
<footer>
<div>
<img id="srlogo" src="./assets/Sprakradet_logo_neg.png" alt="">
......@@ -62,237 +18,6 @@
</v-app>
</template>
<script>
import axios from "axios"
import entities from './utils/entities.js'
import Article from './components/Article.vue'
import SearchResults from './components/SearchResults.vue'
import Autocomplete from './components/Autocomplete.vue'
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);
});
function navigate_to_article(self, source) {
axios.get(api_endpoint + '/' + self.$route.params.lang + '/article/' + self.$route.params.id)
.then(function(response){
self.article = Object.assign(response.data, {'dictionary': self.$route.params.lang})
self.search_results = []
})
.catch(function(error){
if (error.response && error.response.status == 404) {
self.article = {
lemmas: [],
error: "Vi har ingen artikkel med id " + self.$route.params.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
if (! self.search_results.length) {
self.article = {
lemmas: [],
error: "Vi fant ingen resultater for '" + decodeURIComponent(query) + "'. (Søkeforlag kommer i en senere oppatering av Ordbøkene)"
}
}
})
.catch(function(error){
if (error.response && error.response.status == 400) {
self.article = {
lemmas: [],
error: "Søkeuttrykket inneholder feil"
}
} else if (error.response) {
self.article = {
lemmas: [],
error: "Noe gikk galt på serversiden"
}
} else {
self.article = {
lemmas: [],
error: "Nettverksproblemer, prøv igjen"
}
}
})
.then(function(_){
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)
if (! self.search_results.length) {
self.article = {
lemmas: [],
error: "Ordet '" + decodeURIComponent(word) + "' finnes ikke i ordbøkene"
}
}
})
.catch(function(error){
if (error.response) {
self.article = {
lemmas: [],
error: "Noe gikk galt på serversiden"
}
} else {
self.article = {
lemmas: [],
error: "Nettverksproblemer, prøv igjen"
}
}
})
.then(function(_){
self.waiting_for_articles = false
history.replaceState({article: self.article, search_results: self.search_results, lang: self.lang}, '')
})
}
export default {
name: 'app',
data: function() {
return {
article_key: 0,
search_results: [],
lang: 'bob,nob',
waiting_for_articles: true,
waiting_for_metadata: true,
article: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}},
monthly_bm: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}},
monthly_nn: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
}
},
computed: {
waiting: function() {
return (this.waiting_for_articles || this.waiting_for_metadata) && this.$route.name != 'root'
},
api_pref: function() {
return api_endpoint + '/' + this.lang + '/article/'
}
},
components: {
Article,
Autocomplete,
SearchResults
},
methods: {
select_result: function(event) {
if(event.articles){
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.label, match: event.match}})
}else{
this.waiting_for_articles = true
this.article = {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
this.$router.push(`/${this.lang}/search/${event.q}`)
navigate_to_search(this, event.q)
this.$plausible.trackEvent('dropdown selection', {props: {query: event.label, match: '<fritekstsøk>'}})
}
},
article_link_click: function(item) {
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)
}
}
},
mounted: function(){
let self = this
this.lang = 'bob,nob'
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') {
self.lang = self.$route.params.lang
navigate_to_word(self, self.$route.params.word)
}
else if(self.$route.name == 'lookup'){
navigate_to_article(self, self.$route.params.id)
}
else if (self.$route.name == 'search') {
self.lang = self.$route.params.lang
navigate_to_search(self, self.$route.params.query)
}
else {
self.lang = self.$route.params.lang || 'bob,nob'
self.waiting_for_articles = false
history.replaceState({article: self.article, search_results: self.search_results, lang: self.lang}, '')
}
// words of the month
axios.get(api_endpoint + '/bob/article/5607').then(function(response){
self.monthly_bm = Object.assign(response.data, {dictionary: 'bob'})
})
axios.get(api_endpoint + '/nob/article/78569').then(function(response){
self.monthly_nn = Object.assign(response.data, {dictionary: 'nob'})
})
}).catch(function(_){
self.article = {
lemmas: [],
error: "Et nettverksproblem hindret lasting av siden. Prøv å laste siden på nytt"
}
self.waiting_for_metadata = false
self.waiting_for_articles = false
})
},
watch: {
$route() {
this.$plausible.trackEvent('language', {props: {code: this.$route.params.lang}})
}
},
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
}
}
}
}
</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inria+Serif:ital,wght@0,400;0,700;1,400;1,700&display=swap');
......@@ -353,19 +78,7 @@ p.about-link > a{
color: var(--v-tertiary-base);
}
main {
padding-bottom: 20px;
flex: 1 0 auto;
background-color: var(--v-tertiary-base);
}
main.welcome {
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 {
header, footer {
padding-left: calc((100vw - 1000px) / 2);
padding-right: calc((100vw - 1000px) / 2);
}
......@@ -376,9 +89,6 @@ header, #search_results, #spinner, #single_article_container, footer, div.welcom
}
}
#spinner {
padding-top: 40px;
}
header {
padding-top: 20px;
......@@ -386,25 +96,6 @@ header {
background-color: var(--v-primary-base);
}
div.monthly {
padding: 20px;
border-radius: 10px;
display: flex;
width: 100%;
}
div.monthly > div {
flex: 50%;
}
div.monthly article.bob .dict-label::before {
content: "månedens ";
}
div.monthly article.nob .dict-label::before {
content: "månadens ";
}
.sub-title {
font-size: 20px;
margin: 0px;
......@@ -418,24 +109,6 @@ footer {
color: #ffffff;
}
.search_container {
max-width: 1500px;
padding-top: 50px;
}
.v-label span {
color: var(--v-primary-base);
}
li.suggestion {
font-weight: bold;
padding-left: 20px;
padding-top: 5px;
padding-bottom: 5px;
border: 0px;
background-image: none;
}
footer > div {
display: table-cell;
vertical-align: middle;
......@@ -450,9 +123,5 @@ footer > div {
height: 60px;
}
::selection {
background: var(--v-secondary-base);
color: white;
}
</style>
<template>
<router-view/>
</template>
<template id="">
<main>
<h1>Blæh</h1>
</main>
</template>
<template>
<main :class="(article.error || article.lemmas.length || search_results.length || waiting) ? '' : 'welcome '">
<div class="search_container">
<div class="lang_select_container">
<v-radio-group row v-model="lang">
<template v-slot:label>
<span>VIS TREFF I</span>
</template>
<v-radio value="bob,nob" color="secondary">
<template v-slot:label>
<span>begge<span class="verbose"> ordbøkene</span></span>
</template>
</v-radio>
<v-radio value="bob" color="secondary">
<template v-slot:label>
<span>bokmål</span>
</template>
</v-radio>
<v-radio value="nob" color="secondary">
<template v-slot:label>
<span>nynorsk</span>
</template>
</v-radio>
</v-radio-group>
</div>
<Autocomplete @submit="select_result" :endpoint="api_pref">
</Autocomplete>
</div>
<div id="spinner">
<v-progress-circular indeterminate color="secondary" size="120" v-show="waiting"></v-progress-circular>
</div>
<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 class="monthly">
<div>
<Article :article="monthly_bm" @article-click="article_link_click" />
</div>
<div>
<Article :article="monthly_nn" @article-click="article_link_click" />
</div>
</div>
</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'
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);
});
function navigate_to_article(self, source) {
axios.get(api_endpoint + '/' + self.$route.params.lang + '/article/' + self.$route.params.id)
.then(function(response){
self.article = Object.assign(response.data, {'dictionary': self.$route.params.lang})
self.search_results = []
})
.catch(function(error){
if (error.response && error.response.status == 404) {
self.article = {
lemmas: [],
error: "Vi har ingen artikkel med id " + self.$route.params.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
if (! self.search_results.length) {
self.article = {
lemmas: [],
error: "Vi fant ingen resultater for '" + decodeURIComponent(query) + "'. (Søkeforlag kommer i en senere oppatering av Ordbøkene)"
}
}
})
.catch(function(error){
if (error.response && error.response.status == 400) {
self.article = {
lemmas: [],
error: "Søkeuttrykket inneholder feil"
}
} else if (error.response) {
self.article = {
lemmas: [],
error: "Noe gikk galt på serversiden"
}
} else {
self.article = {
lemmas: [],
error: "Nettverksproblemer, prøv igjen"
}
}
})
.then(function(_){
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)
if (! self.search_results.length) {
self.article = {
lemmas: [],
error: "Ordet '" + decodeURIComponent(word) + "' finnes ikke i ordbøkene"
}
}
})
.catch(function(error){
if (error.response) {
self.article = {
lemmas: [],
error: "Noe gikk galt på serversiden"
}
} else {
self.article = {
lemmas: [],
error: "Nettverksproblemer, prøv igjen"
}
}
})
.then(function(_){
self.waiting_for_articles = false
history.replaceState({article: self.article, search_results: self.search_results, lang: self.lang}, '')
})
}
export default {
name: 'DictionaryView',
data: function() {
return {
article_key: 0,
search_results: [],
lang: 'bob,nob',
waiting_for_articles: true,
waiting_for_metadata: true,
article: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}},
monthly_bm: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}},
monthly_nn: {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
}
},
computed: {
waiting: function() {
return (this.waiting_for_articles || this.waiting_for_metadata) && this.$route.name != 'root'
},
api_pref: function() {
return api_endpoint + '/' + this.lang + '/article/'
}
},
components: {
Article,
Autocomplete,
SearchResults
},
methods: {
select_result: function(event) {
if(event.articles){
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.label, match: event.match}})
}else{
this.waiting_for_articles = true
this.article = {lemmas: [], body:{pronunciation: [], definitions: [], etymology: []}}
this.$router.push(`/${this.lang}/search/${event.q}`)
navigate_to_search(this, event.q)
this.$plausible.trackEvent('dropdown selection', {props: {query: event.label, match: '<fritekstsøk>'}})
}
},
article_link_click: function(item) {
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)
}
}
},
mounted: function(){
let self = this
this.lang = 'bob,nob'
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') {
self.lang = self.$route.params.lang
navigate_to_word(self, self.$route.params.word)
}
else if(self.$route.name == 'lookup'){
navigate_to_article(self, self.$route.params.id)
}
else if (self.$route.name == 'search') {
self.lang = self.$route.params.lang
navigate_to_search(self, self.$route.params.query)
}
else {
self.lang = self.$route.params.lang || 'bob,nob'
self.waiting_for_articles = false
history.replaceState({article: self.article, search_results: self.search_results, lang: self.lang}, '')
}
// words of the month
axios.get(api_endpoint + '/bob/article/5607').then(function(response){
self.monthly_bm = Object.assign(response.data, {dictionary: 'bob'})
})
axios.get(api_endpoint + '/nob/article/78569').then(function(response){
self.monthly_nn = Object.assign(response.data, {dictionary: 'nob'})
})
}).catch(function(_){
self.article = {
lemmas: [],
error: "Et nettverksproblem hindret lasting av siden. Prøv å laste siden på nytt"
}
self.waiting_for_metadata = false
self.waiting_for_articles = false
})
},
watch: {
$route() {
this.$plausible.trackEvent('language', {props: {code: this.$route.params.lang}})
}
},
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
}
}
}
}
</script>
<style>
main {
padding-bottom: 20px;
flex: 1 0 auto;
background-color: var(--v-tertiary-base);
}
main.welcome {
background-image: url('../assets/books.jpg');
background-repeat: no-repeat;
background-attachment: fixed;
}
#search_results, #spinner, #single_article_container, div.welcome, div.search_container {
padding-left: calc((100vw - 1000px) / 2);
padding-right: calc((100vw - 1000px) / 2);
}
#spinner {
padding-top: 40px;
}
div.monthly {
padding: 20px;
border-radius: 10px;
display: flex;
width: 100%;
}
div.monthly > div {
flex: 50%;
}
div.monthly article.bob .dict-label::before {
content: "månedens ";
}
div.monthly article.nob .dict-label::before {
content: "månadens ";
}
.search_container {
max-width: 1400px;
padding-top: 50px;
}
.v-label span {
color: var(--v-primary-base);
}
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;
}
</style>
import Vue from 'vue'
import Root from './Root.vue'
import App from './App.vue'
import About from './components/About.vue'
import DictionaryView from './components/DictionaryView.vue'
import VueRouter from 'vue-router'
import { VuePlausible } from 'vue-plausible'
import vuetify from './plugins/vuetify';
......@@ -17,28 +20,44 @@ const router = new VueRouter({
base: __dirname,
routes: [
{
name: 'root',
path: '/:lang?',
component: App }, // No props, no nothing
{
name: 'word',
path: '/:lang/w/:word'
},
{
name: 'lookup',
path: '/:lang/:id(\\d+)/:lemma?',
component: App,
props: true }, // Pass route.params to props
{
name: 'search',
path: '/:lang/search/:query',
path: '/',
component: App,
props: true}
children: [
{
path: 'om',
name: 'about',
component: About
},
{
path: '',
component: DictionaryView,
children: [
{
path: ':lang',
children: [
{
name: 'word',
path: 'w/:word'
},
{
name: 'lookup',
path: ':id(\\d+)/:lemma?'
},
{
name: 'search',
path: 'search/:query'
}
]
}
]
}
]
}
]
})
new Vue({
router,
vuetify,
render: h => h(App)
render: h => h(Root )
}).$mount('#app')
module.exports = {
runtimeCompiler: true,
transpileDependencies: [
'vuetify'
]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment