Jdlrobson has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/169730

Change subject: Creative destruction: Wikidata Infoboxes in alpha
......................................................................

Creative destruction: Wikidata Infoboxes in alpha

This replaces infoboxes in alpha of the site with a Wikidata generated one.
The idea is we can use this to highlight missing data and use it as a basis
for wikidata games.

Change-Id: I9c206b4c87b9aec0e8e59f484a24d26fd7570fdf
---
M includes/Resources.php
A javascripts/modules/infobox/Infobox.js
A javascripts/modules/infobox/init.js
M javascripts/modules/wikigrok/WikiDataApi.js
A templates/modules/wikigrok/Infobox.hogan
5 files changed, 294 insertions(+), 25 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/MobileFrontend 
refs/changes/30/169730/1

diff --git a/includes/Resources.php b/includes/Resources.php
index bf4ac15..24958c0 100644
--- a/includes/Resources.php
+++ b/includes/Resources.php
@@ -546,9 +546,11 @@
        'mobile.alpha' => $wgMFMobileResourceBoilerplate + array(
                'dependencies' => array(
                        'mobile.beta',
+                       'mobile.infobox',
                ),
                'scripts' => array(
                        'javascripts/modules/mf-translator.js',
+                       'javascripts/modules/infobox/init.js',
                ),
        ),
 
@@ -918,18 +920,26 @@
                ),
        ),
 
+       'mobile.wikigrok.api' => $wgMFMobileResourceBoilerplate + array(
+               'dependencies' => array(
+                       'mobile.startup',
+               ),
+               'scripts' => array(
+                       'javascripts/modules/wikigrok/WikiDataApi.js',
+                       'javascripts/modules/wikigrok/WikiGrokApi.js',
+               ),
+       ),
+
        // See https://www.mediawiki.org/wiki/Extension:MobileFrontend/WikiGrok
        'mobile.wikigrok.dialog' => $wgMFMobileResourceBoilerplate + array(
                'dependencies' => array(
-                       'mobile.alpha',
+                       'mobile.wikigrok.api',
                ),
                'templates' => array(
                        'modules/wikigrok/WikiGrokDialog.hogan',
                        'modules/wikigrok/WikiGrokMoreInfo.hogan',
                ),
                'scripts' => array(
-                       'javascripts/modules/wikigrok/WikiDataApi.js',
-                       'javascripts/modules/wikigrok/WikiGrokApi.js',
                        'javascripts/modules/wikigrok/WikiGrokDialog.js',
                        'javascripts/modules/wikigrok/WikiGrokMoreInfo.js',
                ),
@@ -938,6 +948,18 @@
                ),
        ),
 
