User:Gryllida/DraftsReview/v2.js

// var afch2 = { script_home: 'User:Gryllida/DraftsReview/v2.js' // subst:FULLPAGENAME in double {}s }; /* **************************************************************************** function bugOut{ Log('Could not complete. Please see query error above. Sorry. :-(',0); } function finishOK{	Log('Done. :-)',0); } // Log (MESSAGE, [BUTTONS_DISABLED_STATE]) function Log(msg, propDisabled){ $('#afch2Log').val($('#afch2Log').val + msg + '\r\n'); if(typeof propDisabled != 'undefined'){ $('#afch2Box').prop('disabled',propDisabled); /*$('#afch2ApproveButton').prop('disabled',propDisabled); $('#afch2CancelButton').prop('disabled',propDisabled); $('#afch2DeclineButton').prop('disabled',propDisabled);*/ } } /* **************************************************************************** // Gets meaningful content from the query. function understandJson(data){ var page, wikitext; if(data.edit && data.edit.result == 'Success'){ // An edit was ok		return true; }   if(data.move){ // A move was ok		return true; }   if(!data.query){ // We really need this for a read query return false; }   for (page in data.query.pages) { if(!data.query.pages[page].revisions){ // We also really need this for a read query return false; }           res = data.query.pages[page].revisions[0]['*']; return res; } } /* **************************************************************************** function Contributor(name) { this.name = name; } Contributor.prototype.notify = function(page){ var template = page.isApproved ? 'Afc talk' : 'Afc decline'; var humanStatus = page.isApproved ? 'passed' : 'not ready'; var pageName = page.name.replace(/_/g,' '); var subject = pageName.replace('Wikipedia talk:Articles for creation/',''); var sectionTitle = ''+pageName+' ( revision '+ page.revid+' )'; var talkPage = new Page('User talk:'+this.name); return talkPage.query(1,{		content: +subject+,		summary: ''+page.name+': '+humanStatus,		section: 'new',		sectionTitle: sectionTitle	}); }; /* **************************************************************************** function Page(name) { this.name = name; this.revid = mw.config.get('wgCurRevisionId'); } Page.prototype.query = function(actionType, info, stopNagging) { console.log('processing page ' + this.name); var dfd = $.Deferred, self = this; var query; console.log('setting up query for this action type'); switch (actionType){ case 0: query = this.readQuery(info); break; case 1: query = this.editQuery(info); break; case 3: query = this.moveQuery(info); break; }	console.log('done'); // If the query fails, the check failed. query.fail( function(data){ 		if(!stopNagging){			Log("Couldn't query " + self.name + " (Action type " + actionType + ")");		}		dfd.reject;	}); query.then( function ( data ) {		console.log('I got data.');		console.log(data);		var result = understandJson(data);		if (!result) {			if(!stopNagging){				Log("Got error with query " + self.name + " (Action type " + actionType + ")");				Log(JSON.stringify(data,null,4));			}			dfd.reject(data);		} else { 			dfd.resolve(result);		}	} ); // calling .promise makes the object 'read-only'; only we can resolve / // reject this deferred. it's not necessary to do but it's a nice way of // indicating which piece of code is responsible for some operation. return dfd.promise; }; Page.prototype.readQuery = function(info){ var hash = { format: 'json', action: 'query', prop:   'revisions', rvprop: 'content', rvlimit: 1, titles: this.name, };       if (info && typeof info.sectionNum != 'undefined'){ hash.rvsection=info.sectionNum; }       var promise = $.getJSON(mw.util.wikiScript('api'),hash); return promise; }; // content - target page content // summary - target page summary // section - section number // sectionTitle - section title Page.prototype.editQuery = function(info){ var hash = { url: mw.util.wikiScript( 'api' ), type: 'POST', dataType: 'json', data: { format: 'json', action: 'edit', title: this.name, text: info.content, // will replace entire page content summary: info.summary + ' (see other submissions; semi-automated)', token: mw.user.tokens.get( 'editToken' ) }       };        if (typeof info.section != 'undefined'){ hash.data.section=info.section; }       if (typeof info.sectionTitle != 'undefined'){ hash.data.sectiontitle=info.sectionTitle; }       var promise = $.ajax(hash); return promise; }; Page.prototype.moveQuery = function(info){ fromName = this.name; toName = info.to; this.name=toName; return $.ajax({		url: mw.util.wikiScript( 'api' ),		type: 'POST',		dataType: 'json',		data: {			format: 'json',			action: 'move',			from: fromName,			to: toName,			reason: 'ready (see other submissions)',			token: mw.user.tokens.get( 'editToken' )		}	}); }; /* **************************************************************************** // Decline the page Page.prototype.decline = function{ var self=this; Log('Declining... ',1); this.isApproved=0; // Grab the page markup and work on it	this.query(0) .then(self.processMarkupToDecline.bind(self)) .fail(bugOut); }; Page.prototype.processMarkupToDecline=function(data){ Log('... retrieved the page markup ...'); var markup = new MarkUp(data); // Remove all review pending templates (or exit if there are none) if(!markup.clean){ Log('Article not in queue. Sorry. :-(',0);		return false;	}	// Add review comment into the markup	markup.decline;	contributor = new Contributor(markup.submitterName);	// Save the article with the processed markup (w/ review comment)	Log('... processed markup for declining, trying to save the article ...');	$.when( this.query(1, {			title: this.name,			content: markup.data,			summary: 'draft not ready'		}), contributor.notify(this) )	.done(finishOK)	.fail(bugOut); }; // Comment on the page Page.prototype.comment = function{	var self=this;	Log('Commenting... ',1);	// Grab the page markup and work on it	this.query(0)	.then(self.processMarkupToComment.bind(self))	.fail(bugOut); }; Page.prototype.processMarkupToComment=function(data){	Log('... retrieved the page markup ...');	var markup = new MarkUp(data,this);	var summary = $('#afch2CommentSummary').val;	markup.comment; // uses $('#reviewBox').val	$.when( this.query(1, {		title: this.name,		content: markup.data,		summary: '+comment (' + summary + ')'		}) )	.done(finishOK)	.fail(bugOut); }; // Approve the page Page.prototype.approve = function{	var self=this;	Log('Approving... ',1);	this.isApproved=1;	// Grab the page markup and work on it	this.query(0)	.then(self.processMarkupToApprove.bind(self))	.fail(bugOut); }; Page.prototype.processMarkupToApprove=function(data){	Log('... retrieved the page markup ...');	var markup = new MarkUp(data,this);	var targetName = $('#afch2TargetPageName').val;	var self=this;	// Remove all review pending templates (or exit if there are none)	if(!markup.clean){		Log('Article not in queue. Sorry. :-(',0);		return false; }	// Add review comment into the markup markup.extractComments; this.query(3,{			to: targetName	}).then(self.postMoveProcess.bind(markup)) .fail(bugOut); }; Page.prototype.postMoveProcess = function{ newTalk = new Page('Talk:' + this.page.name); contributor = new Contributor(this.submitterName); $.when(		newTalk.query(1, { content: this.talk, summary: 'creation from Draft discussion', section: 'new', sectionTitle: 'Draft discussion' }),		this.page.query(1, { content: this.data, summary: 'move of discussion to the talk page', }),		contributor.notify(this.page)	).then(finishOK) .fail(bugOut); }; /* **************************************************************************** // Construct a new MarkUp object function MarkUp(data,page){ this.data = data; this.page=page; } MarkUp.prototype.comment = function{ var comment = $('#reviewBox').val ; comment = ""; this.data = comment + "\r\n" + this.data; return true; }; /* * Remove all 'review pending' tags from the MarkUp object * Also place the oldest (valuable! :) review-pending tag * into this.template_res, for later processing */ MarkUp.prototype.clean = function{ var data = this.data; // Find all 'review pending' templates on the page var templates = this.data.match(//gmi); // Exit if no review pending is marked on the page if (templates == null){ return false; }	// Find the oldest 'review pending' teplace on the page; also, remove them all. var ts_min = Infinity; var template_res=''; $(templates).each( function (index, template){ // template = '@FC submission|||ts=20140113103528|u=Daniels Wembley|ns=2'		ts = template.replace(,).split('|')[3].replace('ts=',);		if (ts<ts_min){			ts_min = ts;			template_res = template;		}		data = data.replace(template, );	}); // Remove boiletplate data = data.replace('== Request review at WP:AFC ==',''); data = data.replace(/<!-- Just press the "Save page" button below without .*/,''); // Save template for processing this.data=data; this.template_res = template_res; // Break the submit template into pieces this.values = this.template_res.replace(,).split('|'); // Retrieve the username of the submitter this.submitterName = this.values[4].replace('u=',''); // Exit return true; }; MarkUp.prototype.extractComments = function{ var data = this.data; var talk = ''; if($('#afch2PrjName').val){ talk += '\n'; }	// Find all AFC templates on the page and remove them var templates = this.data.match(//gmi); $(templates).each( function (index, template){		data = data.replace(template, '');		talk += template;		talk += '\r\n';	}); talk+="Approved. --~\r\n"; // Save template for processing this.data=data; this.talk = talk; // Exit return true; }; MarkUp.prototype.decline = function{ // Submit template pieces var values = this.values; // 'd' as first value: Decline values[1]='d'; // 'reason' as second value: Review type ('cv', 'npov', other types exist; not implemented) values[2]='reason'; // Add 3=, declinets, decliner params - no place for them, kick around values.splice(3,0,		'3 = ' + $('#reviewBox').val,		'declinets=',		'decliner=' + mw.config.get('wgUserName')); this.template_res = ''; // Prepend the declined template to the page. this.data = this.template_res + '\r\n' + this.data; return true; }; /* **************************************************************************** // Construct DOM object function DOM{ // Load HTML from subpage Log('Making DOM...'); this.subPage = new Page(afch2.script_home+'/text'); this.page = new Page(mw.config.get('wgPageName')); this.query = this.subPage.query(0, {sectionNum: 0}); } // Hide things and set events as necessary in the DOM DOM.prototype.setUp = function{ var page = this.page; // Hide everything $('afch2Log').hide; $('#afch2Box').hide; $('#afch2ApproveBox').hide; $('#afch2DeclineBox').hide; $('#afch2CommentBox').hide; // Set events //$("#reviewCans").change( function {afch2.dom.insertCannedResponse;}); $('#afch2DeclineButton').click(page.decline.bind(page)); $('#afch2ApproveButton').click(page.approve.bind(page)); $('#afch2CommentButton').click(page.comment.bind(page)); $('#afch2ApprovePageCheck').click(pageCheck); $("#reviewCans").change(insertCannedResponse); $('#afch2CancelButton').click(function{		$('#afch2Box').hide;	}); }; function pageCheck{ $('#afch2ApprovePageCheck').prop('disabled',true); var targetPage = new Page($('#afch2TargetPageName').val); targetPage.query(0,{},1) .then(function{		$('#afch2ApproveButton').prop('disabled',true);	}).fail(function{		$('#afch2ApproveButton').prop('disabled',false);	}).always(function{		$('#afch2ApprovePageCheck').prop('disabled',false);	}); } DOM.prototype.fillInReviewBox = function(data){ var lines = data.split('\n'); lines.shift; $('#reviewBox').val(lines.join('\n')); Log('... filled in the review box. :-)'); }; DOM.prototype.fillInCannedResponses = function(data){	var lines = data.split('\n');	lines.shift;	// Process group, name, and content from each line	$(lines).each(function( i, line ) { group = line.split(':')[0]; name = line.split(':')[1]; content = line.split(':').slice(2).join(':'); // Create optgroup if it doesn't yet exist if($('#reviewCans optgroup[label="'+group+'"]').html == null){ $(' ', {				label: group			}).appendTo('#reviewCans'); }		// Add the option to the relevant optgroup $(' ', {			html: name,			value: content		}).prependTo('#reviewCans optgroup[label="'+group+'"]'); });	Log('... filled in the canned responses. :-)'); }; DOM.prototype.fillIn = function{ var self=this; Log('... filling in DOM ...'); this.subPage.query(0, {sectionNum: 1}) .then(self.fillInReviewBox) .fail(bugOut); this.subPage.query(0, {sectionNum: 2}) .then(self.fillInCannedResponses) .fail(bugOut); }; function insertCannedResponse { var caretPos = document.getElementById("reviewBox").selectionStart; var textAreaTxt = $("#reviewBox").val; var txtToAdd = $( "#reviewCans" ).val; $("#reviewBox").val(textAreaTxt.substring(0, caretPos) + txtToAdd + textAreaTxt.substring(caretPos) ); } DOM.prototype.only_show = function(id){ $('#afch2Box').toggle; $('#afch2ApproveBox').hide; $('#afch2DeclineBox').hide; //$('#afch2CommentBox').hide; $('#' + id).show; }; /* **************************************************************************** // Wait for the page to be parsed $(document).ready( function { 	// Adds review tab	var linkA = mw.util.addPortletLink( 'p-cactions', '#', 'Approve', 'ca-afch2-approve', 'AFC Approve');	var linkD = mw.util.addPortletLink( 'p-cactions', '#', 'Decline or comment', 'ca-afch2-decline', 'AFC Decline');	//var linkC = mw.util.addPortletLink( 'p-cactions', '#', 'Comment', 'ca-afch2-comment', 'AFC Comment');	console.log('Making dom object');	var dom = new DOM;	console.log('Made dom object');	dom.query.then(function(data){ console.log('Added in the html'); $(data).prependTo('#content'); dom.setUp; console.log('dom set up'); dom.fillIn; console.log('dom filled in'); }).fail(bugOut);	// Assigns actions to the tabs	$( linkA ).click( function ( event ) { event.preventDefault; dom.only_show('afch2ApproveBox'); } );	$( linkD ).click( function ( event ) { event.preventDefault; dom.only_show('afch2DeclineBox'); } );	//$( linkC ).click( function ( event ) { //	event.preventDefault; //	dom.only_show('afch2CommentBox'); //} ); } ); //
 * General Log functions ********************************************
 * Query functions **************************************************
 * Contributor functions ********************************************
 * Page functions ***************************************************
 * Page functions: review *******************************************
 * MarkUp functions *************************************************
 * DOM functions ****************************************************
 * Document onload routine ******************************************