User:Bargioni/PrefRank.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.
/* 
Wikidata gadget to set preferred rank to P19, P20, P569, P570
or other properties (see config).
Basic idea: User:Epìdosis
Written by: User:Bargioni, Jan. 2024
  ____            __ ____             _    
 |  _ \ _ __ ___ / _|  _ \ __ _ _ __ | | __
 | |_) | '__/ _ \ |_| |_) / _` | '_ \| |/ /
 |  __/| | |  __/  _|  _ < (_| | | | |   < 
 |_|   |_|  \___|_| |_| \_\__,_|_| |_|_|\_\ 0.1
                                           
Logo obtained from
https://patorjk.com/software/taag/#p=author&f=Standard&t=PrefRank
*/

/* jshint esversion: 6 */

mw.loader.using([ 'jquery.ui' ]).then(function () {

	$( function($) { // our workspace

		function save_pref_rank(claim_id, Qmotivation) {
			// console.log('saving claim', claim_id, Qmotivation); // test
			// refresh claim, modify and save it
			var jq_claim_id = '#'+claim_id.replace(/\$/,'\\$'); // escape $ for jQuery reasons
			$.getJSON(`https://www.wikidata.org/w/api.php?action=wbgetclaims&claim=${claim_id}&format=json`, function(CC) {
				try {
					// console.log(CC, claim_id, Qmotivation); // test
					var P = Object.keys(CC.claims)[0];
					var C = CC.claims[P][0]; // C is the claim to be modified
					C.rank = 'preferred';
					// add qualifier P7452 with value Qmotivation, unless Q0
					if (Qmotivation != 'Q0') {
						var motivation = Qmotivation.replace(/Q/,'');
						if (!C.hasOwnProperty('qualifiers')) {
							C.qualifiers = {};
							C['qualifiers-order'] = [];
						}
						C.qualifiers["P7452"] = [
							{
								"property"  : "P7452",
								"snaktype"  : "value",
								"datavalue" : {
									"value" : {
										"entity-type": "item",
										"numeric-id": motivation,
										"id": Qmotivation
									},
									"type": "wikibase-entityid"
								},
								"datatype" : "wikibase-item"
							}
						];
						C['qualifiers-order'].push("P7452");
					}
					// console.log('going to save claim',C); // test
					let api = new mw.Api()
					let token = mw.user.tokens.values.csrfToken;
					api.post({
						'action'     : 'wbsetclaim',
						'claim'      : JSON.stringify(C),
						'format'     : 'json',
						'token'      : token,
						'summary'    : "Set preferred value using [[User:Bargioni/PrefRank|PrefRank]]"
					})
					.then(function(aw) {
							let P = aw.claim.mainsnak.property;
							mw.notify(`Preferred value of ${P} saved successfully. Please reload the page to see this change.`, {title: 'PrefRank', type: 'success'});
							$(jq_claim_id).fadeOut(200, function(){
    							$(this).css('background', '#F0FFF0').fadeIn(1200);
							});
					})
					.catch(function(aw) {
						console.log('PrefRank server side error',aw);
						mw.notify("A server side error occurred while saving the preferred value.", {title: 'PrefRank', type: 'error'});
						$(jq_claim_id).fadeOut(200, function(){
							$(this).css('background', 'pink').fadeIn(1200);
						});
					});
				}
				catch(e){
					console.log('PrefRank: client side error while saving preferred value',e);
					mw.notify(`A client side error occurred while saving the preferred value: ${e}`, {title: 'PrefRank', type: 'error'});
					$(jq_claim_id).fadeOut(200, function(){
						$(this).css('background', 'pink').fadeIn(1200);
					});
				}
			});
		}

		function setup_pref_rank_motivation_dialog() {
			$('body').append('<div style="display:none" id="PrefRank_dialog" title=""></div>');
			$( "#PrefRank_dialog" ).dialog({
				autoOpen: false,
				modal: true,
				buttons: [
					{
						text: "OK",
						click: function() {
							var claim_id = $('#claim_id').val();
							var Qmotivation = $('#PrefRank_dialog input[name="motivation"]:checked').attr('id');
							// colorare valore pref o altra cosa, o farlo a cosa fatta TODO
							save_pref_rank( claim_id, Qmotivation );
							$( this ).dialog( "close" );
						}
					}
				]
			});
			$('#PrefRank_dialog').on('dialogclose', function(event) {
				mw.PrefRank.chosen_value.css('background-color',''); // disattiva background del valore scelto
				mw.PrefRank.chosen_value = '';
			});
			$('#PrefRank_dialog').parent().css('font-size','1.0em');
			let info_icon = 'https://upload.wikimedia.org/wikipedia/commons/e/e4/Infobox_info_icon.svg';
			$('#PrefRank_dialog').siblings('.ui-dialog-buttonpane').find('.ui-dialog-buttonset').before(
				`<span style="position:relative; top:15px; color:gray"><a href="https://www.wikidata.org/w/index.php?title=User:Bargioni/PrefRank" style="color:gray" target="_blank">PrefRank 0.1 <img src="${info_icon}" width="22px"></a></span>`
			);
		}

		function get_property(P) {
			let item = mw.PrefRank.item.entities[qid];
			let claims = item.claims[P] ? item.claims[P] : [];
			return claims;
		}

		function get_property_values(P) {
			// return the values of property P
			var values = [];
			let props = get_property(P);
			for (var i = 0; i < props.length; i++) {
				var v = props[i].mainsnak.datavalue;
				if (v) {
					if (v.type == 'time') { values.push( v.value.time ) }
					if (v.type == 'wikibase-entityid') { values.push( v.datavalue ? v.datavalue.value.id : v.value.id ) }
					if (v.type == 'string') { values.push( v.datavalue ? v.datavalue.value : v.value ) }
				}
			}
			return values;
		}

		function setup_pref_rank(apply_to_claims, P) {
			// console.log('apply PrefRank button to ',P, apply_to_claims); // test
			for (var i=0; i < apply_to_claims.length; i++) {
				var claim = apply_to_claims[i];
				var claim_id = claim.id;
				var jq_claim_id = '#'+claim_id.replace(/\$/,'\\$'); // escape $ for jQuery reasons
				if (mw.PrefRank.config.button == 'special_icon') {
					var pref_rank_icon = `<img class="pref_rank_icon" 
						title="${mw.PrefRank.config.strings[mw.PrefRank.user_lang] ? mw.PrefRank.config.strings[mw.PrefRank.user_lang].tooltip : mw.PrefRank.config.strings.en.tooltip}"
						width="${mw.PrefRank.config.special_icon_img_width}" 
						alt="[PrefRank button]"
						src="${mw.PrefRank.config.special_icon_img_src}" 
						data_prop="${claim_id}"/>`;
					$(jq_claim_id).find('.wikibase-toolbar-container.wikibase-edittoolbar-container').prepend('<span style="float:left">'+pref_rank_icon+'</span>')
				}
				if (mw.PrefRank.config.button == 'click_on_rank_icon') {
					$(jq_claim_id).find('.ui-icon-rankselector')
						.css({'cursor':'pointer', 'border':'2px solid lightgreen'})
						.addClass('pref_rank_icon')
						.attr('title', `${mw.PrefRank.config.strings[mw.PrefRank.user_lang] ? mw.PrefRank.config.strings[mw.PrefRank.user_lang].tooltip : mw.PrefRank.config.strings.en.tooltip}`)
						.attr('data_prop', claim_id);
				}
			}
		}

		function apply_pref_rank_to_property(P) {
			// console.log('apply_pref_rank_to_property',P); // test
			let claims = get_property(P);
			// console.log(P, claims); // test
			var apply_to_claims = [];
			for	(var i = 0; i < claims.length; i++) {
				var claim = claims[i];
				// console.log(claim) // test
				if (claim.rank == 'preferred') return false; // do not apply, we have a pref'd value
				if (claim.rank == 'normal') apply_to_claims.push(claim);
			}
			if (apply_to_claims.length > 1) {
				setup_pref_rank(apply_to_claims, P); // apply
				return true;
			}
			return false; // do not apply, no more than 1 value
		}

		function setup_options() {
			var motivations = [];
			var strings = mw.PrefRank.config.strings[ mw.PrefRank.user_lang ] || mw.PrefRank.config.strings.en;
			var motivations = mw.PrefRank.config.motivations;
			var motivation_labels = strings.motivation_labels;
			var html = []; var check = 'checked="checked"';
			for (var i=0; i < motivations.length; i++) {
				var m = motivations[i];
				var ml = motivation_labels[i] || '?';
				html.push(`<input ${check} type="radio" id="${m}" name="motivation" value="${m}">
					<label for="${m}">${ml}</label><br/>`);
				check = '';
			}
			return html.join('');
		}

		function apply_pref_rank() {
			for (var i = 0; i < mw.PrefRank.config.properties.length; i++) {
				var P = mw.PrefRank.config.properties[i];
				apply_pref_rank_to_property(P);
			}
			if ($('.pref_rank_icon').length) {
				setup_pref_rank_motivation_dialog();
				$('.pref_rank_icon')
					.css('cursor','pointer')
					.click(function(event){
						event.preventDefault();
						var claim_id = $(this).attr('data_prop');
						var h_claim_id = `<input id="claim_id" type="hidden" value="${claim_id}"/>`;
						var options = setup_options();
						var P = $(this).closest('.wikibase-statementgroupview.listview-item').attr('id');
						var chosen_value;
						if (mw.PrefRank.config.button == 'special_icon') {
							chosen_value = $( $(this).closest('div') ).find('.wikibase-snakview-value.wikibase-snakview-variation-valuesnak').eq(0);
						}
						else {
							chosen_value = $(this).closest('div.wikibase-statementview').find('.wikibase-snakview-value.wikibase-snakview-variation-valuesnak').eq(0);
						}
						chosen_value.css('background-color',mw.PrefRank.config['background-color']);
						mw.PrefRank.chosen_value = chosen_value;
						var strings = mw.PrefRank.config.strings[ mw.PrefRank.user_lang ] || mw.PrefRank.config.strings.en;
						var comment = strings.dialog_comment1 + ' "' +
							chosen_value.text() + 
							'" ' + strings.dialog_comment2 + 
							' ' + P + '. ' +
							strings.dialog_comment3;
						$( "#PrefRank_dialog" )
							.dialog( "option", "title", strings.dialog_title )
							.html(comment + '<p style="padding-top:5px">' + options + '</p>' + h_claim_id);
						if (!event.originalEvent.shiftKey) {
							 // open the dialog unless shift was pressed
							 $( "#PrefRank_dialog" ).dialog('open');
						}
						else {
							// save the preferred value using the first i.e. the default motivation
							$('#PrefRank_dialog').parent().find('.ui-dialog-buttonpane button').click();
						}
					});
				// disable the pref_rank_icon when user edits the claim as usual; this will allow to manually modify the rank itself, e.g. for deprecating
				$('.wikibase-edittoolbar-container').click(function(){
					$(this).parent().find('.pref_rank_icon').unbind('click');
					$(this).parent().find('.pref_rank_icon').css('border','');
					$(this).parent().find('.pref_rank_icon').removeClass('pref_rank_icon');
				});
			}
		}

		function pref_rank_check_item_instances() {
			let item_instances = get_property_values('P31');
			let config_instances = mw.PrefRank.config.instances;
			let instances = item_instances.filter(e => config_instances.includes(e));
			if (instances.length == 0) {
				console.log('PrefRank: no instances, exit');
				return false;
			}
			return true;
		}

		function get_config_and_item( qid ) {
			if (mw.PrefRank.config === undefined) {
				mw.PrefRank.retries++;
				if (mw.PrefRank.retries > mw.PrefRank.max_retries) {
					alert("Unable to load config.\nImpossible to activate gadget PrefRank");
					return;
				}
				setTimeout(function(){get_config_and_item(qid)}, 200); // try (again)
			}
			else {
				console.log('PrefRank config loaded'); // test
				let url = 'https://www.wikidata.org/wiki/Special:EntityData/'+qid+'.json';
				$.getJSON(url, function(R) {
					mw.PrefRank.item = R;
					if ( pref_rank_check_item_instances() ) apply_pref_rank();
				});
			}
		}
	
		// ========== MAIN

		// check if we are viewing an item
		var qid = mw.config.get( 'wbEntityId' );
		if ( !qid ) return;

		console.log('PrefRank gadget loaded');
		if (mw.PrefRank === undefined) mw.PrefRank = {};
		mw.PrefRank.qid = qid;
		mw.PrefRank.user_lang = wb.getUserLanguages()[0];
		mw.PrefRank.retries = 0;
		mw.PrefRank.max_retries = 50;
		mw.PrefRank.chosen_value = '';
		get_config_and_item(qid);

	}); // end of our workspace

}); // end of mw.loader.using