From f3f0ea6c1d9087429d8f066f1c51db646839b52c Mon Sep 17 00:00:00 2001 From: Henrik Askjer <henrik.askjer@uib.no> Date: Tue, 16 Nov 2021 13:33:36 +0100 Subject: [PATCH] lazy loading of articles --- src/components/DictionaryView.vue | 147 ++++++++++++++++++------------ src/components/SearchResults.vue | 27 +++--- 2 files changed, 101 insertions(+), 73 deletions(-) diff --git a/src/components/DictionaryView.vue b/src/components/DictionaryView.vue index e871e9ee..8093fec9 100644 --- a/src/components/DictionaryView.vue +++ b/src/components/DictionaryView.vue @@ -36,22 +36,23 @@ <div id="spinner" v-if="waiting"> <v-progress-circular indeterminate color="secondary" size="120"></v-progress-circular> </div> - <SearchResults :hits="search_results" + <SearchResults :results_bm="search_results.bm" + :results_nn="search_results.nn" :lang="lang" :key="lang" :meta="this.article_info.meta" @article-click="article_link_click" @details-click="details_click" - v-if="search_results.length && ! waiting && ! article" /> + v-if="total_results() && ! waiting && ! article" /> <div id="single_article_container" v-if="article"> - <div class="return_to_results" v-if="search_results && search_results.length"> + <div class="return_to_results" v-if="total_results"> <router-link :to="article.source" @click.native="return_to_results()"> <v-icon class="nav_arrow">arrow_left</v-icon>Tilbake til {{article.dictionary == 'bm' ? 'søkeresultater' : 'søkjeresultat'}} </router-link> </div> <Article :key="article_key" :article="article" @article-click="article_link_click" /> </div> - <div class="welcome" v-if="! (article || error || search_results.length || waiting)"> + <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" /> @@ -106,7 +107,7 @@ function navigate_to_article(self, source) { 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.search_results = {} self.error = null }) .catch(function(error){ @@ -120,7 +121,7 @@ function navigate_to_article(self, source) { }) .then(function(response){ self.waiting_for_articles = false - history.replaceState({article: self.article, search_results: [], lang: self.lang, error: self.error, article_info: self.article_info}, '') + history.replaceState({article: self.article, search_results: {}, lang: self.lang, error: self.error, article_info: self.article_info}, '') if (source) { self.$plausible.trackEvent('internal link incoming', {props: {origin: source}}) } @@ -155,9 +156,62 @@ function navigate_to_search(self, query) { } */ -function load_articles(self, response, query, offset, n, dict) { - +function load_articles(self, query, offset, n, dict) { + + let article_IDs = self.article_info.articles[dict] + if (offset > article_IDs.length) { + n = 0 + } + else if (offset + n > article_IDs.length) { + n = n + (article_IDs.length - n) + } + if (n > 0) { + article_IDs = article_IDs.slice(offset, n) + console.log("ARTICLES", dict,article_IDs) + 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 + }) + }) + self.article = null + if (! results.length) { + 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 + } + if (offset == 0) { + self.search_results[dict] = results + } + else { + self.search_results[dict] = self.search_results[dict].concat(results) + } + }) + .catch(error => { + self.waiting_for_articles = false + self.connection_error(error) + }) + } } @@ -168,62 +222,21 @@ function navigate_to_query(self, word) { // Get article IDs api.get('articles?', {params: {w: query.match || query.q, dict: self.lang, scope: "w"}}).then((response) => { self.article_info = response.data - let article_ids = response.data["articles"] - let unwrapped = [] - for (const d in article_ids) { - article_ids[d].forEach(i => unwrapped.push({ - dictionary: d, - id: i - })) - } - - // Get individual articles - Promise.all(unwrapped.map((article) => { - return axios.get(`${ARTICLE_ENDPOINT}${article.dictionary}/article/${article.id}.json`) - - })) - .then((response) => { - self.search_results = response.map((element, index) => { - return Object.assign(element.data, { - dictionary: unwrapped[index].dictionary - }) - }) - self.article = null - if (! self.search_results.length) { - 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 - } - }) - .catch(error => { - self.connection_error(error) - }) + self.search_results = {} + Promise.all([load_articles(self, query, 0, 10, "bm"), + load_articles(self, query, 0, 10, "nn")]) .then(() => { self.waiting_for_articles = false history.replaceState({ article: self.article, - search_results: self.search_results, lang: self.lang, error: self.error, - article_info: self.article_info - }, '') + article_info: self.article_info, + search_results: self.search_results + }, '') + }) + }).catch(error =>{ self.connection_error(error) @@ -262,8 +275,24 @@ export default { SearchResults }, methods: { + total_results: function() { + + if (this.search_results) { + let total = 0 + if (this.search_results.bm) { + return total += this.search_results.bm.length + } + if (this.search_results.nn) { + return this.search_results.nn.length + } + console.log("TOTAL", total) + return total + + } + + }, connection_error: function(error) { - this.search_results = [] + this.search_results = {} if (error.response) { this.error = [] if (this.lang !== 'bm') this.error.push(`Noko gjekk gale på serversida`) @@ -316,7 +345,7 @@ export default { 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, article_info: this.article_info}, '') + history.replaceState({article: this.article, search_results: {}, lang: this.lang, error: null, article_info: this.article_info}, '') }, return_to_results: function() { this.article = null diff --git a/src/components/SearchResults.vue b/src/components/SearchResults.vue index a3330519..f560eed8 100644 --- a/src/components/SearchResults.vue +++ b/src/components/SearchResults.vue @@ -1,9 +1,9 @@ <template> <section id="search_results"> <div class="flex-container" :class="$vuetify.breakpoint.name"> - <ul class="hits" v-if="results_bm.length"> + <ul class="hits" :v-if="results_bm"> <li class="results-count">Treff i Bokmålsordboka: {{count_bm}}</li> - <li class="article_container" v-for="(result, index) in results_bm" :key="index + results_hash" tabindex="-1"> + <li class="article_container" v-for="(result, index) in results_bm" :key="index + bm_hash" tabindex="-1"> <Article :article="result" @article-click="article_link_click" @@ -11,9 +11,9 @@ </Article> </li> </ul> - <ul class="hits" v-if="results_nn.length"> + <ul class="hits" :v-if="results_nn"> <li class="results-count">Treff i Nynorskorboka: {{count_nn}}</li> - <li class="article_container" v-for="(result, index) in results_nn" :key="index + results_hash" tabindex="-1"> + <li class="article_container" v-for="(result, index) in results_nn" :key="index + nn_hash" tabindex="-1"> <Article :article="result" @article-click="article_link_click" @@ -28,31 +28,30 @@ <script> import Article from './Article.vue' - export default { name: 'SearchResults', props: { - hits: Array, + results_bm: Array, + results_nn: Array, lang: String, meta: Object }, computed: { right_col_class_name: function() { if (this.$vuetify.breakpoint.mdAndUp) { - if (this.results_bm.length) { + if (this.results_bm) { return 'righ_hand_column' } } return '' }, - results_bm: function(){ - return this.hits.filter(hit => hit.dictionary == 'bm') - }, - results_nn: function(){ - return this.hits.filter(hit => hit.dictionary == 'nn') + bm_hash: function(){ + console.log("HASH_B;") + return this.results_bm.reduce((hash, hit) => (hash + hit.article_id) % 10000, 0) }, - results_hash: function(){ - return this.hits.reduce((hash, hit) => (hash + hit.article_id) % 10000, 0) + nn_hash: function(){ + console.log("HASH_NN") + return this.results_nn.reduce((hash, hit) => (hash + hit.article_id) % 10000, 0) }, count_bm: function(){ console.log(this.meta) -- GitLab