Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
$(document).ready ( function () {
	
	var wd_edit = {
	
		t : {
			go2wd:"View or edit this property on Wikidata",
			set_value:"Set or edit this value",
			add_value:"Add a new value for this property",
			edit:'edit',
			sticky_msg:'Your input has been added to Wikidata. It will become permanent in this table on the next update (within ~24h or manually).',
			wd_api_fail:'Edit via Wikidata API has failed.'
		} ,
		
		init : function () {
			var me = this ;
			me.lang = mw.config.get('wgPageContentLanguage') ;
		} ,
		
		getItemString : function ( i , p ) {
			var me = this ;
			var key = p=='label' ? 'labels' : 'descriptions' ;
			if ( typeof i[key] == 'undefined' ) return '' ;
			if ( typeof i[key][me.lang] == 'undefined' ) return '' ;
			return i[key][me.lang].value ;
		} ,
		
		setDisplayString : function ( o , s , mode ) {
			var me = this ;
			$('#wd_hover').remove() ;
			var note = "<div style='background-color:#FFFF84;font-size:7pt;'>" + me.t.sticky_msg + "</div>" ;
			if ( mode == 'replace' ) {
				var a = o.find('a') ;
				if ( a.length === 0 ) $(o).text(s) ;
				else $(a[0]).text(s) ;
				$(o).append ( note ) ;
			} else if ( mode == 'append' ) {
				$(o).append(s+note) ;
			}
		} ,
		
		getWikidataEditToken : function ( callback ) {
			this.doAPI ( {
		        action: 'query',
		        meta: 'tokens'
		    } , function ( d ) {
		    	callback ( d.query.tokens.csrftoken ) ;
		    } ) ;
		} ,
		
		setLabelValue : function ( q , p , s , callback ) {
			var me = this ;
			var action = '' ;
			if ( p == 'label' ) action = 'wbsetlabel' ;
			if ( p == 'desc' ) action = 'wbsetdescription' ;
			me.editAPI ( {
				action:action,
				id:q,
				language:me.lang,
				value:s
			} , function ( d ) {
				callback ( d ) ;
			}) ;
		} ,

		editAPI : function ( data , callback ) {
			var me = this ;
			me.getWikidataEditToken ( function ( token ) {
				data.token = token ;
				me.doAPI ( data , callback ) ;
			}) ;
		} ,
		
		doAPI : function ( data , callback ) {
			data.format = 'json' ;
			data.origin = 'https:'+mw.config.get('wgServer') ;
			$.ajax( {
			    url: 'https://www.wikidata.org/w/api.php',
			    method:'POST',
			    data: data ,
			    xhrFields: {
			        withCredentials: true
			    },
			    dataType: 'json'
			} ).done( function ( d ) {
//					console.log('OK!',d) ;
					callback ( d ) ;
			} );
		} ,
		
		setItemString : function ( i , p , v , o ) {
			var me = this ;
			me.getWikidataEditToken ( function ( token ) {
				if ( typeof token == 'undefined' || token === '' ) {
					alert ( "Problem getting edit token from Wikidata!" ) ;
					return ;
				}
				me.setLabelValue ( i.title , p , v , function ( d ) {
					if ( d.success ) me.setDisplayString ( o , v , 'replace' ) ;
					else alert ( me.t.wd_api_fail ) ;
				} ) ;
				
			}) ;
		} ,
		
		loadItem : function ( q , callback ) {
			q = q.toUpperCase() ;
			$.getJSON ( 'https://www.wikidata.org/w/api.php?action=wbgetentities&ids='+q+'&format=json&callback=?' , function ( d ) {
				callback ( d.entities[q] ) ;
			} ) ;
		} ,
		
		addPropValue : function ( o , q , p ) {
			var me = this ;
			me.loadItem ( q , function ( i ) {
				if ( p == 'label' || p == 'desc' ) {
					var s = me.getItemString(i,p) ;
					var v = prompt ( me.t.set_value , s ) ;
					if ( v !== null && v != s ) me.setItemString ( i , p , v , o ) ;
					return false ;
				}
			} ) ;
		} ,
		
		prep4edit : function ( o_orig , q , p ) {
			var me = this ;
			$(o_orig).hover(function(){
				$('#wd_hover').remove() ;
				var o = $(this) ;
				var off = o.position() ;
				var ry = parseInt(off.top) + 5 ;
				var h = "<div style='position:absolute;background-color:#EEE;border:1px solid #DDD;padding:2px;box-shadow: 10px 10px 5px #888888;z-index:5;top:"+ry+"px' id='wd_hover'>" ;
				var m = p.match(/^p(\d+)$/) ;

				var title = me.t.set_value ;
				if ( m !== null ) title = me.t.add_value ;
				var label = '+' ;
				if ( m === null ) label = me.t.edit ;
				h += "<div><a href='#' id='wd_hover_add' title='"+title+"'>["+label+"]</a></div>" ;

				var target = q ;
				if ( m !== null ) target += "#" + p.toUpperCase() ;
				h += "<div><a href='//www.wikidata.org/wiki/"+target+"' title='"+me.t.go2wd+"'>&rArr;WD</a></div>"

				h += "</div>" ;
				o.prepend(h) ;
				$('#wd_hover').css ( { left:parseInt(off.left)+parseInt(o.width())-parseInt($('#wd_hover').width()) } ) ;
				
				$('#wd_hover_add').click ( function () {
					$('#wd_hover').remove() ;
					me.addPropValue ( o , q , p ) ;
					return false ;
				})
			},function(){
				$('#wd_hover').remove() ;
			}) ;
		}
	} ;
	
	
	
	// Prepare cells
	wd_edit.init() ;
	$('table.wd_can_edit').each ( function () {
		var table = $(this) ;
		table.find('tr').each ( function () {
			var classList = this.className.split(/\s+/);
			var q ;
			$.each ( classList , function (k,v) {
				var m = v.match(/^wd_q(\d+)/);
				if ( m === null ) return ;
				q = 'Q'+m[1];
			});
			if ( typeof q == 'undefined' ) return ;
			$(this).find('td').each ( function () {
				var classList = this.className.split(/\s+/);
				var me = this ;
				$.each ( classList , function (k,v) {
					var m = v.match(/^wd_(.+)/);
					if ( m === null ) return ;
					wd_edit.prep4edit ( me , q , m[1] ) ;
				} ) ;
			}) ;
		});
	});
});