Skip to content
Snippets Groups Projects
Commit a724d78f authored by Petr Kalashnikov's avatar Petr Kalashnikov
Browse files

Merge remote-tracking branch 'origin/master' into UU428

parents e884a1ef ee58dcbd
No related branches found
No related tags found
No related merge requests found
...@@ -21,5 +21,4 @@ yarn-error.log* ...@@ -21,5 +21,4 @@ yarn-error.log*
*.sw? *.sw?
package-lock.json
*.iml *.iml
source diff could not be displayed: it is too large. Options to address this: view the blob.
...@@ -12,16 +12,16 @@ ...@@ -12,16 +12,16 @@
"@fortawesome/free-brands-svg-icons": "^5.15.3", "@fortawesome/free-brands-svg-icons": "^5.15.3",
"@fortawesome/free-solid-svg-icons": "^5.15.3", "@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/vue-fontawesome": "^2.0.2", "@fortawesome/vue-fontawesome": "^2.0.2",
"axios": "^0.19.2", "axios": "^0.21.1",
"core-js": "~3.6.5", "core-js": "~3.6.5",
"debounce": "^1.2.1", "debounce": "^1.2.1",
"inflection-table": "https://git.app.uib.no/api/v4/projects/16442/jobs/artifacts/0.2.20/raw/module.tar.gz?job=publish", "inflection-table": "https://git.app.uib.no/api/v4/projects/16442/jobs/artifacts/0.2.25/raw/module.tar.gz?job=publish",
"vue": "^2.6.12", "vue": "^2.6.12",
"vue-material-design-icons": "^4.11.0", "vue-material-design-icons": "^4.11.0",
"vue-plausible": "^1.1.4", "vue-plausible": "^1.1.4",
"vue-router": "^3.5.1", "vue-router": "^3.5.1",
"vue-social-sharing": "^3.0.8", "vue-social-sharing": "^3.0.8",
"vuetify": "^2.4.8" "vuetify": "^2.5.8"
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.8",
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
"eslint": "^5.16.0", "eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0", "eslint-plugin-vue": "^5.0.0",
"material-design-icons-iconfont": "^6.1.0", "material-design-icons-iconfont": "^6.1.0",
"sass": "^1.32.8", "sass": "^1.38.0",
"sass-loader": "^10.0.0", "sass-loader": "^10.0.0",
"vue-cli-plugin-vuetify": "^2.1.1", "vue-cli-plugin-vuetify": "^2.1.1",
"vue-template-compiler": "^2.6.12", "vue-template-compiler": "^2.6.12",
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
font-family: NotoParen, 'Noto Sans', Helvetica, Arial, sans-serif; font-family: NotoParen, 'Noto Sans', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
color: #2c3e50; color: var(--v-text-base);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
......
...@@ -124,12 +124,12 @@ article { ...@@ -124,12 +124,12 @@ article {
padding: 24px; padding: 24px;
margin: 10px; margin: 10px;
border-radius: 30px; border-radius: 30px;
border: solid 1px var(--v-primary-base); border: solid 1px var(--v-border-base);
background-color: var(--v-tertiary-base); background-color: #ffffff;
} }
#single_article_container article { #single_article_container article {
border-style: none; border: solid 2px var(--v-primary-base);
} }
.fade { .fade {
...@@ -141,7 +141,7 @@ section { ...@@ -141,7 +141,7 @@ section {
} }
h3 { h3 {
color: #560027; color: var(--v-primary-base);
font-variant: small-caps; font-variant: small-caps;
} }
......
<template> <template>
<div class="autocomplete-container" :class="$vuetify.breakpoint.name" > <div class="autocomplete-container" :class="$vuetify.breakpoint.name">
<v-autocomplete <v-combobox
v-model="select" v-model="select"
:loading="loading" :loading="loading"
:items="items" :items="items"
:search-input.sync="search" :search-input.sync="search"
item-text="label" item-text="label"
:menu-props="{maxHeight: $vuetify.breakpoint.name === 'xs' ? 190 : 500, transition: 'fade-transition'}" :menu-props="{maxHeight: $vuetify.breakpoint.name === 'xs' ? 190 : 500, transition: 'fade-transition', allowOverflow: true}"
prepend-inner-icon="search" prepend-inner-icon="search"
:append-icon="null" :append-icon="null"
return-object return-object
rounded rounded
hide-no-data hide-no-data
auto-select-first
no-filter no-filter
hide-details hide-details
label="Søk..." label="Søk..."
...@@ -19,26 +20,27 @@ ...@@ -19,26 +20,27 @@
full-width full-width
flat flat
outlined outlined
auto-select-first
placeholder="Søk her" placeholder="Søk her"
ref="autocomplete" ref="autocomplete"
color="primary" color="primary"
:dense="$vuetify.breakpoint.smAndDown" :dense="$vuetify.breakpoint.smAndDown"
> >
<template v-slot:item="data"> <template v-slot:item="data">
<span class="search-hit">{{data.item.label}} </span> ({{data.item.lang_set ? Array.from(data.item.lang_set).sort().join(', ') : 'fritekstsøk'}}) <span class="search-hit">
{{data.item.label}}
</span>
({{data.item.lang? data.item.lang[1] ? "bm, nn" : {"bob": "bm", "nob": "nn"}[data.item.lang[0]] : 'fritekstsøk'}})
</template> </template>
</v-autocomplete> </v-combobox>
</div> </div>
</template> </template>
<script> <script>
import axios from "axios" import axios from "axios"
import debounce from "debounce"
export default { export default {
props: { props: {
endpoint: String endpoint: String,
}, },
data: function() { data: function() {
return { return {
...@@ -46,42 +48,7 @@ ...@@ -46,42 +48,7 @@
items: [], items: [],
search: null, search: null,
select: null, select: null,
debounced: debounce(function(q, self) { suggesting: null,
self.loading = true
return axios.get(self.endpoint + 'suggest?q=' + encodeURIComponent(q))
.then(
function(response) {
let hits = []
if (q == self.search) {
response.data.forEach((item, i) => {
let match = encodeURIComponent(item.match)
if (! hits[0] || hits[0].word != match) {
hits.splice(0, 0, {q: encodeURIComponent(q), lang_set: new Set(), word: match, articles: []})
}
hits[0].lang_set.add(item.dictionary == 'bob' ? 'bm' : 'nn')
hits[0].articles.push(item)
});
hits.forEach(function (hit) {
if (hit.lang_set) {
hit.label = decodeURIComponent(hit.word)
}
});
hits.reverse()
hits = hits.slice(0, 9)
}
hits.sort( (h1, h2) => {
let val1 = h1.label.length * 10 + (h1.label[0].toLowerCase() === h1.label[0] ? 0 : 1)
let val2 = h2.label.length * 10 + (h2.label[0].toLowerCase() === h2.label[0] ? 0 : 1)
return val1 - val2
})
if (q) {
hits.push({q: encodeURIComponent(q), label: q + ' '})
}
self.items = hits
self.loading = false
})
}, 100)
} }
}, },
watch: { watch: {
...@@ -93,15 +60,84 @@ ...@@ -93,15 +60,84 @@
} }
}, },
select(item) { select(item) {
this.$emit('submit', item) if (item) {
let self = this if (typeof item != 'string') {
setTimeout(() => self.$refs.autocomplete.$refs.input.select(), 1) let self = this
/*
if (item.articles) {
axios.get(self.endpoint + 'articles?', {params: {lord: item.match,
dict: self.$parent.lang}})
.then(
function(response) {
['bob', 'nob'].forEach((dict_tag) => {
response.data[dict_tag].forEach((article_id) => {
let article = {}
article.article_id = article_id
article.dictionary = dict_tag
article.match = item.match
item.articles.push(article)
})
})
}
)
}
*/
this.items = []
this.suggesting = false
self.$emit('submit', item)
setTimeout(() => {
self.$refs.autocomplete.$refs.input.select()
this.items = []
this.suggesting = false
}, 1)
}
// If blurred
else {
this.items = []
}
}
} }
}, },
methods: { methods: {
run_query(q) { run_query(q) {
this.debounced(q, this) this.suggesting = true
} // Put full text search in the list while processing suggestions
if (this.items[0]) {
if (this.items[0].lang) {
this.items.unshift({q: q, label: q})
}
else {
this.items[0] = {q: q, label: q}
}
}
let self = this
axios.get(self.endpoint + 'suggest?', { params: {q: q,
dict: self.$parent.lang,
n: 9}} )
.then(
function(response) {
if (self.$refs.autocomplete.searchInput == q & self.suggesting) {
let hits = []
response.data.forEach((item, i) => {
let hit = {q: q, match: item[0], label: item[0], articles: []}
hit.lang = item[1]
hits.push(hit)
});
// whitespace necessary because duplicates aren't allowed in the dropdown
hits.push({q: q, label: q + ' '})
self.items = hits
}
self.loading = false
})
},
}, },
} }
</script> </script>
......
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
</v-radio> </v-radio>
</v-radio-group> </v-radio-group>
</div> </div>
<Autocomplete @submit="select_result" :endpoint="api_pref"> <Autocomplete @submit="select_result" :endpoint="oda_endpoint">
</Autocomplete> </Autocomplete>
</div> </div>
<div id="spinner" v-if="waiting"> <div id="spinner" v-if="waiting">
...@@ -74,6 +74,7 @@ import SearchResults from './SearchResults.vue' ...@@ -74,6 +74,7 @@ import SearchResults from './SearchResults.vue'
import Autocomplete from './Autocomplete.vue' import Autocomplete from './Autocomplete.vue'
var api_endpoint = process.env.VUE_APP_API_PREFIX + '/api/dict' var api_endpoint = process.env.VUE_APP_API_PREFIX + '/api/dict'
const oda_endpoint = 'https://oda.uib.no/opal-api/'
function compare_by_hgno(lemma_text) { function compare_by_hgno(lemma_text) {
return function(art1, art2) { return function(art1, art2) {
...@@ -188,6 +189,9 @@ export default { ...@@ -188,6 +189,9 @@ export default {
}, },
api_pref: function() { api_pref: function() {
return api_endpoint + '/' + this.lang + '/article/' return api_endpoint + '/' + this.lang + '/article/'
},
oda_endpoint: function() {
return oda_endpoint
} }
}, },
components: { components: {
...@@ -199,19 +203,24 @@ export default { ...@@ -199,19 +203,24 @@ export default {
select_result: function(event) { select_result: function(event) {
this.event = event this.event = event
if(event.articles){ if(event.articles){
let source = '/' + this.lang + '/w/' + event.word let source = '/' + this.lang + '/w/' + event.match
this.$router.push(source) this.$router.push(source)
this.search_results = event.articles.sort(compare_by_hgno(decodeURIComponent(event.word))).map(a => Object.assign(a, {source: source})) /*
this.search_results = event.articles.map(a => Object.assign(a, {source: source}))
this.article = null this.article = null
this.error = null this.error = null
history.replaceState({article: this.article, search_results: this.search_results, lang: this.lang, error: this.error}, '') history.replaceState({article: this.article, search_results: this.search_results, lang: this.lang, error: this.error}, '')
this.$plausible.trackEvent('dropdown selection', {props: {query: event.label, match: event.match}}) */
this.waiting_for_articles = true
navigate_to_word(this, event.match)
this.$plausible.trackEvent('dropdown selection', {props: {query: event.q, match: event.match}})
}else{ }else{
this.waiting_for_articles = true this.waiting_for_articles = true
this.article = null this.article = null
this.$router.push(`/${this.lang}/search/${event.q}`) this.$router.push(`/${this.lang}/search/${event.q}`)
navigate_to_search(this, event.q) navigate_to_search(this, event.q)
this.$plausible.trackEvent('dropdown selection', {props: {query: event.label, match: '<fritekstsøk>'}}) this.$plausible.trackEvent('dropdown selection', {props: {query: event.q, match: '<fritekstsøk>'}})
} }
}, },
update_lang_form: function(event) { update_lang_form: function(event) {
......
...@@ -99,9 +99,6 @@ export default { ...@@ -99,9 +99,6 @@ export default {
<style> <style>
article (table, th, td) {
border: solid 1px;
}
summary { summary {
width: 30em; width: 30em;
...@@ -217,7 +214,7 @@ details > summary::-webkit-details-marker { ...@@ -217,7 +214,7 @@ details > summary::-webkit-details-marker {
background-color: #ffffff; background-color: #ffffff;
border: solid 1px; border: solid 1px;
color: var(--v-primary-base); color: var(--v-primary-base);
border-color: var(--v-primary-base); border-color: var(--v-border-base);
border-radius: 10px; border-radius: 10px;
padding: 10px; padding: 10px;
width: min-content; width: min-content;
...@@ -236,16 +233,17 @@ div.lemma { ...@@ -236,16 +233,17 @@ div.lemma {
table { table {
border-collapse: collapse; border-collapse: collapse;
margin-top: 5px; margin-top: 5px;
border-color: var(--v-primary-base);
} }
th, td { th, td {
border: solid 1px; border: solid 1px;
border-color: var(--v-primary-base);
padding: 5px; padding: 5px;
} }
th { th {
background-color: var(--v-tertiary-darken1) background-color: var(--v-tertiary-darken1);
color: var(--v-primary-darken1);
} }
.infl-label { .infl-label {
......
...@@ -51,7 +51,9 @@ export default new Vuetify({ ...@@ -51,7 +51,9 @@ export default new Vuetify({
secondary: '#BC477B', secondary: '#BC477B',
tertiary: '#FDF4F5', tertiary: '#FDF4F5',
anchor: '#560027', anchor: '#560027',
error: '#FDF4F5' error: '#FDF4F5',
border: '#9E9E9E',
text: '#2c3e50'
} }
} }
}, },
......
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