MediaWiki

Difference between revisions of "Common.js"

(retrait du développement de l’UI de sélection des contribs)
(je remet la version de l’UI contributions (nous sommes en cours de démo avec WMFR, il y avait des lenteurs sur Blazegraph))
Tag: Undo
Line 170: Line 170:
 
$( 'div#P19 .wb-external-id' ).attr( 'href', $( 'div#P19 .wb-external-id' ).attr( 'href' ).replace( /\+/g, '_' ) );
 
$( 'div#P19 .wb-external-id' ).attr( 'href', $( 'div#P19 .wb-external-id' ).attr( 'href' ).replace( /\+/g, '_' ) );
 
}
 
}
 +
 +
// Development in final phase of the interface for displaying contributions
 +
$( function (){
 +
if( mw.config.get( 'wgPageName' ) !== 'User:Nicolas_NALLET' ) {
 +
return;
 +
}
 +
var userLanguage = mw.config.get( 'wgUserLanguage' );
 +
var messages = {
 +
'no-results': {
 +
en: 'No results.',
 +
de: 'Keine Ergebnisse.',
 +
fr: 'Pas de résultat.',
 +
}
 +
};
 +
mw.loader.using( ['oojs', 'oojs-ui'], function () {
 +
 +
var oouiSelectors = {
 +
'speaker': null,
 +
'gender': null,
 +
'language': null,
 +
'proficiency': null,
 +
};
 +
var sparqlGlobal = {
 +
'speaker': 'SELECT DISTINCT ?speaker ?speakerLabel WHERE { ?speaker prop:P2 entity:Q3 . ?speaker rdfs:label ?speakerLabel . FILTER( LANG(?speakerLabel) = "en" ) } ORDER BY ?speakerLabel',
 +
'gender': 'SELECT DISTINCT ?gender ?genderLabel WHERE { ?gender prop:P2 entity:Q7 . SERVICE wikibase:label { bd:serviceParam wikibase:language "' + userLanguage + ',fr,en" } } ORDER BY ?gender',
 +
'language': 'SELECT DISTINCT ?language ?languageLabel WHERE { ?language prop:P2 entity:Q4 . SERVICE wikibase:label { bd:serviceParam wikibase:language "' + userLanguage + ',fr,en" } } ORDER BY ?languageLabel',
 +
'proficiency': 'SELECT DISTINCT ?proficiency ?proficiencyLabel WHERE { ?proficiency prop:P2 entity:Q5 . SERVICE wikibase:label { bd:serviceParam wikibase:language "' + userLanguage + ',fr,en" } } ORDER BY ?proficiency',
 +
};
 +
var placeholders = {
 +
'speaker': '👤 Speaker',
 +
'gender': '♀️ ♂️ Speaker\'s gender',
 +
'language': '🏳️ Language',
 +
'proficiency': '🥇 Level of proficiency',
 +
};
 +
var htmlElements = {
 +
'speaker': '#filteruser',
 +
'gender': '#filtergender',
 +
'language': '#filterlanguage',
 +
'proficiency': '#filterlevelofproficiency',
 +
};
 +
var lastRequest = {
 +
'speaker': '',
 +
'gender': '',
 +
'language': '',
 +
'proficiency': '',
 +
};
 +
 +
function updateSelector( type ) {
 +
return function( values ) {
 +
if( ( oouiSelectors['speaker'] && oouiSelectors['speaker'].getValue() != lastRequest['speaker'] ) ||
 +
    ( oouiSelectors['gender'] && oouiSelectors['gender'].getValue() != lastRequest['gender'] ) ||
 +
    ( oouiSelectors['language'] && oouiSelectors['language'].getValue() != lastRequest['language'] ) ||
 +
    ( oouiSelectors['proficiency'] && oouiSelectors['proficiency'].getValue() != lastRequest['proficiency'] ) ) {
 +
return;
 +
}
 +
 +
oouiSelectors[type] = new OO.ui.ComboBoxInputWidget( {
 +
placeholder: placeholders[type],
 +
menu: {
 +
filterFromInput: true,
 +
items: values.results.bindings.map( function( x ) {
 +
return new OO.ui.MenuOptionWidget( {
 +
data: x[ type + 'Label' ].value + " (" + x[type].value.substr( 31 ) + ")",
 +
label: x[ type + 'Label' ].value
 +
} );
 +
} )
 +
}
 +
} );
 +
 +
$( htmlElements[type] ).html('').append(
 +
oouiSelectors[type].$element
 +
);
 +
 +
oouiSelectors[type].on( 'change', function() { doQuery(); doQuery( 'speaker' ); doQuery( 'gender' ); doQuery( 'language' ); doQuery( 'proficiency' ); } );
 +
 +
};
 +
}
 +
 +
$.getJSON(
 +
'https://lingualibre.org/bigdata/namespace/wdq/sparql',
 +
{
 +
query: sparqlGlobal['speaker']
 +
}
 +
).done( updateSelector( 'speaker' ) );
 +
 +
$.getJSON(
 +
'https://lingualibre.org/bigdata/namespace/wdq/sparql',
 +
{
 +
query: sparqlGlobal['gender']
 +
}
 +
).done( updateSelector( 'gender' ) );
 +
 +
$.getJSON(
 +
'https://lingualibre.org/bigdata/namespace/wdq/sparql',
 +
{
 +
query: sparqlGlobal['language']
 +
}
 +
).done( updateSelector( 'language' ) );
 +
 +
$.getJSON(
 +
'https://lingualibre.org/bigdata/namespace/wdq/sparql',
 +
{
 +
query: sparqlGlobal['proficiency']
 +
}
 +
).done( updateSelector( 'proficiency' ) );
 +
 +
// Display results
 +
function createAudioBoxesForSearch( data ) {
 +
if ( data.results === undefined || data.results.bindings === undefined ) {
 +
displayError( 'error: no result from SPARQL' );
 +
return;
 +
}
 +
if ( data.results.bindings.length < 1 ) {
 +
$( '#audioresults' ).html( messages['no-results'][userLanguage] ? messages['no-results'][userLanguage] : messages['no-results']['en'] );
 +
return;
 +
}
 +
var length = data.results.bindings.length < 100 ? data.results.bindings.length : 100;
 +
$( '#audioresults' ).html( '' );
 +
for (var i = 0; i < length; i++) {
 +
var box = $( '<div class="audiobox"> <div class="ab-playbutton"><i></i></div> <div> <div class="ab-title">...</div> <div class="ab-metadata">...</div> </div> </div>' );
 +
var audiobox = new AudioBox( data.results.bindings[ i ].record.value.substr( 31 ), box );
 +
$( '#audioresults' ).append( box );
 +
//ab1 = new AudioBox( data.query.rwrecords[ i ], $( '.audiobox' ).eq( i ) );
 +
//$("body").append('<div class="audiobox"> <div class="ab-playbutton"><i></i></div> <div> <div class="ab-title">...</div> <div class="ab-metadata">...</div> </div> </div>');
 +
}
 +
}
 +
 +
// Do SPARQL request from filters
 +
function doQuery( variable ){
 +
 +
// Do not modify a selector where there is a value
 +
if( variable && oouiSelectors[variable] && oouiSelectors[variable].getValue() ) {
 +
return;
 +
}
 +
 +
function getQ( type ) {
 +
if( variable === type ) {
 +
return '?' + type;
 +
}
 +
var text = oouiSelectors[type] ? oouiSelectors[type].getValue() : '';
 +
if( !text ) {
 +
return '';
 +
}
 +
text = text.trim();
 +
if( /^Q[0-9]+$/.test( text ) ) {
 +
return 'entity:' + text;
 +
} else if( /\((Q[0-9]+)\)$/.test( text ) ) {
 +
return 'entity:' + text.replace( /.*\((Q[0-9]+)\)$/, '$1' );
 +
} else {
 +
console.warn( 'Bad input “' + text + '”' );
 +
return '';
 +
}
 +
}
 +
 +
var speaker = getQ( 'speaker' ),
 +
    gender = getQ( 'gender' ),
 +
    language = getQ( 'language' ),
 +
    proficiency = getQ( 'proficiency' ),
 +
    somevalue = false;
 +
if( ! variable ) {
 +
lastRequest = {
 +
'speaker': oouiSelectors['speaker'] ? oouiSelectors['speaker'].getValue() : '',
 +
'gender': oouiSelectors['gender'] ? oouiSelectors['gender'].getValue() : '',
 +
'language': oouiSelectors['language'] ? oouiSelectors['language'].getValue() : '',
 +
'proficiency': oouiSelectors['proficiency'] ? oouiSelectors['proficiency'].getValue() : '',
 +
};
 +
}
 +
 +
var query = "SELECT " + ( variable ? 'DISTINCT ?' + variable + ' ?' + variable + 'Label' : "?record" ) + " WHERE { ?record prop:P2 entity:Q2 ; prop:P4 ?language ; prop:P5 ?speaker . ";
 +
if( speaker ) {
 +
query += "?record prop:P5 " + speaker + " . ";
 +
somevalue = true;
 +
}
 +
if( gender ) {
 +
query += "?record prop:P5 [ prop:P8 " + gender + " ] . ";
 +
somevalue = true;
 +
}
 +
if( language ) {
 +
query += "?record prop:P4 " + language + " . ";
 +
somevalue = true;
 +
}
 +
if( proficiency ) {
 +
query += "?speaker llp:P4 [ llv:P4 ?language ; llq:P16 " + proficiency + " ] . ";
 +
somevalue = true;
 +
}
 +
query += "SERVICE wikibase:label { bd:serviceParam wikibase:language '" + userLanguage + ",en,fr' } } LIMIT 100";
 +
 +
if( variable ) {
 +
if( !somevalue ) {
 +
query = sparqlGlobal[variable];
 +
}
 +
} else {
 +
if( !variable && !somevalue ) {
 +
return;
 +
}
 +
$( '#audioresults' ).html( '' ); // TODO replace by a spinner
 +
}
 +
 +
// Execute the request
 +
var result = $.getJSON(
 +
'https://lingualibre.org/bigdata/namespace/wdq/sparql',
 +
{
 +
query: query,
 +
//Accept: 'application/sparql-results+json'
 +
}
 +
);
 +
 +
// Depending if we want the whole results or update on selector
 +
if( variable ) {
 +
result.then( updateSelector( variable ), displayError );
 +
} else {
 +
result.then( createAudioBoxesForSearch, displayError );
 +
}
 +
}
 +
 +
} );
 +
 +
} );

