User:XXN/massmerge.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)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
// Script for mass merging items
// Works with two parallel pair lists of items (sources & targets)
// Once installed, go to [[Special:MassMerge]] and provide the two lists of items: (1) source items, and (2) target items
// Author: XXN

mw.loader.using(['mediawiki.api.edit', 'mediawiki.Title'], function () {
	"use strict";

	var config = mw.config.get(['wgNamespaceNumber', 'wgTitle', 'skin']);

	function removeBlanks(arr) {
		var ret = [];
		var i, len;
		for (i = 0, len = arr.length; i < len; i++) {
			var s = arr[i];
			s = s.trim();
			if (s) {
				ret.push(s);
			}
		}
		return ret;
	}

	function doMassMerge() {
		var sources = document.getElementById("wdMassMergeQ1").value.split("\n");
		sources = removeBlanks(sources);
		if (!sources.length) {
			return;
		}
		var targets = document.getElementById("wdMassMergeQ2").value.split("\n");
		targets = removeBlanks(targets);
		if (!targets.length) {
			return;
		}
		var
			api = new mw.Api(),
			wdMassMergeSummary = document.getElementById("wdMassMergeSummary").value,
			merged = 0,
			failed = [],
			error = [],
			deferreds = [],
			onSuccess = function () {
				merged++;
				document.getElementById("wdMassMergeSubmit").value = "(" + merged + ")";
			};


		function makeMergeFunc(source, target) {
			return function () {
				return $.Deferred(function (deferred) {
					var options = {
						action: 'wbmergeitems',
						ignoreconflicts: 'description',
						fromid: source,
						toid: target,
						summary: '[[User:XXN/massmerge.js|massmerge.js]] ' + wdMassMergeSummary
					};
					var promise = api.postWithEditToken(options);
					promise.done(onSuccess);
					promise.fail(function (code, obj) {
						failed.push(source);
						error.push(obj.error.info);
					});
					promise.always(function () {
						deferred.resolve();
					});
				});
			};
		}
          /*
		  function createRedirect(source, target) {
			// we have to clear the entity first before creating the redirect...
			return api.postWithEditToken({
			  action: 'wbeditentity',
			  id: source,
			  clear: true,
			  summary: 'Clearing item to prepare for redirect',
			  data: '{}'
			}).then(function () {
			  return api.postWithEditToken({
				action: 'wbcreateredirect',
				from: source,
				to: target
			  });
			});
		   }
           */
		// Make a chain of deferred objects. We chain them rather than execute them in
		// parallel so that we don't make 1000 simultaneous merge requests and bring the
		// site down. We use deferred objects rather than the promise objects returned
		// from the API request so that the chain continues even if some pages gave errors.
		var deferred = makeMergeFunc(sources[0], targets[0])();
		for (var i = 1, len = sources.length, len2 = targets.length; i < len && i < len2; i++) {
			deferred = deferred.then(makeMergeFunc(sources[i], targets[i]));
		}

		// Show the output and do cleanup once all the requests are done.
		$.when(deferred).then(function () {
			document.getElementById("wdMassMergeSubmit").value = "Done (" + merged + ")";
			if (failed.length) {
				var $failedList = $('<ul>');
				for(var x = 0; x < failed.length; x++) {
					// Link the items in the "failed" array
					var failedTitle = mw.Title.newFromText(failed[x]);
					var $failedItem = $('<li>');
					if (failedTitle) {
						$failedItem.append( $('<a>')
							.attr('href', failedTitle.getUrl())
							.text(failed[x])
						);
					} else {
						$failedItem.text(failed[x]);
					}
					$failedItem.append(document.createTextNode(': ' + error[x]));
					$failedList.append($failedItem);
				}
				$('#wdMassMergeFailedContainer')
					.append($('<br />'))
					.append($('<b>')
						.text('Failed merges:')
					)
					.append($failedList);
			}
		});
	}
 
	function massMergeForm() {
		var bodyContent = (config.skin == "cologneblue" ? "article" : "bodyContent");
		document.getElementsByTagName("h1")[0].textContent = "XXN's mass-merge tool for Wikidata (beta)";
		document.title = "XXN's mass-merge tool for Wikidata";
		document.getElementById(bodyContent).innerHTML = //'<h3 id="siteSub">Wikidata</h3>' +
//			'<p>XXN\'s mass-merge tool</p>' +
			'<br /><br />' +
			'<form id="wdMassMerge" name="wdMassMerge">' +
			'<b>If you abuse this tool, it\'s <i>your</i> fault, not mine.</b>' +
			'<div id="wdMassMergeFailedContainer"></div>' +
			'<br /><br />' +
            'Merge from items (one on each line, please):<br />' +
					'<textarea tabindex="1" name="wdMassMergeQ1" id="wdMassMergeQ1" rows="5" cols="5"></textarea>' +
            'Merge to items (one on each line, please):<br />' +
                    '<textarea tabindex="2" name="wdMassMergeQ2" id="wdMassMergeQ2" rows="5" cols="5"></textarea>' +
				'<br /><br /><table style="background-color:transparent">' +
				'<tr><td>Summary (optional):</td>' +
					'<td><input type="text" id="wdMassMergeSummary" name="wdMassMergeSummary" maxlength="255" /></td></tr>' +
					'<tr><td><input type="button" id="wdMassMergeSubmit" name="wdMassMergeSubmit" value="Merge" /></td>' +
			'</form>';
		document.getElementById("wdMassMergeSubmit").addEventListener("click", function (e) {
			doMassMerge();
		});
	}
	 
	if (config.wgNamespaceNumber == -1 && config.wgTitle.toLowerCase() == "massmerge") {
		massMergeForm();
	}
});