MediaWiki:Gadget-EasyQuery.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.
$( function () {
	var namespace = mw.config.get( 'wgNamespaceNumber' );
	var isMain = namespace === 0;
	var isProperty = namespace === 120;
	var isLemma = namespace === 146;
	if ( !isMain && !isProperty && !isLemma ) {
		return;
	}

	function createPopupAndAddIcon( element, query, title, label ) {
		var url = '#' + encodeURIComponent(query);

		mw.loader.using( [ 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui.styles.icons-interactions' ] ).then( function () {
			var searchIcon = new OO.ui.IconWidget( {
				icon: 'ellipsis',
				iconTitle: title,
				$element: $( '<a>' ).attr( {
					href: 'https://query.wikidata.org/' + url,
					target: '_blank',
					style: 'background-size: 20px 20px; opacity: 0.5;'
				} )
			} );

			var $content = $( '<div>' );
			var popup = new OO.ui.PopupWidget( {
				$content: $content,
				width: 500,
				head: true,
				padded: false,
				label: label,
				align: 'force-right'
			} );

			$( document ).keydown( function( e ) {
				// ESCAPE key pressed
				if ( e.keyCode === 27 ) {
					popup.onCloseButtonClick();
				}
			} );

			searchIcon.$element.click( function () {
				$content.html(
					$( '<iframe scrolling="yes" frameborder="0">' )
					.attr( {
						src: 'https://query.wikidata.org/embed.html' + url,
						width: '500',
						height: '400'
					} )
				);
				popup.$element.attr( 'style', 'position:absolute; z-index:100;' );
				popup.toggle( true );
				return false;
			} );
			$( element ).append( searchIcon.$element, popup.$element );
		} );
	}

	// Title lable popup
	var $title = $( '.wikibase-title' );
	var id = $title.find( '.wikibase-title-id' ).text().replace( /[()]/g, '' );
	var query = ''
		+ '#defaultView:Graph\n'
		+ 'SELECT ?node ?nodeLabel ?nodeImage ?childNode ?childNodeLabel ?childNodeImage ?rgb WHERE {\n'
		+ '  {\n'
		+ '    BIND(wd:' + id + ' AS ?node)\n'
		+ '    ?node ?p ?i.\n'
		+ '    OPTIONAL { ?node wdt:P18 ?nodeImage. }\n'
		+ '    ?childNode ?x ?p.\n'
		+ '    ?childNode rdf:type wikibase:Property.\n'
		+ '    FILTER(STRSTARTS(STR(?i), "http://www.wikidata.org/entity/Q"))\n'
		+ '    FILTER(STRSTARTS(STR(?childNode), "http://www.wikidata.org/entity/P"))\n'
		+ '  }\n'
		+ '  UNION\n'
		+ '  {\n'
		+ '    BIND("EFFBD8" AS ?rgb)\n'
		+ '    wd:' + id + ' ?p ?childNode.\n'
		+ '    OPTIONAL { ?childNode wdt:P18 ?childNodeImage. }\n'
		+ '    ?node ?x ?p.\n'
		+ '    ?node rdf:type wikibase:Property.\n'
		+ '    FILTER(STRSTARTS(STR(?childNode), "http://www.wikidata.org/entity/Q"))\n'
		+ '  }\n'
		+ '  OPTIONAL {\n'
		+ '    ?node wdt:P18 ?nodeImage.\n'
		+ '    ?childNode wdt:P18 ?childNodeImage.\n'
		+ '  }\n'
		+ '  SERVICE wikibase:label { bd:serviceParam wikibase:language "' + mw.config.get( 'wgUserLanguage' ) + '". }\n'
		+ '}';
	createPopupAndAddIcon( $title.find( '.wikibase-title-id' ), query, 'Click to see graph', 'Entity Graph');
	
	function buildQuery(property, object) {
		var query;
		var language = mw.config.get( 'wgUserLanguage' ) + ',en,de,fr,ja,es,ru,pt,it,zh,fa,ar,pl,nl,uk,tr,id,he,cs,sv,hu,fi,vi,ko,el,hi,bn,no,ca,ro,th,da,sr,bg,az,ms,et,uz,hr,sk,eu,hy,sl,lt,eo,ta,kk,lv,be,kn,sq,ur,mk';

		// Use nested query, otherwise query timeouts on basic things like "P31 Q5"
		// Do not use [AUTO_LANGUAGE], because there is no language selector in iframe
		if ( isLemma ) {
			query = ''
			+ 'SELECT ?item ?lemma ?category ?language {\n'
			+ '  {\n'
			+ '    SELECT * WHERE {\n'
			+ '      ?item rdf:type ontolex:LexicalEntry ;\n'
			+ '            wdt:'+ property +' '+ object +' ;\n'
			+ '            wikibase:lemma ?lemma ;\n'
			+ '            wikibase:lexicalCategory ?categoryItem ;\n'
			+ '            dct:language ?languageItem .\n'
			+ '    } LIMIT 100\n'
			+ '  }\n'
			+ '  SERVICE wikibase:label {\n'
			+ '    bd:serviceParam wikibase:language "'+ language +'" .\n'
			+ '    ?languageItem rdfs:label ?language . ?categoryItem rdfs:label ?category .\n'
			+ '  }\n'
			+ '}';
		} else {
			var propFilter = isProperty ? '      ?item rdf:type wikibase:Property .\n' : '';
			
			// Use nested query, otherwise query timeouts on basic things like "P31 Q5"
			// Do not use [AUTO_LANGUAGE], because there is no language selector in iframe
			query = ''
			+ 'SELECT * {\n'
			+ '  {\n'
			+ '    SELECT * {\n'
			+ '      ?item wdt:'+ property +' '+ object +' .\n'
			+ propFilter
			+ '    } LIMIT 100\n'
			+ '  }\n'
			+ '  SERVICE wikibase:label {\n'
			+ '    bd:serviceParam wikibase:language "'+ language +'" .\n'
			+ '    ?item rdfs:label ?label . ?item schema:description ?description\n'
			+ '  }\n'
			+ '}';
		}

		return query;
	}

	mw.hook( 'wikibase.entityPage.entityLoaded' ).add( function ( entityData ) {
		var propertyId;
		for (propertyId in entityData.claims) {
			var statementGroup = entityData.claims[propertyId];
			for ( var i = 0; i < statementGroup.length; i++ ) {
				var statement = statementGroup[i];
				if ( statement.mainsnak.snaktype !== "value" ) {
					continue;
				}

				var statementId = statement.id;
				var statementView = document.getElementById(statementId);
				if ( !statementView ) {
					continue;
				}

				var attachPoint = statementView.querySelector('.wikibase-statementview-mainsnak .wikibase-snakview-indicators');
				if ( !attachPoint ) {
					continue;
				}
				
				var datavalue = statement.mainsnak.datavalue;
				var datatype = statement.mainsnak.datatype;
				var object = undefined;

				if ( datatype === 'wikibase-item' || datatype === 'wikibase-property' || datatype === 'wikibase-lexeme' ) {
					object = 'wd:' + datavalue.value.id;
				} else if ( datatype === 'time' ) {
					object = '"' + datavalue.value.time + '"^^xsd:dateTime';
				} else if ( datatype === 'quantity' ) {
					object = datavalue.value.amount;
				} else if ( datatype === 'string' || datatype === 'external-id' ) {
					object = JSON.stringify(datavalue.value); // escaping quotes
				} else if ( datatype === 'url' ) {
					object = '<' + datavalue.value + '>';
				} else if ( datatype === 'monolingualtext' ) {
					object = JSON.stringify(datavalue.value.text) + '@' + datavalue.value.language;
				} else if ( datatype === 'commonsMedia' ) {
					object = '<http://commons.wikimedia.org/wiki/Special:FilePath/' + encodeURIComponent(datavalue.value) + '>';
				}
				if ( !object ) {
					continue;
				}

				var query = buildQuery( propertyId, object );
				createPopupAndAddIcon( $( attachPoint ), query, 'More items with this statement' );
			}
		}
	} );
} );