Revision as of 10:00, 26 August 2021

// Replace Wikidata IDs with their [label, description]
if ( $( '.wb-external-id' ).length > 0 ) {
	mw.loader.using( 'mediawiki.ForeignApi', function() {
		$( '.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 ] !== undefined ? entity.labels[ lang ].value + ' <i>(' + node.text() + ')</i>' : node.text() ),
						description = ( entity.descriptions[ lang ] !== undefined ? '<small>' + entity.descriptions[ lang ].value + '</small>' : '' );
					
					node.html( label + '<br>' + description )
				} );
			}
		} );
	} );
}

//Add an audio player to the audio records links in the wikibase items
const BASE_FILE_URL = 'https://commons.wikimedia.org/wiki/Special:Redirect/file?wptype=file&wpvalue=';

function playButton( audioUrl ) {
	var button = new OO.ui.ButtonWidget( {
		framed: false,
		icon: 'play',
		title: 'play'
	} );
	button.on( 'click', function() {
		var audio = new Audio( audioUrl );
		audio.play();
	} );

	return button.$element;
}

if ( $( '#P3 a.extiw' ).length > 0 ) {
    mw.loader.using( [ 'oojs-ui-widgets', 'oojs-ui.styles.icons-media' ], function() {
        $( '#P3 a.extiw' ).each( function() {
            var $node = $( this );
            $node.before( playButton( BASE_FILE_URL + $node.text() ) );
        } );
    } );
}


