User:Fomafix/MediaWiki:Gadget-AuthorityControl.js

From Wikidata
Jump to navigation Jump to search

Note: After publishing, 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: Press Ctrl-F5.
/* AuthorityControl.js
 * Provides a link to various Authority Control tools (VIAF, GND, etc.) for Wikidata statements that
 * feature certain properties.
 *
 * Original gadget coded by [[User:Ricordisamoa]]
 */
( function ( mw, $ ) {

if ( mw.config.get( 'wgNamespaceNumber' ) !== 0 || !mw.config.exists( 'wbEntityId' ) ) {
	// Only item pages feature appropriate statements.
	return;
}

var PROPERTIES = {};

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

	var globes = {
		'Q2': 'earth',
		'Q111': 'mars',
		'Q308': 'mercury',
		'Q313': 'venus',
		'Q405': 'moon',
		'Q15034': 'mimas'
	};

	/* BUG: .getGlobe() returns Q2 always */
	var globeQKey = coord.getGlobe().replace( 'http://www.wikidata.org/entity/', '' );
	var globe = globes[globeQKey];

	return coord.getLatitude() + '_N_' + coord.getLongitude() + '_E_globe:' + globe;
}

/**
 * Creates a link that is placed after a snak's input textarea.
 *
 * @param {number} numericPropertyId Refers to PROPERTIES.
 * @param {object} snakValue The original value that shall be used in the link.
 * @param {jQuery} $parent The node whose descendants shall be searched for the snak value
 *                 textarea.
 * @param {jQuery} $toolbarParent The node the "edit" toolbar corresponding to the value that shall
 *                 be linked is initialized on.
 */
function createLink( numericPropertyId, snakValue, $parent, $toolbarParent ) {
	// @todo this could be it's own function
	var linkValue;
	if ( snakValue.getType() === 'string' ) {
		switch ( Number( numericPropertyId ) ) {
		case 213: // ISNI
			linkValue = snakValue.getValue().replace( / /g, '' );
			break;
		case 502: // HURDAT
			linkValue = snakValue.getValue().substring( 4, 8 ); // year
			if ( Number( linkValue ) <= 2005 ) {
				linkValue += '/'; // Brings a list for that year
				// For direct link, would need to append <name of hurricane>.[s]htlm 
				// ex: http://www.nhc.noaa.gov/archive/2004/ALEX.shtml or 2001/ALLISON.html
			} else { // after 2005
				linkValue += '/' + snakValue.getValue().substring( 0, 4 ).toLowerCase() + '/';
			}
			break;
		case 628: // E Number
			linkValue = snakValue.getValue().substring( 1, 16 ); // Skip initial letter
			break;
		case 882: // FIPS
			linkValue = snakValue.getValue();
			linkValue = linkValue.substr( 0, 2 ) + '/' + linkValue;
			break;
		default:
			linkValue = snakValue.getValue();
		}
	}
	else if ( snakValue.getType() === 'globecoordinate' ) {
		linkValue = getGeoHackParams( snakValue.getValue() );
	}
	
	var $displayElement = $parent.find( '.wb-snak-value .valueview' );
	var displayText = $displayElement.text();

	var $btnEdit = $toolbarParent.find( '.wikibase-toolbar-button-edit' );
	var linkTemplate = PROPERTIES[numericPropertyId];

	var $link = $( '<a>' )
		.text( displayText )
		.attr( 'href', linkTemplate.replace( '$1', linkValue ) )
		// Show the 'external link' icon:
		.addClass( 'external' );

	$displayElement.hide().after( $link );

	// Using ".one" since, currently, link and textarea visibility are not toggled after leaving
	// edit mode anyhow:
	$btnEdit.one( 'click', function () {
		$link.hide();
		$displayElement.show();
	} );
}

/**
 * Creates a link for the snakview featuring a specific snak.
 * Since the order of the snaks within a SnakList does not necessarily have to be the same than the
 * displayed/grouped snakviews, all snakviews need to be looped over to find out the snakview that
 * features a specific snak.
 *
 * @param {wikibase.Snak} snakToLink
 * @param {jQuery} $parent The node whose descendants will be searched for snaklistviews
 * @param {jQuery} [$toolbarParent] The node the "edit" toolbar corresponding to the value that
 *                 shall be linked is initialized on.
 */
function linkSnakview( snakToLink, $parent, $toolbarParent ) {
	$toolbarParent = $toolbarParent || $parent;

	$parent.find( '.wb-snakview' ).each( function () {
		var snak = $.data( this, 'wikibaseSnakview' ).snak();

		if ( snak.equals( snakToLink ) ) {
			createLink( snak.getPropertyId().slice( 1 ), snak.getValue(), $( this ), $toolbarParent );
			return false;
		}
	} );
}

/**
 * Initializes the gadget.
 * This procedure needs to be performed as good as possible. jQuery selector usage should be limited
 * to a minimum.
 */
function initGadget() {
	$( ':wikibase-statementview' ).each( function () {
		var $statementview = $( this ),
			statementview = $.data( this, 'statementview' ),
			statement = statementview.value(),
			mainSnak = statement.getClaim().getMainSnak(),
			numericPropertyId = mainSnak.getPropertyId().slice( 1 ),
			qualifiers = statement.getClaim().getQualifiers(),
			references = statementview.getReferences(),
			// Do not look for referenceview DOM nodes before they are actually needed:
			$referenceviews = null;

		if ( PROPERTIES[numericPropertyId] ) {
			createLink(
				numericPropertyId,
				mainSnak.getValue(),
				statementview.$mainSnak || statementview.$claimview.data( 'claimview' ).$mainSnak,
				$statementview
			);
		}

		qualifiers.each( function ( i, snak ) {
			if ( PROPERTIES[snak.getPropertyId().slice( 1 )] ) {
				linkSnakview( snak, statementview.$qualifiers, $statementview );
			}
		} );

		for ( var i in references ) {
			references[i].getSnaks().each( function ( j, snak ) {
				if ( PROPERTIES[snak.getPropertyId().slice( 1 )] ) {
					if ( !$referenceviews ) {
						$referenceviews = $statementview.find( ':wikibase-referenceview' );
					}
					linkSnakview( snak, $referenceviews.eq( i ) );
				}
			} );
		}
	} );
}

function getProperties() {
	var api = new mw.Api(),
		repoApi = new wb.api.RepoApi( api ),
		claim,
		claims = [],
		entity = JSON.parse( mw.config.get( 'wbEntity' ) );
	for ( claim in entity.claims ) {
		claims.push( claim );
	}
	if ( !claims.length ) {
		return $.Deferred().resolve();
	}
	return repoApi.getEntities( claims, 'claims' )
	.done( function ( data ) {
		$.each( data.entities, function ( entityId, entity ) {
			if ( entity.claims ) {
				$.each( entity.claims, function ( claimId, claim ) {
					if ( claimId === 'P1630' ) {
						PROPERTIES[entityId.slice( 1 )] = claim[0].mainsnak.datavalue.value;
					}
				} );
			}
		} );
	} );
}

getProperties().done( function () {
	if ( $.isEmptyObject( PROPERTIES ) ) {
		return;
	}
	mw.loader.using( 'wikibase.view.ViewFactory', initGadget );
} );

}( mediaWiki, jQuery ) );