Jump to content

User:Anoptimistix/common.js

From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by Anoptimistix (talk | contribs) at 14:55, 14 July 2017 (New script inserted). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.
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.
importScript('User:Lourdes/PageCuration.js'); // Linkback: [[User:Lourdes/PageCuration.js]]

*/
 
$.when( mw.loader.using( ['mediawiki.util'] ), $.ready ).done( function() {
  mw.util.addPortletLink(
    'p-personal',
    mw.util.getUrl('Special:NewPagesFeed'),
    'Page Curation',
    'pt-pagecuration',
    'View Special:New Pages using the Page Curation tool',
    null,
    '#pt-preferences'
  );
});
// <nowiki>
$( function($) {
	
var moveToDraft = function moveToDraft() {

//'Global' vars & objects are stored in the m2d object
var m2d = {};
m2d.Api = new mw.Api();
m2d.page = mw.config.get(['wgArticleId', 'wgPageName']);
m2d.rationale = "Undersourced, incubate in draftspace";
m2d.editsummary = "[[WP:AFC|AFC]] draft";
m2d.notification_heading = "[[Draft:$1|$1]] moved to draftspace";
m2d.notification = "An article you recently created, [[Draft:$1|$1]], does not have enough sources and citations as written to remain published. It needs more citations from [[WP:RS|reliable]], [[WP:IS|independent sources]]. <small>([[WP:42|?]])</small> Information that can't be referenced should be removed ([[WP:V|verifiability]] is of [[WP:5|central importance]] on Wikipedia). I've moved your draft to [[Wikipedia:Draftspace|draftspace]] (with a prefix of \"<code>Draft:</code>\" before the article title) where you can incubate the article with minimal disruption. When you feel the article meets Wikipedia's [[WP:GNG|general notability guideline]] and thus is ready for mainspace, please follow the prompts on the [[Wikipedia:AfC|Articles for Creation]] template atop the page. ~~~~";
m2d.scriptad = " ([[User:Evad37/MoveToDraft.js|via script]])";

//get user-specified default rationale & notification from window object
if ( window.m2d_rationale != null ) { m2d.rationale = window.m2d_rationale; }
if ( window.m2d_editsummary != null ) { m2d.editsummary = window.m2d_rationale; }
if ( window.m2d_notification != null ) { m2d.notification = window.m2d_notification; }	

//Make error message from returned values when api fails
var makeErrorMsg = function(code, result) {
	var details = "";
	if ( code === "http" ) {
		details = "HTTP error: " + result.textStatus; // result contains the jqXHR object
	} else if ( code === "ok-but-empty" ) {
		details = "Error: Got an empty response from the server";
	} else {
		details = "API error: " + code;
	}
	return details;
};

var getPageText = function(p) {
	var t = mw.Title.newFromText( decodeURIComponent(p) );
	if (t) {
		return t.getPrefixedText();
	} else {
		return p.replace(/_/g, " ");
	}
};

// --- Api calls ---
// Grab page data - initial author, current wikitext, whether Draft:pagename already exists
var grabPageData = function() {
	
	var patt_isRedirect = /^\s*#redirect/i;
	
	//function to check if all done
	var checkPageData = function() {
		if ( m2d.author != null && m2d.oldwikitext != null ) {
			//all done - go to next screen
			screen1();
		}
	};
	
	//try making an api call or just the first revision - but if that is a redirect, then get 'max'
	//number of revisions, and look for first non-redirect revision - use this as the initial author,
	//not the creator of the redirect.
	
	var apiCallback_getAuthor_maxRvlimit = function (result) {
		var revisions = result.query.pages[m2d.page.wgArticleId].revisions;
		for ( var i=1; i<revisions.length; i++ ) {
			if ( !patt_isRedirect.test(revisions[i]['*']) ) {
				m2d.author = revisions[i].user;
				break;
			}
		}
		//Check that we actually found an author (i.e. not all revisions were redirects
		if ( m2d.author != null ) {
			checkPageData();
		} else {
			m2d.Api.abort();
			var retry = prompt("Could not retrieve page author:\n"+makeErrorMsg(c, r)+"\n\nTry again?");
			if ( retry ) {
				screen0();
			} else {
				$("#M2D-modal").remove();
			}
		}
	};
	
	var apiCallback_getAuthor = function (result) {
		// Check if page is currently a redirect
		if ( result.query.pages[m2d.page.wgArticleId].redirect ) {
			m2d.Api.abort();
			alert("Error: " + m2d.page.wgPageName + " is a redirect");
			return;
		}
		// Check if first revision is a redirect
		rvwikitext = result.query.pages[m2d.page.wgArticleId].revisions[0]['*'];
		if ( patt_isRedirect.test(rvwikitext) ) {
			//repeat query, to look for first non-redirect revision
			m2d.Api.get( {
				action: 'query',
				pageids: m2d.page.wgArticleId,
				prop: 'revisions',
				rvprop: ['user', 'content'],
				rvlimit: 'max',
				rvdir: 'newer'
			} )
			.done( apiCallback_getAuthor_maxRvlimit )
			.fail( function(c,r) {
				m2d.Api.abort();
				var retry = prompt("Could not retrieve page author:\n"+makeErrorMsg(c, r)+"\n\nTry again?");
				if ( retry ) {
					screen0();
				} else {
					$("#M2D-modal").remove();
				}
			} );
		} else {
			m2d.author = result.query.pages[m2d.page.wgArticleId].revisions[0].user;
			checkPageData();
		}
	};
	
	//Get author
	m2d.Api.get( {
		action: 'query',
		pageids: m2d.page.wgArticleId,
		prop: ['revisions', 'info'],
		rvprop: ['user', 'content'],
		rvlimit: 1,
		rvdir: 'newer'
	} )
	.done( apiCallback_getAuthor )
	.fail( function(c,r) {
		m2d.Api.abort();
		var retry = prompt("Could not retrieve page author:\n"+makeErrorMsg(c, r)+"\n\nTry again?");
		if ( retry ) {
			screen0();
		} else {
			$("#M2D-modal").remove();
		}
	} );
	
	var apiCallback_getWikitext = function(result) {
		m2d.oldwikitext = result.query.pages[m2d.page.wgArticleId].revisions[0]['*'];
		checkPageData();
	};
	

	//Get current wikitext
	//TODO: also get proposed Draft: page (to check if it is empty or not)
	m2d.Api.get( {
		action: 'query',
		pageids: m2d.page.wgArticleId,
		prop: 'revisions',
		rvprop: 'content'
	} )
	.done( apiCallback_getWikitext )
	.fail( function(c,r) {
		m2d.Api.abort();
		var retry = prompt("Could not retrieve page wikitext:\n"+ makeErrorMsg(c, r)+"\n\nTry again?");
		if ( retry ) {
			screen0();
		} else {
			$("#M2D-modal").remove();
		}
	} );
};

//Move page
var movePage = function() {
	$("#M2D-task0").css({"color":"#00F", "font-weight":"bold"});
	$("#M2D-status0").html("...");
	
	m2d.Api.postWithToken( 'csrf', {
		action: 'move',
		fromid: m2d.page.wgArticleId,
		to: m2d.newTitle,
		movetalk: 1,
		noredirect: 1,
		reason: m2d.rationale + m2d.scriptad
	} )
	.done( function() {
		$("#M2D-task0").css({"color":"#000", "font-weight":""});
		$("#M2D-status0").html("Done!");
		getImageInfo();
	} )
	.fail( function(c,r) {
		var retry = prompt("Could not move page:\n"+ makeErrorMsg(c, r)+"\n\nTry again?");
		if ( retry ) {
			movePage();
		} else {
			$("#M2D-modal").remove();
		}
	} );
};
	
//Find which images are non-free
var getImageInfo = function() {
	$("#M2D-task1").css({"color":"#00F", "font-weight":"bold"});
	$("#M2D-status1").html("...");
	
	apiCallback_getImageInfo = function(result) {
		var nonfreefiles = [];
		if ( result && result.query ) {
			var pageids = result.query.pageids;
			for ( var i=0; i<pageids.length; i++ ) {
				if ( pageids[i]>0 && result.query.pages[pageids[i]].categories ) {
					nonfreefiles.push(result.query.pages[pageids[i]].title);
				}
			}
		}
		editWikitext(nonfreefiles);
	};
	
	m2d.Api.get( {
		action: 'query',
		pageids: m2d.page.wgArticleId,
		generator: 'images',
		gimlimit: 'max',
		prop: 'categories',
		cllimit: 'max',
		clcategories: 'Category:All non-free media',
		indexpageids: 1
	} )
	.done( function(result){
		$("#M2D-task1").css({"color":"#000", "font-weight":""});
		$("#M2D-status1").html("Done!");
		apiCallback_getImageInfo(result);
	} )
	.fail( function(c,r) {
		var retry = prompt("Could not find if there are non-free files:\n"+ makeErrorMsg(c, r)+"\n\n[Okay] to try again, or [Cancel] to skip");
		if ( retry ) {
			getImageInfo();
		} else {
			$("#M2D-task1").css({"color":"#F00", "font-weight":""});
			$("#M2D-status1").html("Skipped");
			editWikitext([]);
		}
	} );	

};


//Comment out non-free files, turn categories into links, add substed afc draft template
var editWikitext = function(nonfreefiles) {
	$("#M2D-task2").css({"color":"#00F", "font-weight":"bold"});
	$("#M2D-status2").html("...");
	
	// afc, categories
	var wikitext = "{{subst:AFC draft|" + m2d.author + "}}\n" +
		m2d.oldwikitext.replace(/\[\[\s*[Cc]ategory\s*:/g, "[[:Category:");

	// non-free files
	//  (derived from [[WP:XFDC]] - https://en.wikipedia.org/wiki/User:Evad37/XFDcloser.js )
	if ( nonfreefiles.length > 0 ) {
		// Start building regex strings
		normal_regex_str = "(";
		gallery_regex_str = "(";
		free_regex_str = "(";
		for ( var i=0; i<nonfreefiles.length; i++ ) {
			// Take off namespace prefix
			filename = nonfreefiles[i].replace(/^.*?:/, "");
			// For regex matching: first character can be either upper or lower case, special
			// characters need to be escaped, spaces can be either spaces or underscores
			filename_regex_str = "[" + mw.RegExp.escape(filename.slice(0, 1).toUpperCase()) +
			mw.RegExp.escape(filename.slice(0, 1).toLowerCase()) + "]" +
			mw.RegExp.escape(filename.slice(1)).replace(/ /g, "[ _]");
			// Add to regex strings
			normal_regex_str += "\\[\\[\\s*(?:[Ii]mage|[Ff]ile)\\s*:\\s*" + filename_regex_str +
			"\\s*\\|?.*?(?:(?:\\[\\[.*?\\]\\]).*?)*\\]\\]";
			gallery_regex_str += "^\\s*(?:[Ii]mage|[Ff]ile):\\s*" + filename_regex_str + ".*?$";
			free_regex_str += "\\|\\s*(?:[\\w\\s]+\\=)?\\s*(?:(?:[Ii]mage|[Ff]ile):\\s*)?" +
			filename_regex_str;
			
			if ( i+1 === nonfreefiles.length ) {
				normal_regex_str += ")(?![^<]*?-->)";
				gallery_regex_str += ")(?![^<]*?-->)";
				free_regex_str += ")(?![^<]*?-->)";
			} else {
				normal_regex_str += "|";
				gallery_regex_str += "|";
				free_regex_str += "|";				
			}
		}

		// Check for normal file usage, i.e. [[File:Foobar.png|...]]
		var normal_regex = new RegExp( normal_regex_str, "g");
		wikitext = wikitext.replace(normal_regex, "<!-- Commented out: $1 -->");
		
		// Check for gallery usage, i.e. instances that must start on a new line, eventually
		// preceded with some space, and must include File: or Image: prefix
		var gallery_regex = new RegExp( gallery_regex_str, "mg" );
		wikitext = wikitext.replace(gallery_regex, "<!-- Commented out: $1 -->");
		
		// Check for free usages, for example as template argument, might have the File: or Image:
		// prefix excluded, but must be preceeded by an |
		var free_regex = new RegExp( free_regex_str, "mg" );
		wikitext = wikitext.replace(free_regex, "<!-- Commented out: $1 -->");
	}

	m2d.Api.postWithToken( 'csrf', {
		action: 'edit',
		pageid: m2d.page.wgArticleId,
		text: wikitext,
		summary: m2d.editsummary + m2d.scriptad
	} )
	.done( function(){
		$("#M2D-task2").css({"color":"#000", "font-weight":""});
		$("#M2D-status2").html("Done!");
		notifyAuthor();
	} )
	.fail( function(c,r) {
		var retry = prompt("Could not edit draft artice:\n"+ makeErrorMsg(c, r)+"\n\n[Okay] to try again, or [Cancel] to skip");
		if ( retry ) {
			editWikitext(nonfreefiles);
		} else {
			$("#M2D-task2").css({"color":"#F00", "font-weight":""});
			$("#M2D-status2").html("Skipped");
			notifyAuthor();
		}
	} );
	
};

var notifyAuthor = function() {
	$("#M2D-task3").css({"color":"#00F", "font-weight":"bold"});
	$("#M2D-status3").html("...");
	
	//TODO
	m2d.Api.postWithToken( 'csrf', {
		action: 'edit',
		title: 'User talk:' + m2d.authorName,
		section: 'new',
		sectiontitle: m2d.notifyMsgHead,
		text: m2d.notifyMsg,
	} )	
	.done( function(){
		$("#M2D-task3").css({"color":"#000", "font-weight":""});
		$("#M2D-status3").html("Done!");
		updateTalk();
	} )
	.fail( function(c,r) {
		var retry = prompt("Could not edit author talk page:\n"+ makeErrorMsg(c, r)+"\n\n[Okay] to try again, or [Cancel] to skip");
		if ( retry ) {
			notifyAuthor();
		} else {
			$("#M2D-task3").css({"color":"#F00", "font-weight":""});
			$("#M2D-status3").html("Skipped");
			updateTalk();
		}
	} );
};

var updateTalk = function() {
	$("#M2D-task4").css({"color":"#00F", "font-weight":"bold"});
	$("#M2D-status4").html("...");

	//if page exists, do a regex search/repace for class/importances parameters
	var apiCallback_getTalkWikitext = function(result) {
		var talk_id = result.query.pageids[0];
		if ( talk_id < 0 ) {
			$("#M2D-task4").css({"color":"#000", "font-weight":""});
			$("#M2D-status4").html("Done (talk page does not exist)");
			$("#M2D-finished, #M2D-abort").toggle();
			return;
		}
		var old_talk_wikitext = result.query.pages[talk_id].revisions[0]['*'];
		var new_talk_wikitext = old_talk_wikitext.replace(/(\|\s*(?:class|importance)\s*=\s*)[^\|}]*(?=[^}]*}})/g, "$1");
		if ( new_talk_wikitext === old_talk_wikitext ) {
			$("#M2D-task4").css({"color":"#000", "font-weight":""});
			$("#M2D-status4").html("Done (no changes needed)");
			$("#M2D-finished, #M2D-abort").toggle();
			return;
		}

		m2d.Api.postWithToken( 'csrf', {
			action: 'edit',
			pageid: talk_id,
			section: '0',
			text: new_talk_wikitext,
			summary: 'Remove class/importance from project banners' + m2d.scriptad
		} )
		.done( function(){
			$("#M2D-task4").css({"color":"#000", "font-weight":""});
			$("#M2D-status4").html("Done!");
			$("#M2D-finished, #M2D-abort").toggle();
		} )
		.fail( function(c,r) {
			var retry = prompt("Could not edit draft's talk page:\n"+ makeErrorMsg(c, r)+"\n\n[Okay] to try again, or [Cancel] to skip");
			if ( retry ) {
				updateTalk();
			} else {
				$("#M2D-task4").css({"color":"#F00", "font-weight":""});
				$("#M2D-status4").html("Skipped");
				$("#M2D-finished, #M2D-abort").toggle();
			}
		} );		
		
	};	
	
	//get talk page wikitext (section 0)
	m2d.Api.get( {
		action: 'query',
		titles: m2d.newTitle.replace("Draft:", "Draft talk:"),
		prop: 'revisions',
		rvprop: 'content',
		rvsection: '0',
		indexpageids: 1
	} )
	.done( apiCallback_getTalkWikitext )
	.fail( function(c,r) {
		var retry = prompt("Could not find draft's talk page:\n"+ makeErrorMsg(c, r)+"\n\n[Okay] to try again, or [Cancel] to skip");
		if ( retry ) {
			updateTalk();
		} else {
			$("#M2D-task4").css({"color":"#F00", "font-weight":""});
			$("#M2D-status4").html("Skipped");
			$("#M2D-finished, #M2D-abort").toggle();
		}
	} );
	
};

// --- Interface screens ---
//0) Initial screen
var screen0 = function() {
	$("#M2D-interface-header").html("Move To Draft...");
	$("#M2D-interface-content").html("Loading...");
	grabPageData();
};

//1) User inputs
var screen1 = function() {
	$("#M2D-interface-header").html("Move To Draft: options");
	
	$("#M2D-interface-content").html(
		'<label for="M2D-option-newtitle">Move to <b>Draft:</b></label>'+
		'<input type="text" name="M2D-option-newtitle" id="M2D-option-newtitle" /><br/><br/>'+
		'<label for="M2D-option-author" id="M2D-option-author-label">Author:</label>'+
		'<input type="text" name="M2D-option-author" id="M2D-option-author" /><br/><br/>'+
		'<label for="M2D-option-message-head" id="M2D-option-message-head-label">Notification heading:</label><br/>'+
		'<textarea id="M2D-option-message-head" rows=1 style="width:99%;" /><br/>'+
		'<label for="M2D-option-message" id="M2D-option-message-label">Notification message:</label><br/>'+
		'<textarea id="M2D-option-message" rows=6 style="width:99%;" />'
		//TODO(?): Move rationale and edit summary text inputs
	);
	
	$('#M2D-option-newtitle').val(getPageText(m2d.page.wgPageName));
	$('#M2D-option-author').val(m2d.author);
	$('#M2D-option-message-head').val(m2d.notification_heading.replace(/\$1/g, getPageText(m2d.page.wgPageName)));
	$('#M2D-option-message').val(m2d.notification.replace(/\$1/g, getPageText(m2d.page.wgPageName)));
	
	$("#M2D-interface-footer").html(
		'<button id="M2D-next">Continue</button><button id="M2D-cancel" style="margin-left:3em;">Cancel</button>'
	);

	$("#M2D-cancel").click(function(){
		$("#M2D-modal").remove();
	});
		
	$("#M2D-next").click(function(){
		//Gather inputs
		m2d.newTitle = "Draft:" + $('#M2D-option-newtitle').val().trim();
		m2d.authorName = $('#M2D-option-author').val().trim();
		m2d.notifyMsgHead = $('#M2D-option-message-head').val().trim();
		m2d.notifyMsg = $('#M2D-option-message').val().trim();
		
		//Verify inputs
		var errors=[];
		if ( m2d.newTitle.length === 0 ) {
			errors.push("Invalid draft title");
		}
		if ( m2d.authorName.length === 0 ) {
			errors.push("Invalid user name");
		}
		if ( m2d.notifyMsgHead.length === 0 ) {
			errors.push("Notification heading is empty");
		}
		if ( m2d.notifyMsg.length === 0 ) {
			errors.push("Notification message is empty");
		}
		if ( errors.length >= 1 ) {
			alert("Error:\n\n" + errors.join(";\n"));
			return;
		}
		
		//start process off
		screen2();
	});

};

//2) Progress indicators	
var screen2 = function() {
	$("#M2D-interface-header").html("Move To Draft: In progress...");
	$("#M2D-interface-content").html(
	'<ul id="M2D-tasks">'+
		'<li id="M2D-task0">Moving page... <span id="M2D-status0">(waiting)</span></li>'+
		'<li id="M2D-task1">Checking images... <span id="M2D-status1">(waiting)</span></li>'+
		'<li id="M2D-task2">Editing page wikitext... <span id="M2D-status2">(waiting)</span></li>'+
		'<li id="M2D-task3">Notifying author... <span id="M2D-status3">(waiting)</span></li>'+
		'<li id="M2D-task4">Updating talk page banners... <span id="M2D-status4">(waiting)</span></li>'+
	'</ul>'	
	);
	$("#M2D-tasks").css("color", "#888");
	
	$("#M2D-interface-footer").html(
		'<button id="M2D-abort">Abort uncompleted tasks</button>'+
		'<span id="M2D-finished">Finished! <button id="M2D-close">Close</button></span>'
	);
	$("#M2D-finished").hide();
	$("#M2D-close").click( function(){
		$("#M2D-modal").remove();
		window.location.reload();
	} );
	$("M2D-abort").click( function(){
		m2d.Api.abort();
		$("#M2D-modal").remove();
		window.location.reload();
	} );
		
	//Start task 0. The rest are done sequentially as each task is completed (or skipped).
	movePage();
};

// --- Add link to 'More' menu which starts everything ---
mw.util.addPortletLink( 'p-cactions', '#', 'Move to draft', 'ca-m2d', null, null, "#ca-move");
$('#ca-m2d').on('click', function(e) {
	e.preventDefault();
	// Add interface shell
	$('body').prepend('<div id="M2D-modal">'+
		'<div id="M2D-interface">'+
			'<h4 id="M2D-interface-header"></h4>'+
			'<hr>'+
			'<div id="M2D-interface-content"></div>'+
			'<hr>'+
			'<div id="M2D-interface-footer"></div>'+
		'</div>'+
	'</div>');
	
	// Interface styling
	$("#M2D-modal").css({
		"position": "fixed",
		"z-index": "1",
		"left": "0",
		"top": "0",
		"width": "100%",
		"height": "100%",
		"overflow": "auto",
		"background-color": "rgba(0,0,0,0.4)"
	});
	$("#M2D-interface").css({
		"background-color": "#f0f0f0",
		"margin": "15% auto",
		"padding": "2px 20px",
		"border": "1px solid #888",
		"width": "80%",
		"max-width": "60em",
		"font-size": "90%"
	});
	$("#M2D-interface-content").css("min-height", "7em");
	$("#M2D-interface-footor").css("min-height", "3em");
		
	// Initial interface content
	screen0();
});



// End of function moveToDraft
};

// Only operate in article and user namespaces
if( mw.config.get('wgNamespaceNumber') === 0 ) {
	mw.loader.using( ['mediawiki.util', 'mediawiki.api', 'mediawiki.Title', 'mediawiki.RegExp'], moveToDraft() );
} else {
	//console.log("[M2D] not namespace 0");
}

});
// </nowiki>