/**
 * Display last records on main page
 **/
var ab1, ab2;


var AudioBox = function( recordQid, $node ) {
	this.wbRecord = new mw.recordWizard.wikibase.Item( recordQid );
	
	this.$node = $node;
	this.audioNode = document.createElement( 'audio' );
	this.audioNode.preload = 'auto';

    this.api = new mw.Api();	

	this.recordQid = recordQid;
	this.langQid = null;
	this.speakerQid = null;
	
	this.label = '';
	this.media = '';
	this.lang = '';
	this.speaker = '';
	
	this.wbRecord.getFromApi( this.api ).then( this.processRecord.bind( this ), displayError );
}

AudioBox.prototype.processRecord = function() {
	this.label = this.wbRecord.getLabel( 'en' );
	this.media = 'https://commons.wikimedia.org/wiki/Special:FilePath/' + this.wbRecord.getStatements( 'P3' )[ 0 ].getValue();
	this.langQid = this.wbRecord.getStatements( 'P4' )[ 0 ].getValue();
	this.speakerQid = this.wbRecord.getStatements( 'P5' )[ 0 ].getValue();

	this.api.get( {
		action: "wbgetentities",
		format: "json",
		ids: this.langQid + '|' + this.speakerQid,
		props: "labels",
		languages: mw.config.get( 'wgUserLanguage' ) + "|en",
		languagefallback: 1,
	} ).then( this.processLabels.bind( this ), displayError );
}

