MediaWiki
Common.js
Note: After saving, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
- Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
// Replace Wikidata IDs with their [label, description]
$( '.wb-external-id' ).each( function() {
if ( $( this ).attr( 'href' ).lastIndexOf( 'https://www.wikidata.org', 0 ) === 0 ) {
var wikidataApi = new mw.ForeignApi( 'https://www.wikidata.org/w/api.php', {
anonymous: true,
parameters: { 'origin': '*' },
ajax: { timeout: 10000 }
} ),
lang = mw.config.get( 'wgUserLanguage' ),
node = $( this );
wikidataApi.get( {
'action': 'wbgetentities',
'format': 'json',
'ids': node.text(),
'props': 'labels|descriptions',
'languages': lang,
'languagefallback': 1,
'origin': '*'
} ).then( function( data ) {
var entity = data.entities[ node.text() ],
label = entity.labels[ lang ].value,
description = entity.descriptions[ lang ].value;
node.html( label + ' <i>(' + node.text() + ')</i><br><small>' + description + '</small>' )
} );
}
} );
// Fetch and display DataViz results
const sparqlEndpoint = "https://v2.lingualibre.fr/bigdata/namespace/wdq/sparql";
var DataViz = function( node ) {
this.node = node;
this.baseQuery = node.children( '.dataviz-query' ).text().replace(/\u00A0/g, ' ');
this.resultNode = node.children( '.dataviz-result' );
this.inputsNode = node.children( '.dataviz-inputs' );
// Add inputs
this.addInputs();
this.refresh();
};
DataViz.prototype.addInputs = function() {
var regex = /#extra:({.+?})? (.+)/g,
process = new OO.ui.Process(),
query = this.baseQuery,
m;
this.inputs = [];
this.labels = {};
this.filters = {};
while ( ( m = regex.exec( query ) ) !== null ) {
console.log( m );
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
var input = JSON.parse( m[ 1 ] );
input[ 'query' ] = m[ 2 ];
if ( input[ 'label' ] !== undefined ) {
this.labels[ input[ 'label' ] ] = input[ 'label' ];
}
if ( input[ 'filter' ] !== undefined ) {
this.filters[ input[ 'filter' ] ] = [];
}
var i = this.inputs.push( input );
this.baseQuery = this.baseQuery.replace( m[ 0 ], '#$' + i );
}
// Fetch labels
if ( Object.keys( this.labels ).length ) {
process.next( this.getLabels.bind( this ) );
}
// Preload values for limited inputs
for ( var item in this.filters ) {
process.next( this.loadFilterValues.bind( this, item ) );
}
// Once all data has been collected, we can create the fields
for ( var i=0; i < this.inputs.length; i++ ) {
process.next( this.createField.bind( this, this.inputs[ i ] ) );
}
var button = new OO.ui.ButtonWidget( {
label: 'Filtrer!',
flags: [ 'primary', 'progressive' ]
} );
button.on( 'click', this.refresh.bind( this ) );
this.inputsNode.append( button.$element );
process.execute();
};
DataViz.prototype.loadFilterValues = function( item ) {
var query = 'select ?id ?idLabel where {?id prop:P2 entity:' + item + '. SERVICE wikibase:label{bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en".}}';
return this.postQuery( query ).then( function( data ) {
var rows = data.results.bindings;
for ( var i=0; i < rows.length; i++ ) {
dataviz.filters[ item ].push( new OO.ui.MenuOptionWidget( {
data: rows[ i ][ 'id' ].value.split( '/' ).pop(),
label: rows[ i ][ 'idLabel' ].value
} ) );
}
} );
};
DataViz.prototype.getLabels = function( query ) {
var dataviz = this,
lang = mw.config.get( 'wgUserLanguage' ),
api = new mw.Api();
return api.get( {
action: 'wbgetentities',
format: 'json',
ids: Object.keys( this.labels ).join( '|' ),
props: 'labels',
languages: lang,
languagefallback: 1
} ).then( function( data ) {
for ( entity in data.entities ) {
dataviz.labels[ entity ] = data.entities[ entity ].labels[ lang ].value;
}
} );
};
DataViz.prototype.createField = function( infos ) {
var field;
switch( infos.type ) {
case 'wikibase-item':
field = new OO.ui.CapsuleMultiselectWidget( {
menu: { items: this.filters[ infos[ 'filter' ] ] }
} );
break;
default:
field = new OO.ui.TextInputWidget();
}
this.inputsNode.append( new OO.ui.FieldLayout( field, {
align: 'left',
label: this.labels[ infos[ 'label' ] ],
} ).$element );
infos[ 'field' ] = field;
};
DataViz.prototype.preProcessQuery = function() {
var query = this.baseQuery;
for ( var i=0; i < this.inputs.length; i++ ) {
if ( this.inputs[ i ].field !== undefined ) {
switch( this.inputs[ i ].type ) {
case 'wikibase-item':
var values = this.inputs[ i ].field.getItemsData();
for ( var j=0; j < values.length; j++ ) {
values[ j ] = '{' + this.inputs[ i ].query.replace( '[EXTRA]', values[ j ] ) + '}';
}
query = query.replace( '#$' + (i+1), values.join( ' UNION ' ) );
break;
default:
var value = this.inputs[ i ].field.getValue();
query = query.replace( '#$' + (i+1), this.inputs[ i ].query.replace( '[EXTRA]', value ) );
}
}
}
return query;
};
DataViz.prototype.postQuery = function( query ) {
query = query.replace(/\u00A0/g, ' ').replace( '[AUTO_LANGUAGE]', mw.config.get( 'wgUserLanguage' ) );
return $.post( sparqlEndpoint, { format: 'json', query: query } );
};
DataViz.prototype.refresh = function() {
var dataviz = this,
query = this.preProcessQuery();
this.postQuery( query ).then( function( data ) {
var table = dataviz.dataToTable( data.head.vars, data.results.bindings );
dataviz.resultNode.html( table );
} ).fail( function( data ) {
console.log( data.responseText );
//TODO: manage errors
} );
};
DataViz.prototype.dataToTable = function( headList, bodyList ) {
var order = [],
theadTr = $( '<tr>' ),
thead = $( '<thead>' ).append( theadTr ),
tbody = $( '<tbody>' ),
table = $( '<table>' )
.addClass( 'wikitable sortable' )
.append( thead ).append( tbody );
for ( var i = 0; i < headList.length; i++ ) {
theadTr.append( $( '<th>' ).text( headList[ i ] ) );
order.push( headList[ i ] );
}
for ( var i=0; i < bodyList.length; i++ ) {
var tr = $( '<tr>' ).appendTo( tbody );
for ( var j=0; j < order.length; j++ ) {
var cell = bodyList[ i ][ order[ j ] ];
if ( cell.type === 'uri' ) {
cell.value = $( '<a>' )
.attr( 'href', cell.value )
.text( cell.value.split( '/' ).pop() );
}
tr.append( $( '<td>' ).html( cell.value ) );
}
}
table.tablesorter();
return table;
}
mw.loader.using( [ 'jquery.tablesorter', 'oojs-ui' ], function() {
$( '.dataviz' ).each( function() {
window.dataviz = new DataViz( $( this ) );
} );
} );