+       'mobile.infobox' => $wgMFMobileResourceBoilerplate + array(
+               'dependencies' => array(
+                       'mobile.wikigrok.api',
+               ),
+               'templates' => array(
+                       'modules/wikigrok/Infobox.hogan',
+               ),
+               'scripts' => array(
+                       'javascripts/modules/infobox/Infobox.js',
+               ),
+       ),
+
        'mobile.site' => array(
                'dependencies' => array( 'mobile.startup' ),
                'class' => 'MobileSiteModule',
diff --git a/javascripts/modules/infobox/Infobox.js 
b/javascripts/modules/infobox/Infobox.js
new file mode 100644
index 0000000..023780c
--- /dev/null
+++ b/javascripts/modules/infobox/Infobox.js
@@ -0,0 +1,209 @@
+( function ( M, $ ) {
+       var Infobox,
+               WikiDataApi = M.require( 'modules/wikigrok/WikiDataApi' ),
+               View = M.require( 'View' );
+       /**
+        * A Wikidata generated infobox.
+        * FIXME: This currently requires 2 hits to the Wikidata API on every 
page load.
+        * @class Infobox
+        * @extends View
+        */
+       Infobox = View.extend( {
+               template: M.template.get( 'modules/wikigrok/Infobox.hogan' ),
+
+               className: 'wikidata-infobox',
+               defaults: {
+                       description: undefined,
+                       rows: []
+               },
+               typeDefaults: {
+                       human: {
+                               description: undefined,
+                               rows: [ {
+                                               id: 'P18'
+                                       },
+                                       // description
+                                       // details about employment
+                                       {
+                                               id: 'P569',
+                                               label: 'Born'
+                                       }, {
+                                               id: 'P19',
+                                               label: 'Birthplace'
+                                       },
+                                       // nationality
+                                       // political party
+                                       {
+                                               id: 'P26',
+                                               label: 'Spouse(s)'
+                                       }, {
+                                               id: 'P25',
+                                               label: 'Mother(s)'
+                                       }, {
+                                               id: 'P22',
+                                               label: 'Father(s)'
+                                       },
+                                       //{ id: 'P43', label: 'Stepfather(s)' },
+                                       {
+                                               id: 'P9',
+                                               label: 'Sister(s)'
+                                       }, {
+                                               id: 'P7',
+                                               label: 'Brother(s)'
+                                       }, {
+                                               id: 'P40',
+                                               label: 'Child(ren)'
+                                       },
+                                       // residence
+                                       {
+                                               id: 'P69',
+                                               label: 'Alma mater'
+                                       }, {
+                                               id: 'P106',
+                                               label: 'Occupation'
+                                       }, {
+                                               id: 'P108',
+                                               label: 'Employer(s)'
+                                       }, {
+                                               id: 'P140',
+                                               label: 'Religion'
+                                       },
+                                       // awards
+                                       {
+                                               id: 'P109',
+                                               label: 'Signature'
+                                       }, {
+                                               id: 'P856',
+                                               label: 'Official website'
+                                       }
+                               ]
+                       },
+                       default: {
+                               description: undefined,
+                               rows: [ {
+                                       id: 'P856',
+                                       label: 'Official website'
+                               } ]
+                       }
+               },
+               /**
+                * Parses a list of claims
+                *
+                * @private
+                * @param {Object} claims as returned by WikiData#getClaims
+                * @return {Array} List of values matching that claim
+                */
+               _getValues: function ( claims ) {
+                       var values = [];
+
+                       $.each( claims, function ( i, claim ) {
+                               var snak = claim.mainsnak,
+                                       value = snak.datavalue;
+                               if ( snak.datatype === 'commonsMedia' ) {
+                                       values.push( {
+                                               url: mw.util.getUrl( 'File:' + 
value.value ),
+                                               // FIXME: Map this to the image 
src
+                                               value: value.value
+                                       } );
+                               } else if ( value.type === 'string' ) {
+                                       values.push( {
+                                               value: value.value
+                                       } );
+                               } else if ( value.type === 'time' ) {
+                                       // FIXME: Make human readable
+                                       values.push( {
+                                               value: value.value.time
+                                       } );
+                               } else if ( value.type === 'wikibase-entityid' 
) {
+                                       values.push( {
+                                               id: 'Q' + value.value[ 
'numeric-id' ],
+                                               isLink: true
+                                       } );
+                               }
+                       } );
+                       return values;
+               },
+               /**
+                * Translates IDs in the current row value to human readable 
text
+                *
+                * @private
+                * @param {Array} rows with id and label
+                * @return {Array} rows with human readable values
+                */
+               _mapLabels: function ( rows ) {
+                       var labelIds = [];
+
+                       // collect all the label ids
+                       $.each( rows, function ( i, row ) {
+                               $.each( row.values, function ( i, value ) {
+                                       if ( value.id ) {
+                                               labelIds.push( value.id );
+                                       }
+                               } );
+                       } );
+
+                       // work out what they all mean
+                       return this.api.getLabels( labelIds ).then( function ( 
labels ) {
+                               // map the property id to the actual label.
+                               $.each( rows, function ( i, row ) {
+                                       $.each( row.values, function ( j, value 
) {
+                                               if ( labels[ value.id ] ) {
+                                                       value.value = labels[ 
value.id ];
+                                                       value.url = 
mw.util.getUrl( value.value );
+                                               }
+                                       } );
+                               } );
+                               return rows;
+                       } );
+               },
+               /**
+                * Decides based on the type of item what infobox to render
+                *
+                * @private
+                * @param {Object} claims as returned by WikiData#getClaims
+                * @return {Object} default option values
+                */
+               getDefaultsFromClaims: function ( claims ) {
+                       if ( claims.isHuman ) {
+                               return this.typeDefaults.human;
+                       } else {
+                               return this.typeDefaults.default;
+                       }
+               },
+               /**
+                * @inheritdoc
+                */
+               initialize: function ( options ) {
+                       var self = this,
+                               _super = View.prototype.render;
+
+                       this.api = new WikiDataApi( {
+                               itemId: options.itemId
+                       } );
+
+                       this.api.getClaims().done( function ( claims ) {
+                               var rows;
+                               options = $.extend( options, 
self.getDefaultsFromClaims( claims ) );
+                               options.description = claims.description;
+                               rows = options.rows;
+                               $.each( rows, function ( i, row ) {
+                                       if ( claims.entities[ row.id ] ) {
+                                               row.values = self._getValues( 
claims.entities[ row.id ] );
+                                       } else {
+                                               row.values = [];
+                                       }
+                                       row.isEmpty = !( row.values && 
row.values.length );
+                               } );
+
+                               self._mapLabels( rows ).done( function ( rows ) 
{
+                                       options.rows = rows;
+                                       _super.call( self, options );
+                               } );
+                       } );
+                       View.prototype.initialize.apply( this, arguments );
+               }
+       } );
+
+       M.define( 'modules/wikigrok/Infobox', Infobox );
+
+}( mw.mobileFrontend, jQuery ) );
diff --git a/javascripts/modules/infobox/init.js 
b/javascripts/modules/infobox/init.js
new file mode 100644
index 0000000..67be01c
--- /dev/null
+++ b/javascripts/modules/infobox/init.js
@@ -0,0 +1,14 @@
+( function ( M ) {
+       M.assertMode( [ 'alpha' ] );
+       var infobox,
+               wikidataID = mw.config.get( 'wgWikibaseItemId' ),
+               Infobox = M.require( 'modules/wikigrok/Infobox' );
+
+       // upset people
+       $( '.infobox' ).hide();
+       // build the future
+       infobox = new Infobox( {
+               itemId: wikidataID
+       } );
+       infobox.insertBefore( M.getLeadSection() );
+}( mw.mobileFrontend ) );
diff --git a/javascripts/modules/wikigrok/WikiDataApi.js 
b/javascripts/modules/wikigrok/WikiDataApi.js
index c0d3fe0..97b2d3e 100644
--- a/javascripts/modules/wikigrok/WikiDataApi.js
+++ b/javascripts/modules/wikigrok/WikiDataApi.js
@@ -1,5 +1,6 @@
 ( function ( M, $ ) {
-       var Api = M.require( 'api' ).Api, WikiDataApi;
+       var Api = M.require( 'api' ).Api,
+               WikiDataApi;
        /**
         * @class WikiDataApi
         * @extends Api
@@ -7,35 +8,46 @@
        WikiDataApi = Api.extend( {
                apiUrl: 'https://www.wikidata.org/w/api.php',
                useJsonp: true,
-               language: 'en',
+               language: mw.config.get( 'wgUserLanguage' ),
 
                initialize: function ( options ) {
                        this.subjectId = options.itemId;
                        Api.prototype.initialize.apply( this, arguments );
                },
                getClaims: function () {
-                       var id = this.subjectId;
+                       var self = this,
+                               id = this.subjectId;
+
                        return this.ajax( {
                                action: 'wbgetentities',
                                ids: id,
-                               props: 'claims',
+                               languages: this.language,
+                               props: [ 'descriptions', 'claims' ],
                                format: 'json'
                        } ).then( function ( data ) {
-                               var instanceClaims, entityClaims,
+                               var description, instanceClaims, entityClaims,
                                        claims = {};
                                // See if the page has any 'instance of' claims.
-                               if ( data.entities !== undefined && 
data.entities[id].claims.P31 !== undefined ) {
-                                       entityClaims = data.entities[id].claims;
+                               if ( data.entities !== undefined && 
data.entities[ id ].claims.P31 !== undefined ) {
+                                       entityClaims = data.entities[ id 
].claims;
                                        instanceClaims = entityClaims.P31;
 
                                        // Examine claims closely
                                        $.each( instanceClaims, function ( i, 
claim ) {
-                                               claims.isHuman = 
claim.mainsnak.datavalue.value['numeric-id'] === 5 ? true : false;
+                                               claims.isHuman = 
claim.mainsnak.datavalue.value[ 'numeric-id' ] === 5 ? true : false;
                                                claims.hasOccupation = 
entityClaims.P106 ? true : false;
                                                claims.hasCountryOfCitizenship 
= entityClaims.P27 ? true : false;
                                                claims.hasDateOfBirth = 
entityClaims.P569 ? true : false;
                                                claims.hasDateOfDeath = 
entityClaims.P570 ? true : false;
                                        } );
+                                       claims.entities = entityClaims;
+                                       description = data.entities[ id ];
+
+                                       if ( description ) {
+                                               if ( description.descriptions[ 
self.language ] ) {
+                                                       claims.description = 
description.descriptions[ self.language ].value;
+                                               }
+                                       }
                                        return claims;
                                } else {
                                        return false;
@@ -52,21 +64,23 @@
                getLabels: function ( itemIds ) {
                        var lang = this.language;
                        return this.ajax( {
-                                       action: 'wbgetentities',
-                                       props: 'labels',
-                                       languages: lang,
-                                       ids: itemIds
-                               } ).then( function ( data ) {
-                                       var map = {};
-                                       $.each( itemIds, function ( i, itemId ) 
{
-                                               if ( 
data.entities[itemId].labels[lang].value !== undefined ) {
-                                                       map[itemId] = 
data.entities[itemId].labels[lang].value;
-                                               } else {
-                                                       map[itemId] = null;
-                                               }
-                                       } );
-                                       return map;
+                               action: 'wbgetentities',
+                               props: 'labels',
+                               languages: lang,
+                               ids: itemIds
+                       } ).then( function ( data ) {
+                               var map = {};
+                               $.each( itemIds, function ( i, itemId ) {
+                                       if ( data.entities[ itemId ].labels &&
+                                               data.entities[ itemId ].labels[ 
lang ] !== undefined
+                                       ) {
+                                               map[ itemId ] = data.entities[ 
itemId ].labels[ lang ].value;
+                                       } else {
+                                               map[ itemId ] = null;
+                                       }
                                } );
+                               return map;
+                       } );
                }
        } );
 
diff --git a/templates/modules/wikigrok/Infobox.hogan 
b/templates/modules/wikigrok/Infobox.hogan
new file mode 100644
index 0000000..e72be6e
--- /dev/null
+++ b/templates/modules/wikigrok/Infobox.hogan
@@ -0,0 +1,10 @@
+<em>{{description}}</em>
+{{#rows}}
+<div>
+       {{^isEmpty}}{{#label}}<strong>{{label}}</strong>: {{/label}}{{/isEmpty}}
+       {{#values}}
+       {{#url}}<a href="{{url}}">{{value}}</a>{{/url}}
+       {{^url}}{{value}}{{/url}}
+       {{/values}}
+</div>
+{{/rows}}

-- 
To view, visit https://gerrit.wikimedia.org/r/169730
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I9c206b4c87b9aec0e8e59f484a24d26fd7570fdf
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/MobileFrontend
Gerrit-Branch: master
Gerrit-Owner: Jdlrobson <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to