AudioBox.prototype.processLabels = function( data ) {
	var langLabels;

	if ( data.entities === undefined || data.entities[ this.langQid ] === undefined || data.entities[ this.speakerQid ] === undefined ) {
		displayError( 'dataerror' );
		return;
	}
	langLabels = data.entities[ this.langQid ].labels;
	
	if ( langLabels[ mw.config.get( 'wgUserLanguage' ) ] !== undefined ) {
		this.lang = langLabels[ mw.config.get( 'wgUserLanguage' ) ].value;
	} else {
		this.lang = langLabels[ 'en' ].value;
	}
	
	this.speaker = data.entities[ this.speakerQid ].labels[ 'en' ].value;

	this.display();
}

AudioBox.prototype.display = function() {
	this.$node.find( '.ab-title' ).text( this.label );
	this.$node.find( '.ab-metadata' ).text( this.lang + ' - ' + this.speaker );
	
	this.audioNode.src = this.media;
	this.$node.find( '.ab-playbutton' ).click( this.audioNode.play.bind( this.audioNode ) );
}






function createAudioBoxes( data ) {
	if ( data.query === undefined || data.query.rwrecords === undefined || data.query.rwrecords.length < 2 ) {
		displayError( 'nodata' );
		return;
	}

	ab1 = new AudioBox( data.query.rwrecords[ 0 ], $( '.audiobox' ).eq( 0 ) );
	ab2 = new AudioBox( data.query.rwrecords[ 1 ], $( '.audiobox' ).eq( 1 ) );
}

function getLastRecords() {
    var api = new mw.Api();
	api.get( {
        action: 'query',
        format: 'json',
        list: 'rwrecords',
        rwrlimit: '2',
		rwrsort: 'pageid',
		rwrdir: 'descending',
		rwrformat: 'qid'
  } ).then( createAudioBoxes, displayError );
}

function displayError( code, error ) {
	console.warn( code, error );
}

if ( mw.config.get( 'wgPageName' ) === 'LinguaLibre:Main_Page' ) {
    mw.loader.using( [ 'mediawiki.api', 'ext.recordWizard.wikibase' ] ).then( getLastRecords );
}

// T206801 - Links to Wikipedia contain "+" (instead of "_")
if ( $( 'div#P19 .wb-external-id' ).length ) {
	$( 'div#P19 .wb-external-id' ).attr( 'href', $( 'div#P19 .wb-external-id' ).attr( 'href' ).replace( /\+/g, '_' ) );
}

