User:CristianCantoro/missing props.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.
/*
(c) 2013 Magnus Manske, GPL V2+
Usage: Add
 importScript( 'User:Magnus_Manske/missing_props.js' );
to your "common.js" User subpage
 
Feel free to expand the types and expected properties lists!
*/
 
var wd_missing_props = {
 
	q_prefix : 'Q' ,
	p_prefix : 'P' ,
	api : '/w/api.php' ,
	id_cnt : 0 ,
 
	types : { // P/Q indicators
		'book' : [ [31,571] ] ,
		'species' : [ [105,7432] ] ,
		'human' : [ [31, 5] ],
                'geographical' : [ [107, 618123] ],
                'village' : [ [31,532] ]
	} ,
 
	expected : { // Potential properties
		'book' : [357,392,364,50,98,136,135,393,291,123,577,179,110,212,243,166,155,156,144] ,
		'species' : [107,225,74,373] ,
		'human' : [21, 27, 569, 570, 19, 20, 513, 106, 101, 108, 69, 512, 26, 40, 25, 22, 9, 7, 463, 102, 39, 373, 43, 45, 140],
                'geographical' : [373, 131, 625] ,
                'village' : [107, 131, 132, 625] 
	} ,
 
	init : function () {
		var self = this ;
 
		var portletLink = mw.util.addPortletLink( 'p-tb', 'javascript:;', 'Missing props','t-wd_mp');
		$(portletLink).click ( function () {
			self.run(true) ;
			return false ;
		} ) ;
		self.run(false);
	} ,
 
	run : function ( do_alert ) {
		var self = this ;
		self.determineType ( function () {
			if ( undefined === self.type ) {
				if ( do_alert ) alert ( 'Could not determine item type' ) ;
				return ;
			}
			var loadLabels = [] ;
			$('div.wd_mp').remove() ;
 
			$.each ( self.expected[self.type] , function ( k , v ) {
				if ( undefined !== self.claims[self.p_prefix+v] ) return ; // Has that prop
				var h = "<div class='wd_mp' style='border:1px solid #DDDDDD;padding:2px;margin-top:5px' id='wd_mp"+v+"'>" ;
				h += "<a href='javascript:;' class='wd_mp_ap' prop='"+v+"'>Add \"<span class='" + self.p_prefix + v + "'>P" + v + "</span>\"</a>" ;
				h += "</div>" ;
				$('div.wb-claimlistview :last').after ( h ) ;
				loadLabels.push ( self.p_prefix+v ) ;
			} ) ;
			self.showLabels ( loadLabels ) ;
			$('a.wd_mp_ap').click ( function(){self.addProp($(this).attr('prop'));return false} ) ;
			self.autofill() ;
		} ) ;
	} ,
 
	autofill : function () {
		var self = this ;
 
		$.each ( ['en','de','es','fr','it','pt'] , function ( dummy , lang ) {
 
			var page = $('td.wb-sitelinks-link-'+lang+' a').text() ;
			if ( page === undefined || page == '' ) return ;
 
			$.getJSON ( '//'+lang+'.wikipedia.org/w/api.php?callback=?' , {
				action:'query',
				prop:'links',
				pllimit:500,
				plnamespace:0,
				titles:page,
				format:'json'
			} , function ( d_wp ) {
				var titles = [] ;
				$.each ( (d_wp.query.pages||{}) , function ( k , v ) {
					if ( k < 0 ) return ; // Paranoia
					$.each ( (v.links||[]) , function ( k2 , v2 ) {
						titles.push ( v2.title ) ;
					} ) ;
				} ) ;
 
				self.doPostDance ( titles , [] , lang ) ;
 
 
			} ) ;
 
			return false ;
		} ) ;
	} ,
 
 
	doPostDance : function ( titles , candidates , lang ) {
		var self = this ;
		var t = [] ;
		while ( t.length < 50 && titles.length > 0 ) {
			t.push ( titles.shift() ) ;
		}
 
		$.post ( self.api , {
			action:'wbgetentities',
			sites:lang+'wiki',
			titles:t.join('|'),
			languages:'en',
			format:'json'
		} , function ( d ) {
			$.each ( (d.entities||{}) , function ( q , v ) {
				if ( q < 0 ) return ;
				var o = { q : q ,
					label : ( typeof v.labels === 'undefined' || typeof v.labels.en === 'undefined' ) ? q : v.labels.en.value ,
					page : v.sitelinks[lang+'wiki'].title ,
					desc : ( undefined === v.descriptions || undefined === v.descriptions.en ) ? '' : v.descriptions.en.value ,
				}
				candidates.push ( o ) ;
			} ) ;
 
			if ( titles.length > 0 ) {
				self.doPostDance ( titles , candidates , lang ) ;
				return ;
			}
 
			var h = "<span> or prefilled <form class='wp_mp_quickadd' style='display:inline-block'><select class='wd_mp_select'>" ;
			$.each ( candidates , function ( dummy , v ) {
				h += "<option value='" + v.q + "'>" ;
				h += (v.label==v.q?v.page:v.label) ;
				if ( v.desc != '' ) h += ' : ' + v.desc.substr(0,20) ;
				h += "</option>" ;
			} ) ;
			h += "</select>" ;
			h += "<input type='submit' onclick='' value='+' /></form></span>" ;
 
			$(h).insertAfter ( 'a.wd_mp_ap' ) ;
			$('form.wp_mp_quickadd input').click ( function ( o ) {
				o.preventDefault() ;
				var p = $($($(this).parents('div.wd_mp').get(0)).find('a.wd_mp_ap')).attr('prop') ;
				var q = $($($(this).parents('div.wd_mp').get(0)).find('select.wd_mp_select')).val() ;
				var val = '{"entity-type":"item","numeric-id":' + q.replace(/\D/g,'') + '}' ;
				self.createClaim ( p , val ) ;
				return false ;
			} ) ;
		} ) ;
 
	} ,
 
	addProp : function ( p ) {
		var self = wd_missing_props ;

		$('#wd_mp'+p).remove() ;
		$('span.wb-addtoolbar :last a').click() ;
 
		$('div.wb-snak-property input.ui-entityselector-input').val ( self.p_prefix+p ) ;

		var e = $.Event("keydown") ;
		e.which = 40 ;
		$("div.wb-snak-property input.ui-entityselector-input").trigger(e) ;

		self.clickit() ;
		return false ;
	} ,
 
	clickit : function () {
/*		var self = wd_missing_props ;
		var a = $('a.ui-entityselector-section-container') ;
		if ( a.length == 0 ) {
			setTimeout ( self.clickit , 100 ) ;
			return ;
		}
 
		// THIS DOES NOT WORK! NEITHER DOES .click() on first dropbox element!
		setTimeout ( function () {
			var e = $.Event("keydown");
			e.which = 9;
			$("div.wb-claim-new input.ui-entityselector-input").trigger(e);
		} , 1000 ) ;*/
	} ,
 
	showLabels : function ( props ) {
		var self = this ;
		$.post ( self.api , {
			action:'wbgetentities',
			ids:props.join('|'),
			props:'labels',
			format:'json'
		} , function ( d ) {
			var lang = mw.config.get('wgUserLanguage') ;
			$.each ( d.entities , function ( k , v ) {
				if ( typeof v.labels !== 'undefined' && typeof v.labels[lang] !== 'undefined' ) {
					$('span.'+k).html ( v.labels[lang].value ) ;
				}
			} ) ;
		} , 'json' ) ;
	} ,
 
	determineType : function ( callback ) {
		var self = this ;
		var entity = mw.config.get('wgTitle').toUpperCase() ;
		$.post ( self.api , {
			action:'wbgetentities',
			ids:entity,
			props:'claims',
			format:'json'
		} , function ( d ) {
			self.claims = d.entities[entity].claims ;
 
			$.each ( self.types , function ( type , tl ) {
				$.each ( tl , function ( dummy , tp ) {
					if ( undefined === self.claims[self.p_prefix+tp[0]] ) return ;
					$.each ( self.claims[self.p_prefix+tp[0]] , function ( k2 , v2 ) {
						if ( v2.mainsnak.datavalue.value['numeric-id'] != tp[1] ) return ;
						self.type = type ;
						return false ;
					} ) ;
					if ( undefined !== self.type ) return false ;
				} ) ;
				if ( undefined !== self.type ) return false ;
			} ) ;
			callback() ;
		} , 'json' ) ;
	} ,
 
 
// BEGIN from wikidata_useful.js	
 
	createClaim : function ( property , value ) {
		var entity = mw.config.get('wgPageName').toUpperCase() ;
		var self = this ;
		entity = self.q_prefix + entity.replace ( /\D/g , '' ) ;
		property = property.replace ( /\D/g , '' ) ;
		$.post ( self.api , {
			action : 'query' ,
			prop : 'info' ,
			intoken : 'edit' ,
			titles : entity ,
			format : 'json'
		} , function ( data ) {
			var token , lastrevid ;
			$.each ( (data.query.pages||[]) , function ( k , v ) {
				token = v.edittoken ;
				lastrevid = v.lastrevid ;
			} ) ;
 
			if ( undefined === token ) {
				console.log ( "Cannot get edit token for " + entity ) ;
				return ;
			}
 
			property = property.replace(/\D/g,'') ;
			entity = entity.replace(/\D/g,'') ;
			var vo = JSON.parse ( value ) ;
			var is_item_target = vo['numeric-id'] !== undefined ;
			var value_id = is_item_target ? vo['numeric-id']+'' : vo ;
 
			var other_entity = ( entity.replace(/\D/g,'') != entity.replace(/\D/g,'') ) ;
 
			$.post ( self.api , {
				action : 'wbcreateclaim' ,
				entity : self.q_prefix+entity ,
				snaktype : 'value' ,
				property : self.p_prefix+property ,
				value : value ,
				token : token ,
				baserevid : lastrevid ,
				format : 'json'
			} , function ( data ) {
				var id = 'wd_mp_added_' + self.id_cnt ;
				self.id_cnt++ ;
				var h = "<div id='" + id + "'>" ;
				h += "Added " ;
				h += "<span class='added_entity_p'>" + property + "</span>" ;
				h += " &Rarr; " ;
				h += "<span class='added_entity_q'>" + value_id + "</span>" ;
				if ( other_entity ) h += " to entity <span class='added_entity_x'>" + entity + "</span>" ;
				h += ".</div>" ;
				$($('div.wb-claims').get(0)).append ( h ) ;
				self.updateEntity ( id , property , self.p_prefix ) ;
				if ( is_item_target ) self.updateEntity ( id , value_id , self.q_prefix ) ;
				if ( is_item_target && other_entity ) self.updateEntity ( id , entity.replace(/\D/g,'') , 'x' ) ;
			} , 'json' ) ;
 		} , 'json' ) ;
 
	} ,
 
	updateEntity : function ( id , value , prefix ) {
		var self = this ;
		var q = prefix+value ;
		if ( prefix == 'x' ) q = self.q_prefix + value ;
		$.getJSON ( self.api , {
			action : 'wbgetentities' ,
			ids : q ,
			format : 'json'
		} , function ( data ) {
			var labels = data.entities[q].labels ;
			var title = q ;
			if ( undefined !== labels ) {
				$.each ( ['en','de','fr'] , function ( k , v ) {
					if ( undefined === labels[v] ) return ;
					title = labels[v].value ;
					return false ;
				} ) ;
			}
			var h = "<a href='/wiki/" + q + "'>" + title + "</a>" ;
			$('#'+id+' span.added_entity_'+prefix).html ( h ) ;
		} ) ;
	} ,
 
 
// END wikidata_useful.js	
 
	dummy : ''
 
} ;
 
$ ( function() {
	if ( mw.config.get('wgNamespaceNumber') != 0 ) return ;
	if ( mw.config.get('wgAction') != 'view' ) return ;
 
	wd_missing_props.init () ;
});