From 7403fdd42aefe86101fbea68201d0aa934e4f1ca Mon Sep 17 00:00:00 2001 From: zexigong Date: Sun, 26 Feb 2023 18:55:03 -0800 Subject: [PATCH 1/6] Open ImageViewer when user clicks an article image --- src/components/image_viewer/ImageViewer.vue | 10 ++- src/components/topic_page/Wikipedia.vue | 76 +++++++++++++++++++-- src/store/store.js | 4 +- 3 files changed, 79 insertions(+), 11 deletions(-) diff --git a/src/components/image_viewer/ImageViewer.vue b/src/components/image_viewer/ImageViewer.vue index 4ee0a05a..add7737c 100644 --- a/src/components/image_viewer/ImageViewer.vue +++ b/src/components/image_viewer/ImageViewer.vue @@ -64,7 +64,7 @@ -
+ @@ -56,6 +57,7 @@ import axios from "axios"; import HeaderLink from "@/components/HeaderLink"; import ArticleLanguageMenu from "@/components/menu/ArticleLanguageMenu"; import Links from "@/components/topic_page/Links"; +import ImageViewer from "@/components/image_viewer/ImageViewer"; export default { name: "WikipediaArticle", props: {}, @@ -120,7 +122,8 @@ export default { components: { HeaderLink, ArticleLanguageMenu, - Links + Links, + ImageViewer }, methods: { onLanguageChange(language) { @@ -149,7 +152,69 @@ export default { response.data.wikipedia.content_urls.desktop.page; } }); + }, + isDescendant(child) { + let node = child.parentNode; + while (node) { + if (node === this.$refs.excerpt || node === this.$refs.remain) { + return true; + } + node = node.parentNode; + } + return false; } + }, + mounted() { + let imgs = document.querySelectorAll("img"); + let refs = this.$refs; + imgs.forEach(img => { + if ( + img.parentElement && + img.parentElement.nodeName == "A" && + this.isDescendant(img.parentElement) + ) { + // suppress orginal click action + img.parentElement.addEventListener("click", function(e) { + e.preventDefault(); + }); + img.addEventListener("click", function(e) { + let items = [ + { + actors: [], + collection: "", + creators: [], + datecreated: [], + description: [], + details: [], + downloadURL: "", + formats: [], + geoLocations: [], + id: "", + imageURL: img.currentSrc + .slice(0, img.currentSrc.lastIndexOf("/")) + .replace("/thumb", ""), + infoURL: img.parentElement.href, + inscriptions: [], + institutions: [], + inventoryNumber: "", + license: "", + license_link: "", + materials: [], + measurements: [], + places: [], + publisher: null, + rightsstatement: "", + source: "", + subjects: [], + thumbURL: img.currentSrc, + title: [img.parentElement.parentElement.outerText], + year: 0 + } + ]; + refs.imageviewer.show(items, 0); + }); + } + }); } }; @@ -209,7 +274,6 @@ export default { } */ .expanded .remain { - display:initial; + display: initial; } - diff --git a/src/store/store.js b/src/store/store.js index b395d95f..c9379b1e 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -11,8 +11,8 @@ Vue.use(VueAxios, axios) import WIKI from './constants' -//const BASE_URL = "http://localhost:3000/" -const BASE_URL = "https://wikidocumentaries-api.wmflabs.org/" +const BASE_URL = "http://localhost:3000/" +// const BASE_URL = "https://wikidocumentaries-api.wmflabs.org/" const wikidocumentaries = { title: 'Vapaamuurarin hauta', From ecdca39385246343011aad6bee98fe8b6c6b8de3 Mon Sep 17 00:00:00 2001 From: zexigong <108034351+zexigong@users.noreply.github.com> Date: Sun, 26 Feb 2023 19:18:47 -0800 Subject: [PATCH 2/6] undo store change --- src/store/store.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/store/store.js b/src/store/store.js index c9379b1e..fa280240 100644 --- a/src/store/store.js +++ b/src/store/store.js @@ -11,8 +11,8 @@ Vue.use(VueAxios, axios) import WIKI from './constants' -const BASE_URL = "http://localhost:3000/" -// const BASE_URL = "https://wikidocumentaries-api.wmflabs.org/" +// const BASE_URL = "http://localhost:3000/" +const BASE_URL = "https://wikidocumentaries-api.wmflabs.org/" const wikidocumentaries = { title: 'Vapaamuurarin hauta', From 2eeb2e80f6fa91a08d65b5a0ce8b4f914f34747a Mon Sep 17 00:00:00 2001 From: zexigong <108034351+zexigong@users.noreply.github.com> Date: Sun, 5 Mar 2023 01:52:45 -0800 Subject: [PATCH 3/6] Use API to fetch imageinfo Support multiple images in image viewer --- src/components/image_viewer/ImageViewer.vue | 6 +- src/components/topic_page/Wikipedia.vue | 190 ++++++++++++++------ 2 files changed, 139 insertions(+), 57 deletions(-) diff --git a/src/components/image_viewer/ImageViewer.vue b/src/components/image_viewer/ImageViewer.vue index add7737c..36d4c5be 100644 --- a/src/components/image_viewer/ImageViewer.vue +++ b/src/components/image_viewer/ImageViewer.vue @@ -64,7 +64,7 @@
-
+ @@ -116,7 +116,8 @@ export default { return { isExpanded: false, language: this.$i18n.locale, - wikipedia: this.$store.state.wikidocumentaries.wikipedia + wikipedia: this.$store.state.wikidocumentaries.wikipedia, + items: [] }; }, components: { @@ -150,10 +151,12 @@ export default { this.wikipedia.remainingHTML = response.data.wikipediaRemainingHTML; this.wikipedia.wikipediaURL = response.data.wikipedia.content_urls.desktop.page; + this.items = []; } }); }, - isDescendant(child) { + // check if an element is n decendant of the article + isArticleDescendant(child) { let node = child.parentNode; while (node) { if (node === this.$refs.excerpt || node === this.$refs.remain) { @@ -162,59 +165,142 @@ export default { node = node.parentNode; } return false; - } - }, - mounted() { - let imgs = document.querySelectorAll("img"); - let refs = this.$refs; - imgs.forEach(img => { - if ( - img.parentElement && - img.parentElement.nodeName == "A" && - this.isDescendant(img.parentElement) - ) { - // suppress orginal click action - img.parentElement.addEventListener("click", function(e) { + }, + // get the image title from wiki imageURL + getImageTitleFromURL(imgURL) { + return imgURL.slice(imgURL.lastIndexOf("/") + 1); + }, + async getImageDetailsInfo(imgs) { + const parent = this; + // check if items data is stored + if (this.items.length !== 0) return this.items; + this.items = new Array(imgs.length); + await Promise.all( + imgs.map(async function(img, index) { + let requestConfig = { + baseURL: parent.$store.state.BASE_URL, + url: "/wiki/imageinfo", + method: "get", + params: { + titles: parent.getImageTitleFromURL(img.parentNode.href), + language: parent.language + } + }; + await axios + .request(requestConfig) + .then(function(response) { + let wikiImageInfo = response.data.wikiImageInfo; + let extMetadata = wikiImageInfo.imageinfo[0].extmetadata; + // fill the image item fields with data from the api + parent.items[index] = { + actors: [], + collection: "", + creators: extMetadata.Artist ? [extMetadata.Artist.value] : [], + datecreated: extMetadata.DateTimeOriginal + ? [extMetadata.DateTimeOriginal.value] + : [], + description: extMetadata.ImageDescription + ? [extMetadata.ImageDescription.value] + : [], + details: [], + downloadURL: wikiImageInfo.imageinfo[0].url, + formats: [], + geoLocations: [], + id: "", + imageURL: wikiImageInfo.imageinfo[0].url, + infoURL: img.parentElement.href, + inscriptions: [], + institutions: [], + inventoryNumber: "", + license: extMetadata.License ? extMetadata.License.value : "", + license_link: extMetadata.LicenseUrl + ? extMetadata.LicenseUrl.value + : "", + materials: [], + measurements: [], + places: [], + publisher: null, + rightsstatement: "", + source: "", + subjects: [], + thumbURL: img.currentSrc, + title: [ + extMetadata.ObjectName.value + ? extMetadata.ObjectName.value + : wikiImageInfo.title + ], + year: 0 + }; + }) + .catch(function(error) { + // infer image info from the img element + parent.items[index] = { + actors: [], + collection: "", + creators: [], + datecreated: [], + description: [], + details: [], + downloadURL: "", + formats: [], + geoLocations: [], + id: "", + imageURL: img.currentSrc + .slice(0, img.currentSrc.lastIndexOf("/")) + .replace("/thumb", ""), + infoURL: img.parentElement.href, + inscriptions: [], + institutions: [], + inventoryNumber: "", + license: "", + license_link: "", + materials: [], + measurements: [], + places: [], + publisher: null, + rightsstatement: "", + source: "", + subjects: [], + thumbURL: img.currentSrc, + title: [img.parentElement.parentElement.outerText], + year: 0 + }; + console.log(error); + }); + }) + ); + return this.items; + }, + addLinksToImages() { + // query all images in the wikipedia article + const imgs = Array.from(document.querySelectorAll("img")).filter( + img => + img.parentElement && + img.parentElement.nodeName == "A" && + this.isArticleDescendant(img.parentElement) + ); + const parent = this; + for (let i = 0; i < imgs.length; i++) { + let img = imgs[i]; + // suppress orginal image click action + img.parentElement.addEventListener("click", e => { e.preventDefault(); }); - img.addEventListener("click", function(e) { - let items = [ - { - actors: [], - collection: "", - creators: [], - datecreated: [], - description: [], - details: [], - downloadURL: "", - formats: [], - geoLocations: [], - id: "", - imageURL: img.currentSrc - .slice(0, img.currentSrc.lastIndexOf("/")) - .replace("/thumb", ""), - infoURL: img.parentElement.href, - inscriptions: [], - institutions: [], - inventoryNumber: "", - license: "", - license_link: "", - materials: [], - measurements: [], - places: [], - publisher: null, - rightsstatement: "", - source: "", - subjects: [], - thumbURL: img.currentSrc, - title: [img.parentElement.parentElement.outerText], - year: 0 - } - ]; - refs.imageviewer.show(items, 0); + // when the image is clicked, the image viewer is opened + img.addEventListener("click", async e => { + const items = await parent.getImageDetailsInfo(imgs); + parent.$refs.imageviewer.show(items, i); }); } - }); + } + }, + mounted() { + // add links on page mounted + this.addLinksToImages(); + }, + updated() { + // add links on language changed + this.addLinksToImages(); } }; From 4150e979a5fe6a11d5a7b6b5b55f6abff7b766d1 Mon Sep 17 00:00:00 2001 From: zexigong <108034351+zexigong@users.noreply.github.com> Date: Tue, 14 Mar 2023 22:43:10 -0700 Subject: [PATCH 4/6] convert item field htmlString to regular text --- src/components/topic_page/Wikipedia.vue | 26 ++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/components/topic_page/Wikipedia.vue b/src/components/topic_page/Wikipedia.vue index e1809763..3ef49089 100644 --- a/src/components/topic_page/Wikipedia.vue +++ b/src/components/topic_page/Wikipedia.vue @@ -170,6 +170,16 @@ export default { getImageTitleFromURL(imgURL) { return imgURL.slice(imgURL.lastIndexOf("/") + 1); }, + // convert item field htmlString to regular text + convertHtmlToText(htmlString) { + const parser = new DOMParser(); + const floatingElement = parser.parseFromString( + htmlString , + "text/html" + ); + const text = floatingElement.activeElement.innerText; + return text; + }, async getImageDetailsInfo(imgs) { const parent = this; // check if items data is stored @@ -195,12 +205,22 @@ export default { parent.items[index] = { actors: [], collection: "", - creators: extMetadata.Artist ? [extMetadata.Artist.value] : [], + creators: extMetadata.Artist + ? [parent.convertHtmlToText(extMetadata.Artist.value)] + : [], datecreated: extMetadata.DateTimeOriginal - ? [extMetadata.DateTimeOriginal.value] + ? [ + parent.convertHtmlToText( + extMetadata.DateTimeOriginal.value + ) + ] : [], description: extMetadata.ImageDescription - ? [extMetadata.ImageDescription.value] + ? [ + parent.convertHtmlToText( + extMetadata.ImageDescription.value + ) + ] : [], details: [], downloadURL: wikiImageInfo.imageinfo[0].url, From cdaba90336798adfae030d12f43c50eccf15e8ad Mon Sep 17 00:00:00 2001 From: zexigong <108034351+zexigong@users.noreply.github.com> Date: Fri, 24 Mar 2023 01:00:34 -0700 Subject: [PATCH 5/6] Migrate most data processing logic to backend --- src/components/topic_page/Wikipedia.vue | 73 ++++++------------------- 1 file changed, 18 insertions(+), 55 deletions(-) diff --git a/src/components/topic_page/Wikipedia.vue b/src/components/topic_page/Wikipedia.vue index 3ef49089..83419e64 100644 --- a/src/components/topic_page/Wikipedia.vue +++ b/src/components/topic_page/Wikipedia.vue @@ -173,10 +173,7 @@ export default { // convert item field htmlString to regular text convertHtmlToText(htmlString) { const parser = new DOMParser(); - const floatingElement = parser.parseFromString( - htmlString , - "text/html" - ); + const floatingElement = parser.parseFromString(htmlString, "text/html"); const text = floatingElement.activeElement.innerText; return text; }, @@ -200,57 +197,23 @@ export default { .request(requestConfig) .then(function(response) { let wikiImageInfo = response.data.wikiImageInfo; - let extMetadata = wikiImageInfo.imageinfo[0].extmetadata; - // fill the image item fields with data from the api - parent.items[index] = { - actors: [], - collection: "", - creators: extMetadata.Artist - ? [parent.convertHtmlToText(extMetadata.Artist.value)] - : [], - datecreated: extMetadata.DateTimeOriginal - ? [ - parent.convertHtmlToText( - extMetadata.DateTimeOriginal.value - ) - ] - : [], - description: extMetadata.ImageDescription - ? [ - parent.convertHtmlToText( - extMetadata.ImageDescription.value - ) - ] - : [], - details: [], - downloadURL: wikiImageInfo.imageinfo[0].url, - formats: [], - geoLocations: [], - id: "", - imageURL: wikiImageInfo.imageinfo[0].url, - infoURL: img.parentElement.href, - inscriptions: [], - institutions: [], - inventoryNumber: "", - license: extMetadata.License ? extMetadata.License.value : "", - license_link: extMetadata.LicenseUrl - ? extMetadata.LicenseUrl.value - : "", - materials: [], - measurements: [], - places: [], - publisher: null, - rightsstatement: "", - source: "", - subjects: [], - thumbURL: img.currentSrc, - title: [ - extMetadata.ObjectName.value - ? extMetadata.ObjectName.value - : wikiImageInfo.title - ], - year: 0 - }; + // Process some data here because DOMParser is not available at backend + if (wikiImageInfo.datecreated && wikiImageInfo.datecreated[0]) { + wikiImageInfo.datecreated[0] = parent.convertHtmlToText( + wikiImageInfo.datecreated[0] + ); + } + if (wikiImageInfo.creators && wikiImageInfo.creators[0]) { + wikiImageInfo.creators[0] = parent.convertHtmlToText( + wikiImageInfo.creators[0] + ); + } + if (wikiImageInfo.description && wikiImageInfo.description[0]) { + wikiImageInfo.description[0] = parent.convertHtmlToText( + wikiImageInfo.description[0] + ); + } + parent.items[index] = wikiImageInfo; }) .catch(function(error) { // infer image info from the img element From ed0237af5fb6aebc29ac9cf63ac60f7b3c318447 Mon Sep 17 00:00:00 2001 From: zexigong <108034351+zexigong@users.noreply.github.com> Date: Thu, 25 May 2023 00:58:43 -0700 Subject: [PATCH 6/6] Merge multiple request for getting images from api into one request --- src/components/topic_page/Wikipedia.vue | 60 ++++++++++++------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/src/components/topic_page/Wikipedia.vue b/src/components/topic_page/Wikipedia.vue index 83419e64..6b059328 100644 --- a/src/components/topic_page/Wikipedia.vue +++ b/src/components/topic_page/Wikipedia.vue @@ -182,41 +182,21 @@ export default { // check if items data is stored if (this.items.length !== 0) return this.items; this.items = new Array(imgs.length); - await Promise.all( - imgs.map(async function(img, index) { - let requestConfig = { + const titles = imgs.map(img => parent.getImageTitleFromURL(img.parentNode.href)); + let requestConfig = { baseURL: parent.$store.state.BASE_URL, url: "/wiki/imageinfo", method: "get", params: { - titles: parent.getImageTitleFromURL(img.parentNode.href), + titles: titles, language: parent.language } }; - await axios - .request(requestConfig) - .then(function(response) { - let wikiImageInfo = response.data.wikiImageInfo; - // Process some data here because DOMParser is not available at backend - if (wikiImageInfo.datecreated && wikiImageInfo.datecreated[0]) { - wikiImageInfo.datecreated[0] = parent.convertHtmlToText( - wikiImageInfo.datecreated[0] - ); - } - if (wikiImageInfo.creators && wikiImageInfo.creators[0]) { - wikiImageInfo.creators[0] = parent.convertHtmlToText( - wikiImageInfo.creators[0] - ); - } - if (wikiImageInfo.description && wikiImageInfo.description[0]) { - wikiImageInfo.description[0] = parent.convertHtmlToText( - wikiImageInfo.description[0] - ); - } - parent.items[index] = wikiImageInfo; - }) - .catch(function(error) { - // infer image info from the img element + let response = await axios.request(requestConfig); + for (var index = 0; index < response.data.wikiImageInfo.length; index++){ + let imgInfo = response.data.wikiImageInfo[index]; + if (!imgInfo){ + let img = imgs[index]; parent.items[index] = { actors: [], collection: "", @@ -248,10 +228,26 @@ export default { title: [img.parentElement.parentElement.outerText], year: 0 }; - console.log(error); - }); - }) - ); + } + else{ + if (imgInfo.datecreated && imgInfo.datecreated[0]) { + imgInfo.datecreated[0] = parent.convertHtmlToText( + imgInfo.datecreated[0] + ); + } + if (imgInfo.creators && imgInfo.creators[0]) { + imgInfo.creators[0] = parent.convertHtmlToText( + imgInfo.creators[0] + ); + } + if (imgInfo.description && imgInfo.description[0]) { + imgInfo.description[0] = parent.convertHtmlToText( + imgInfo.description[0] + ); + } + parent.items[index] = imgInfo; + } + } return this.items; }, addLinksToImages() {