// Development in final phase of the interface for displaying contributions
$( function (){
	if( mw.config.get( 'wgPageName' ) !== 'User:Nicolas_NALLET' ) {
		return;
	}
	var userLanguage = mw.config.get( 'wgUserLanguage' );
	var messages = {
		'no-results': {
			en: 'No results.',
			de: 'Keine Ergebnisse.',
			fr: 'Pas de résultat.',
		}
	};
	mw.loader.using( ['oojs', 'oojs-ui'], function () {

		var oouiSelectors = {
			'speaker': null,
			'gender': null,
			'language': null,
			'proficiency': null,
		};
		var sparqlGlobal = {
			'speaker': 'SELECT DISTINCT ?speaker ?speakerLabel WHERE { ?speaker prop:P2 entity:Q3 . ?speaker rdfs:label ?speakerLabel . FILTER( LANG(?speakerLabel) = "en" ) } ORDER BY ?speakerLabel',
			'gender': 'SELECT DISTINCT ?gender ?genderLabel WHERE { ?gender prop:P2 entity:Q7 . SERVICE wikibase:label { bd:serviceParam wikibase:language "' + userLanguage + ',fr,en" } } ORDER BY ?gender',
			'language': 'SELECT DISTINCT ?language ?languageLabel WHERE { ?language prop:P2 entity:Q4 . SERVICE wikibase:label { bd:serviceParam wikibase:language "' + userLanguage + ',fr,en" } } ORDER BY ?languageLabel',
			'proficiency': 'SELECT DISTINCT ?proficiency ?proficiencyLabel WHERE { ?proficiency prop:P2 entity:Q5 . SERVICE wikibase:label { bd:serviceParam wikibase:language "' + userLanguage + ',fr,en" } } ORDER BY ?proficiency',
		};
		var placeholders = {
			'speaker': '👤 Speaker',
			'gender': '♀️ ♂️ Speaker\'s gender',
			'language': '🏳️ Language',
			'proficiency': '🥇 Level of proficiency',
		};
		var htmlElements = {
			'speaker': '#filteruser',
			'gender': '#filtergender',
			'language': '#filterlanguage',
			'proficiency': '#filterlevelofproficiency',
		};
		var lastRequest = {
			'speaker': '',
			'gender': '',
			'language': '',
			'proficiency': '',
		};

		function updateSelector( type ) {
			return function( values ) {
				if( ( oouiSelectors['speaker'] && oouiSelectors['speaker'].getValue() != lastRequest['speaker'] ) ||
				    ( oouiSelectors['gender'] && oouiSelectors['gender'].getValue() != lastRequest['gender'] ) ||
				    ( oouiSelectors['language'] && oouiSelectors['language'].getValue() != lastRequest['language'] ) ||
				    ( oouiSelectors['proficiency'] && oouiSelectors['proficiency'].getValue() != lastRequest['proficiency'] ) ) {
					return;
				}

				oouiSelectors[type] = new OO.ui.ComboBoxInputWidget( {
					placeholder: placeholders[type],
					menu: {
						filterFromInput: true,				
						items: values.results.bindings.map( function( x ) {
							return new OO.ui.MenuOptionWidget( {
								data: x[ type + 'Label' ].value + " (" + x[type].value.substr( 31 ) + ")",
								label: x[ type + 'Label' ].value
							} );
						} )
					}
				} );

				$( htmlElements[type] ).html('').append(
					oouiSelectors[type].$element
				);

				oouiSelectors[type].on( 'change', function() { doQuery(); doQuery( 'speaker' ); doQuery( 'gender' ); doQuery( 'language' ); doQuery( 'proficiency' ); } );

			};
		}

		$.getJSON(
			'https://lingualibre.org/bigdata/namespace/wdq/sparql',
			{
				query: sparqlGlobal['speaker']
			}
		).done( updateSelector( 'speaker' ) );

		$.getJSON(
			'https://lingualibre.org/bigdata/namespace/wdq/sparql',
			{
				query: sparqlGlobal['gender']
			}
		).done( updateSelector( 'gender' ) );

		$.getJSON(
			'https://lingualibre.org/bigdata/namespace/wdq/sparql',
			{
				query: sparqlGlobal['language']
			}
		).done( updateSelector( 'language' ) );

		$.getJSON(
			'https://lingualibre.org/bigdata/namespace/wdq/sparql',
			{
				query: sparqlGlobal['proficiency']
			}
		).done( updateSelector( 'proficiency' ) );

		// Display results
		function createAudioBoxesForSearch( data ) {
			if ( data.results === undefined || data.results.bindings === undefined ) {
				displayError( 'error: no result from SPARQL' );
				return;
			}
			if ( data.results.bindings.length < 1 ) {
				$( '#audioresults' ).html( messages['no-results'][userLanguage] ? messages['no-results'][userLanguage] : messages['no-results']['en'] );
				return;
			}
			var length = data.results.bindings.length < 100 ? data.results.bindings.length : 100;
			$( '#audioresults' ).html( '' );
			for (var i = 0; i < length; i++) {
				var box = $( '<div class="audiobox"> <div class="ab-playbutton"><i></i></div> <div> <div class="ab-title">...</div> <div class="ab-metadata">...</div> </div> </div>' );
				var audiobox = new AudioBox( data.results.bindings[ i ].record.value.substr( 31 ), box );
				$( '#audioresults' ).append( box );
				//ab1 = new AudioBox( data.query.rwrecords[ i ], $( '.audiobox' ).eq( i ) );
				//$("body").append('<div class="audiobox"> <div class="ab-playbutton"><i></i></div> <div> <div class="ab-title">...</div> <div class="ab-metadata">...</div> </div> </div>');	
			}
		}

		// Do SPARQL request from filters
		function doQuery( variable ){

			// Do not modify a selector where there is a value
			if( variable && oouiSelectors[variable] && oouiSelectors[variable].getValue() ) {
				return;
			}

			function getQ( type ) {
				if( variable === type ) {
					return '?' + type;
				}
				var text = oouiSelectors[type] ? oouiSelectors[type].getValue() : '';
				if( !text ) {
					return '';
				}
				text = text.trim();
				if( /^Q[0-9]+$/.test( text ) ) {
					return 'entity:' + text;
				} else if( /\((Q[0-9]+)\)$/.test( text ) ) {
					return 'entity:' + text.replace( /.*\((Q[0-9]+)\)$/, '$1' );
				} else {
					console.warn( 'Bad input “' + text + '”' );
					return '';
				}
			}

			var speaker = getQ( 'speaker' ),
			    gender = getQ( 'gender' ),
			    language = getQ( 'language' ),
			    proficiency = getQ( 'proficiency' ),
			    somevalue = false;
			if( ! variable ) {
				lastRequest = {
					'speaker': oouiSelectors['speaker'] ? oouiSelectors['speaker'].getValue() : '',
					'gender': oouiSelectors['gender'] ? oouiSelectors['gender'].getValue() : '',
					'language': oouiSelectors['language'] ? oouiSelectors['language'].getValue() : '',
					'proficiency': oouiSelectors['proficiency'] ? oouiSelectors['proficiency'].getValue() : '',
				};
			}

			var query = "SELECT " + ( variable ? 'DISTINCT ?' + variable + ' ?' + variable + 'Label' : "?record" ) + " WHERE { ?record prop:P2 entity:Q2 ; prop:P4 ?language ; prop:P5 ?speaker . ";
			if( speaker ) {
				query += "?record prop:P5 " + speaker + " . ";
				somevalue = true;
			}
			if( gender ) {
				query += "?record prop:P5 [ prop:P8 " + gender + " ] . ";
				somevalue = true;
			}
			if( language ) {
				query += "?record prop:P4 " + language + " . ";
				somevalue = true;
			}
			if( proficiency ) {
				query += "?speaker llp:P4 [ llv:P4 ?language ; llq:P16 " + proficiency + " ] . ";
				somevalue = true;
			}
			query += "SERVICE wikibase:label { bd:serviceParam wikibase:language '" + userLanguage + ",en,fr' } } LIMIT 100";

			if( variable ) {
				if( !somevalue ) {
					query = sparqlGlobal[variable];
				}
			} else {
				if( !variable && !somevalue ) {
					return;
				}
				$( '#audioresults' ).html( '' ); // TODO replace by a spinner
			}

			// Execute the request
			var result = $.getJSON(
				'https://lingualibre.org/bigdata/namespace/wdq/sparql',
				{
					query: query,
					//Accept: 'application/sparql-results+json'
				}
			);

			// Depending if we want the whole results or update on selector
			if( variable ) {
				result.then( updateSelector( variable ), displayError );
			} else {
				result.then( createAudioBoxesForSearch, displayError );
			}
		}

	} );

} );