Maryana has submitted this change and it was merged. Change subject: Creative MaxSem friendly destruction: Wikidata Infoboxes in alpha ......................................................................
Creative MaxSem friendly 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. This is rough around the edges and needs lots of design love abut I would say is alpha ready. Example urls: * http://localhost:8080/wiki/Albert_Einstein?wikidataid=Q937&mobileaction=alpha * http://localhost:8080/wiki/Barack_Obama?mobileaction=alpha&wikidataid=Q76 * http://localhost:8080/wiki/Noam%20Chomsky?wikidataid=Q9049&mobileaction=alpha Change-Id: I824d172e30d2b88ec7101e8dfa2ce9f6719c2ddf --- M includes/Resources.php A javascripts/modules/infobox/Infobox.js A javascripts/modules/infobox/init.js A less/modules/infobox.less A templates/modules/infobox/Infobox.hogan 5 files changed, 353 insertions(+), 3 deletions(-) Approvals: Maryana: Looks good to me, approved Bmansurov: Looks good to me, but someone else must approve diff --git a/includes/Resources.php b/includes/Resources.php index ef608ae..325201f 100644 --- a/includes/Resources.php +++ b/includes/Resources.php @@ -923,26 +923,52 @@ ), ), + 'mobile.wikigrok.api' => $wgMFResourceFileModuleBoilerplate + array( + 'dependencies' => array( + 'mobile.startup', + ), + 'scripts' => array( + 'javascripts/modules/wikigrok/WikiDataApi.js', + 'javascripts/modules/wikigrok/WikiGrokSuggestionApi.js', + 'javascripts/modules/wikigrok/WikiGrokResponseApi.js', + ), + ), + // See https://www.mediawiki.org/wiki/Extension:MobileFrontend/WikiGrok 'mobile.wikigrok.dialog' => $wgMFResourceFileModuleBoilerplate + array( 'dependencies' => array( 'mobile.overlays', 'mobile.alpha', + 'mobile.wikigrok.api', ), 'templates' => array( 'Dialog.hogan' => 'templates/modules/wikigrok/WikiGrokDialog.hogan', 'WikiGrokMoreInfo/content.hogan' => 'templates/modules/wikigrok/WikiGrokMoreInfo.hogan', ), 'scripts' => array( - 'javascripts/modules/wikigrok/WikiDataApi.js', - 'javascripts/modules/wikigrok/WikiGrokSuggestionApi.js', - 'javascripts/modules/wikigrok/WikiGrokResponseApi.js', 'javascripts/modules/wikigrok/WikiGrokDialog.js', 'javascripts/modules/wikigrok/WikiGrokMoreInfo.js', ), 'styles' => array( 'less/modules/wikigrok/WikiGrokDialog.less', ), + ), + + 'mobile.infobox' => $wgMFResourceFileModuleBoilerplate + array( + 'dependencies' => array( + 'mobile.wikigrok.api', + 'mobile.ajax', + ), + 'templates' => array( + 'Infobox.hogan' => 'templates/modules/infobox/Infobox.hogan', + ), + 'scripts' => array( + 'javascripts/modules/infobox/Infobox.js', + ), + 'styles' => array( + 'less/modules/infobox.less', + ), + 'position' => 'top', ), // Custom ResourceLoaderModule classes @@ -1226,6 +1252,10 @@ 'dependencies' => array( 'mobile.beta', // Feature modules that should be loaded in alpha should be listed below here. + 'mobile.infobox', + ), + 'scripts' => array( + 'javascripts/modules/infobox/init.js', ), ), 'tablet.scripts' => $wgMFResourceFileModuleBoilerplate + array( diff --git a/javascripts/modules/infobox/Infobox.js b/javascripts/modules/infobox/Infobox.js new file mode 100644 index 0000000..740da0b --- /dev/null +++ b/javascripts/modules/infobox/Infobox.js @@ -0,0 +1,273 @@ +( 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: mw.template.get( 'mobile.infobox', 'Infobox.hogan' ), + + className: 'wikidata-infobox', + defaults: { + spinner: mw.template.get( 'mobile.ajax', 'spinner.hogan' ).render(), + description: mw.config.get( 'wgMFDescription' ) || + 'A Wikipedia page in need of a description.', + rows: [] + }, + typeDefaults: { + // FIXME: In future this should be configurable by Wikipedia admins + human: { + rows: [ + { + id: 'P18' + }, + { + id: 'P569', + label: 'Born' + }, + { + id: 'P19', + label: 'Birthplace' + }, + { + id: 'P570', + label: 'Died' + }, + { + id: 'P20', + label: 'Place of death' + }, + { + id: 'P27', + label: 'Country of citizenship' + }, + // FIXME: Add political party + { + id: 'P26', + label: 'Spouse(s)' + }, { + id: 'P25', + label: 'Mother(s)' + }, { + id: 'P22', + label: 'Father(s)' + }, + //FIXME: Add Stepfather(s) (P43) and step mothers? + { + id: 'P9', + label: 'Sister(s)' + }, + { + id: 'P7', + label: 'Brother(s)' + }, + { + id: 'P40', + label: 'Child(ren)' + }, + // FIXME: add residence? + { + id: 'P69', + label: 'Alma mater' + }, + { + id: 'P106', + label: 'Occupation' + }, + { + id: 'P108', + label: 'Employer(s)' + }, + { + id: 'P140', + label: 'Religion' + }, + // FIXME: add 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 + * @method + * @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.snaktype === 'novalue' ) { + values.push( { + value: 'None' + } ); + } else 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' ) { + values.push( { + // FIXME: This should be more readable. Usually time is not important. + value: new Date( value.value.time.substr( 8 ) ) + } ); + } else if ( value.type === 'wikibase-entityid' ) { + values.push( { + id: 'Q' + value.value[ 'numeric-id' ], + isLink: true + } ); + } else if ( value.type === 'globecoordinate' ) { + values.push( { + value: value.value.latitude + ', ' + value.value.longitude + } ); + } else if ( value.type === 'quantity' ) { + // FIXME: Deal with qualifiers + values.push( { + value: value.value.amount + } ); + } else { + console.log( value.type + ' unknown', value ); + } + } ); + return values; + }, + /** + * Translates IDs in the current row value to human readable text + * + * @private + * @method + * @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 + * @method + * @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 ) { + this.api = new WikiDataApi( { + itemId: options.itemId + } ); + + View.prototype.initialize.apply( this, arguments ); + }, + /** + * @inheritdoc + */ + postRender: function( options ) { + var _loadRest = this._loadRest, + self = this; + + this.$( '.spinner' ).hide(); + this.$( '.more' ).on( 'click', function() { + $( this ).remove(); + _loadRest.call( self, options ); + } ); + }, + /** + * Decides based on the type of item what infobox to render + * + * @private + * @method + */ + _loadRest: function( options ) { + var self = this, + _super = View.prototype.render; + + this.$( '.spinner' ).show(); + 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 ); + } ); + } ).fail( function () { + // remove spinner + self.$el.remove(); + } ); + } + } ); + + 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..981fa4c --- /dev/null +++ b/javascripts/modules/infobox/init.js @@ -0,0 +1,16 @@ +( function ( M, $ ) { + M.assertMode( [ 'alpha' ] ); + var infobox, + wikidataID = mw.config.get( 'wgWikibaseItemId' ), + Infobox = M.require( 'modules/wikigrok/Infobox' ); + + if ( wikidataID ) { + // upset people + $( '.infobox' ).hide(); + // build the future + infobox = new Infobox( { + itemId: wikidataID + } ); + infobox.insertBefore( '#content' ); + } +}( mw.mobileFrontend, jQuery ) ); diff --git a/less/modules/infobox.less b/less/modules/infobox.less new file mode 100644 index 0000000..ec72b98 --- /dev/null +++ b/less/modules/infobox.less @@ -0,0 +1,17 @@ +@import "minerva.variables"; +@import "minerva.mixins"; + +.wikidata-infobox { + padding: 0 1em 2em; + margin: 0 0 1em; + border: solid 1px @grayLight; + border-top: none; + background-color: @grayLightest; +} + +@media all and (min-width: @wgMFDeviceWidthTablet) { + .wikidata-infobox { + max-width: 893px; + margin: 0 auto; + } +} diff --git a/templates/modules/infobox/Infobox.hogan b/templates/modules/infobox/Infobox.hogan new file mode 100644 index 0000000..0fd73cb --- /dev/null +++ b/templates/modules/infobox/Infobox.hogan @@ -0,0 +1,14 @@ +<em>{{description}}</em> +{{^rows}} +<button class="mw-ui-button mw-ui-quiet mw-ui-progressive more">expand…</button> +{{/rows}} +{{{spinner}}} +{{#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/172932 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I824d172e30d2b88ec7101e8dfa2ce9f6719c2ddf Gerrit-PatchSet: 2 Gerrit-Project: mediawiki/extensions/MobileFrontend Gerrit-Branch: master Gerrit-Owner: Jdlrobson <[email protected]> Gerrit-Reviewer: Awjrichards <[email protected]> Gerrit-Reviewer: Bmansurov <[email protected]> Gerrit-Reviewer: Maryana <[email protected]> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list [email protected] https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
