[gnome-maps] placeBubble: Show Wikipedia summary



commit e95416b67f9a33eaf56bf2efff43ec61d51df430
Author: James Westman <james flyingpimonster net>
Date:   Mon Aug 10 14:27:26 2020 -0500

    placeBubble: Show Wikipedia summary
    
    Show an extract (currently approx. the first 200 characters) of a place's
    Wikipedia article, if it has one, in the place bubble. The link to the full
    article is at the end.

 src/placeBubble.js | 50 +++++++++++++++++++++++++++++++++++----------
 src/wikipedia.js   | 59 ++++++++++++++++++++++++++++++++++++++++--------------
 2 files changed, 83 insertions(+), 26 deletions(-)
---
diff --git a/src/placeBubble.js b/src/placeBubble.js
index bab3e4bf..8d2a3bbc 100644
--- a/src/placeBubble.js
+++ b/src/placeBubble.js
@@ -286,16 +286,14 @@ var PlaceBubble = GObject.registerClass({
         }
 
         if (place.wiki) {
-            let link = this._formatWikiLink(place.wiki);
-            content.push({ info: _("Wikipedia"),
-                           linkUrl: link});
+            content.push({ type: 'wikipedia', info: '' });
         }
 
         return content;
     }
 
     _attachContent(content) {
-        content.forEach(({ label, icon, linkUrl, info }) => {
+        content.forEach(({ type, label, icon, linkUrl, info }) => {
             let separator = new Gtk.Separator({ visible: true });
             separator.get_style_context().add_class('no-margin-separator');
             this._placeDetails.add(separator);
@@ -347,8 +345,13 @@ var PlaceBubble = GObject.registerClass({
                                          hexpand: true,
                                          halign: Gtk.Align.FILL });
 
-            box.add(widget);
+            if (type === 'wikipedia') {
+                box.marginTop = 14;
+                box.marginBottom = 18;
+                this._wikipediaLabel = widget;
+            }
 
+            box.add(widget);
             this._placeDetails.add(box);
         });
     }
@@ -363,24 +366,49 @@ var PlaceBubble = GObject.registerClass({
         this._attachContent(content);
 
         this._contactAvatar.text = formatter.title;
-
         this._title.label = formatter.title;
 
-        if (place.wiki)
-            this._requestWikipediaThumbnail(place.wiki);
+        if (place.wiki) {
+            this._requestWikipedia(place.wiki);
+        }
 
         this.loading = false;
     }
 
-    _requestWikipediaThumbnail(wiki) {
-        Wikipedia.fetchArticleThumbnail(wiki, THUMBNAIL_FETCH_SIZE,
-                                        this._onThumbnailComplete.bind(this));
+    _requestWikipedia(wiki) {
+        this._wiki = wiki;
+
+        Wikipedia.fetchArticleInfo(wiki,
+                                   THUMBNAIL_FETCH_SIZE,
+                                   this._onWikiMetadataComplete.bind(this),
+                                   this._onThumbnailComplete.bind(this));
     }
 
     _onThumbnailComplete(thumbnail) {
         this.thumbnail = thumbnail;
     }
 
+    _onWikiMetadataComplete(metadata) {
+        if (metadata.extract) {
+            let text = GLib.markup_escape_text(metadata.extract, -1);
+            let link = this._formatWikiLink(this._wiki);
+
+            /* If the text goes past some number of characters (see
+             * wikipedia.js), it is ellipsized with '...'
+             * GNOME HIG says to use U+2026 HORIZONTAL ELLIPSIS instead.
+             * Also, trim whitespace. */
+            text = text.replace(/\s*\.\.\.\s*$/, '…');
+
+            let uri = GLib.markup_escape_text(link, -1);
+            /* double-escape the tooltip text, as GTK treats it as markup */
+            let tooltipText = GLib.markup_escape_text(uri, -1);
+
+            /* Translators: This is the text for the "Wikipedia" link at the end
+               of summaries */
+            this._wikipediaLabel.label = `${text} <a href="${link}" title="${tooltipText}">${ _("Wikipedia") 
}</a>`;
+        }
+    }
+
     // clear the view widgets to be able to re-populate an updated place
     _clearView() {
         this._placeDetails.get_children().forEach((child) => child.destroy());
diff --git a/src/wikipedia.js b/src/wikipedia.js
index 48e231c1..cca2ab36 100644
--- a/src/wikipedia.js
+++ b/src/wikipedia.js
@@ -37,6 +37,7 @@ function _getSoupSession() {
 }
 
 let _thumbnailCache = {};
+let _metadataCache = {};
 
 function getLanguage(wiki) {
     return wiki.split(':')[0];
@@ -52,31 +53,54 @@ function getHtmlEntityEncodedArticle(wiki) {
 }
 
 /*
- * Try to fetch the thumbnail given an article title and thumbnail size
- * Calls callback with the Gdk.PixBuf of the icon when successful, otherwise
- * undefined
+ * Fetch various metadata about a Wikipedia article, given the wiki language
+ * and article title.
+ *
+ * @size is the maximum width of the thumbnail.
+ *
+ * Calls @metadataCb with an object containing information about the article.
+ * For the keys/values of this object, see the relevant MediaWiki API
+ * documentation.
+ *
+ * Calls @thumbnailCb with the Gdk.Pixbuf of the icon when successful, otherwise
+ * null.
  */
-function fetchArticleThumbnail(wiki, size, callback) {
+function fetchArticleInfo(wiki, size, metadataCb, thumbnailCb) {
     let lang = getLanguage(wiki);
     let title = getHtmlEntityEncodedArticle(wiki);
     let uri = Format.vprintf('https://%s.wikipedia.org/w/api.php', [ lang ]);
     let msg = Soup.form_request_new_from_hash('GET', uri, { action: 'query',
                                                             titles: title,
-                                                            prop: 'pageimages',
+                                                            prop: 'extracts|pageimages',
                                                             format: 'json',
+
+                                                            /* Allow redirects, for example if an
+                                                               article is renamed. */
+                                                            redirects: '1',
+
+                                                            /* don't go past first section header */
+                                                            exintro: 'yes',
+                                                            /* limit the length   */
+                                                            exchars: '200',
+                                                            /* for plain text rather than HTML */
+                                                            explaintext: 'yes',
+
                                                             pithumbsize: size + ''});
     let session = _getSoupSession();
+    let cachedMetadata = _metadataCache[wiki];
     let cachedThumbnail = _thumbnailCache[wiki + '/' + size];
 
-    if (cachedThumbnail) {
-        callback(cachedThumbnail);
+    if (cachedMetadata && cachedThumbnail) {
+        metadataCb(cachedMetadata);
+        thumbnailCb(cachedThumbnail);
         return;
     }
 
     session.queue_message(msg, (session, msg) => {
         if (msg.status_code !== Soup.KnownStatusCode.OK) {
-            log("Failed to request thumbnail: " + msg.reason_phrase);
-            callback(null);
+            log("Failed to request Wikipedia metadata: " + msg.reason_phrase);
+            metadataCb({});
+            thumbnailCb(null);
             return;
         }
 
@@ -88,20 +112,25 @@ function fetchArticleThumbnail(wiki, size, callback) {
              * object, but the API specifies the sub-object as the page ID,
              * so we'll have to use this iteration approach here
              */
-            for (let page in pages) {
-                let thumbnail = pages[page].thumbnail;
+            for (let pageId in pages) {
+                let page = pages[pageId];
 
+                _metadataCache[wiki] = page;
+                metadataCb(page);
+
+                let thumbnail = page.thumbnail;
                 if (thumbnail) {
-                    let source = pages[page].thumbnail.source;
+                    let source = page.thumbnail.source;
 
-                    _fetchThumbnailImage(wiki, size, source, callback);
+                    _fetchThumbnailImage(wiki, size, source, thumbnailCb);
                 } else {
-                    callback(null);
+                    thumbnailCb(null);
                 }
                 return;
             }
         } else {
-            callback(null);
+            metadataCb({});
+            thumbnailCb(null);
         }
     });
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]