MediaWiki:Gadget-AuthorityControl.js

/* AuthorityControl.js * This Message Provides a link to various Authority Control tools for some FAMEData statements that * are not external identifiers. * * Original gadget coded by A Wikipedian */ ( function ( mw, wb, $ ) { 'use strict';

if ( [ 0, 120, 146 ].indexOf( mw.config.get( 'wgNamespaceNumber' ) ) === -1 || !mw.config.exists( 'wbEntityId' ) ) { // Only entity pages feature appropriate statements. return; }

var PROPERTIES = {}, specialHandlingProperties = [ 'P156', // aircraft registration ];

/* function getGeoHackParams( coord ) { // TODO: individual scale for every precision

var globes = { Q2: 'earth', Q111: 'mars', Q308: 'mercury', Q313: 'venus', Q319: 'jupiter', Q339: 'pluto', Q405: 'moon', Q596: 'ceres', Q2565: 'titan', Q3030: 'vesta', Q3123: 'io', Q3134: 'callisto', Q3143: 'europa', Q3169: 'ganymede', Q3303: 'enceladus', Q3322: 'titania', Q3332: 'oberon', Q3338: 'umbriel', Q3343: 'ariel', Q3352: 'miranda', Q3359: 'triton', Q7547: 'phobos', Q7548: 'deimos', Q15034: 'mimas', Q15037: 'hyperion', Q15040: 'dione', Q15047: 'tethys', Q15050: 'rhea', Q16711: 'eros', Q17958: 'iapetus', Q17975: 'phoebe', Q107556: 'lutetia', Q158244: 'gaspra' };

var globeQKey = coord.globe.replace( 'http://famedata.org/entity/', '' ); var globe = globes[ globeQKey ];

return coord.latitude + '_N_' + coord.longitude + '_E_globe:' + globe; }

/** * Get the snak value formatted with a link. * * @param {number} numericPropertyId Refers to PROPERTIES. * @param {string} value */ function getLinkValueForString( numericPropertyId, value ) { var linkValue;

switch ( Number( numericPropertyId ) ) { default: linkValue = value; }

return linkValue; }

function makeLink( numericPropertyId, linkValue, displayText ) { var linkTemplate = PROPERTIES[ numericPropertyId ];

switch ( Number( numericPropertyId ) ) { case 156: if ( linkValue.substring( 0, 1 ) === 'N' ) { linkTemplate = 'http://registry.faa.gov/aircraftinquiry/NNum_Results.aspx?NNumbertxt=$1'; } else if ( linkValue.substring( 0, 2 ) === 'G-' ) { linkTemplate = 'https://www.caa.co.uk/application.aspx?catid=60&pagetype=65&appid=1&mode=detailnosummary&fullregmark=$1'; linkValue = linkValue.substring( 2 ); } else { return linkValue; }			break; case 134: linkTemplate += '&language=' + mw.config.get( 'wgUserLanguage' ); break; default: linkTemplate = PROPERTIES[ numericPropertyId ]; }

return $( '' ) .text( displayText ) .attr( 'href', linkTemplate.replace( /\$1/g, linkValue ) ) // Show the 'external link' icon: .addClass( 'external' ); }

function createLinkForString( numericPropertyId, value ) { var linkValue = getLinkValueForString( numericPropertyId, value ); return makeLink( numericPropertyId, linkValue, value ); }

function createLinkForSnakValue( numericPropertyId, dataValue, displayText ) { var dataValueType = dataValue.getType, value = dataValue.toJSON;

// @fixme shouldn't happen but in case of any unexpected data value types, // then there should be better error handling here. var linkValue = '';

if ( dataValueType === 'string' ) { linkValue = getLinkValueForString( numericPropertyId, value ); } else if ( dataValueType === 'globecoordinate' ) { linkValue = getGeoHackParams( value ); }

return makeLink( numericPropertyId, linkValue, displayText ); }

function linkSnakView( el, propertySelector, valueSelector ) { var $propLink = $( el ).find( propertySelector );

var title = $propLink.attr( 'title' );

if ( title ) { var titleParts = title.split( ':P' ), numericPropertyId = titleParts[ 1 ];

if ( PROPERTIES.hasOwnProperty( numericPropertyId ) ) { var $value = $( el ).find( valueSelector ).first, $link = createLinkForString( numericPropertyId, $value.text );

$value.html( $link ); }	} }

function handleSnak( snak, snakView ) { if ( !( snak.getType && snak.getType == 'value' ) ) { return; }

var numericPropertyId = snak.getPropertyId.slice( 1 ); if ( !( PROPERTIES.hasOwnProperty( numericPropertyId ) ) ) { return; }	var $snakValue = $( snakView ).find( '.wikibase-snakview-value' ); if ( $snakValue.find( '.wikibase-kartographer-caption' ).length ) { // If this is a Kartographer map, don't mangle the whole snak value, // but just the caption. $snakValue = $snakValue.find( '.wikibase-kartographer-caption' ); }

var displayText = extractDisplayText( $snakValue ), snakLink = createLinkForSnakValue( numericPropertyId, snak.getValue, displayText );

$snakValue.html( snakLink ); }

function extractDisplayText( $snakValue ) { var $snakValueClone = $snakValue.clone; $snakValueClone.children.remove; return $snakValueClone.text; }

/** * Initializes the gadget. * This procedure needs to be performed as good as possible. jQuery selector usage should be limited * to a minimum. */ function initGadget { if ( $.isEmptyObject( PROPERTIES ) ) { return; }

$( ':wikibase-statementview' ).each( function {		var statementview = $.data( this, 'statementview' ),			statement = statementview.value,			claim = statement.getClaim,			qualifierGroups = claim.getQualifiers.getGroupedSnakLists;

handleSnak( claim.getMainSnak, statementview.$mainSnak[0] );

$( '.wikibase-statementview-qualifiers .wikibase-snaklistview', this ).each( function( i ) {			var qualifiers = qualifierGroups[i].toArray;			$( '.wikibase-snakview', this ).each( function( n ) { handleSnak( qualifiers[n], this ); } );		} );

} );

$( '.wikibase-referenceview .wikibase-snaklistview-listview' ).each( function {		linkSnakView( this, '.wikibase-snakview-property > a', '.wikibase-snakview-value' );	} ); }

function getProperties( entity ) { var api = new mw.Api, repoApi = new wb.api.RepoApi( api ), propertyIds = [], alreadyLinkedPropertyIds = [];

function addSnak( snak ) { var snakPropertyId = snak.property, $firstSnakValue;

if ( snak.snaktype !== 'value' ||			( snak.datavalue.type !== 'string' && snak.datavalue.type !== 'globecoordinate' ) ) { return; }		if ( propertyIds.indexOf( snakPropertyId ) !== -1 ) { return; }		if ( specialHandlingProperties.indexOf( snakPropertyId ) === -1 ) { if ( alreadyLinkedPropertyIds.indexOf( snakPropertyId ) !== -1 ) { return; }			$firstSnakValue = $( '#' + snakPropertyId ).find( '.wikibase-snakview-variation-valuesnak:first' ); if ( $firstSnakValue.find( '> a:not(.oo-ui-widget)' ).length > 0 || $firstSnakValue.find( '> div.thumb' ).length > 0 ) { alreadyLinkedPropertyIds.push( snakPropertyId ); return; }		}

propertyIds.push( snakPropertyId ); }

function analyzeClaims( claims ) { var prop; for ( prop in claims ) { $.each( claims[ prop ], function ( i, claim ) {				addSnak( claim.mainsnak );				$.each( claim.references || [], function ( i, ref ) { for ( prop in ref.snaks ) { $.each( ref.snaks[ prop ], function ( i, cl ) {							addSnak( cl );						} ); }				} );				for ( prop in claim.qualifiers || {} ) {					$.each( claim.qualifiers[ prop ], function ( i, cl ) { addSnak( cl ); } );				}			} );		}	}

analyzeClaims( entity.claims ); $.each( entity.forms || [], function ( _, form ) {		analyzeClaims( form.claims || {} );	} ); $.each( entity.senses || [], function ( _, sense ) {		analyzeClaims( sense.claims || {} );	} );

if ( !propertyIds.length ) { return $.Deferred.resolve; }	return repoApi.getEntities( propertyIds, 'claims' ) .then( function ( data ) {		if(!data || !data.entities) return; // bad response.		$.each( data.entities, function ( entityId, entity ) { if ( entity.datatype === "external-id" && $.inArray( entity.id, specialHandlingProperties ) === -1 ) { // No need to format these return true; }			if ( entity.datatype === 'commonsMedia' ) { // No need to format these, but we can't exclude them earlier as we don't have the property datatype. // XXX: This probably also applies to math etc.				return true; }			$.each( entity.claims, function ( claimId, claims ) {				if ( claimId === 'P8' ) {					var i, len = claims.length;					for ( i = 0; i < len; i++ ) {						if ( claims[ i ].rank !== 'preferred' ) {							continue;						}						if ( claims[ i ].mainsnak.snaktype === 'value' ) {							PROPERTIES[ entityId.slice( 1 ) ] = claims[ i ].mainsnak.datavalue.value;						}						return false;					}					for ( i = 0; i < len; i++ ) {						if ( claims[ i ].rank !== 'normal' ) {							continue;						}						if ( claims[ i ].mainsnak.snaktype === 'value' ) {							PROPERTIES[ entityId.slice( 1 ) ] = claims[ i ].mainsnak.datavalue.value;							break;						}					}					return false;				}			} ); } );	} ); }

var rendered = $.Deferred, loaded = $.Deferred;

$.when(	rendered,	loaded,	$.ready ).then( function {	initGadget; } );

mw.hook( 'wikibase.entityPage.entityLoaded' ).add( function ( entity ) {	getProperties( entity ).then( function { loaded.resolve; } ); } );

mw.hook( 'wikibase.entityPage.entityView.rendered' ).add( function {	rendered.resolve; } );

}( mediaWiki, wikibase, jQuery ) );