MediaWiki:FulfillEditRequest.js

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
/**
* Script for fulfilling edit requests
*
* @revision 10:43, 14 October 2019 (UTC)
* @rev 1 (2015-01-26); rev 2 (2017-10-29)
* @author Rillke 2015, Perhelion 2018
* TODO: better user select
*/
// <nowiki>
/* eslint indent:[error,tab,{outerIIFEBody:0}] */
/* eslint-disable vars-on-top, no-alert, max-statements-per-line*/

(function ($, mw) {
'use strict';

mw.libs.commons = mw.libs.commons || {};
var conf = mw.config.get(['wgAction', 'wgTitle', 'wgNamespaceNumber']),
	FER = { erTemplates: ['Edit request'] };

mw.libs.commons.fulfillEditRequest = FER = {
	$adminAreas: null,
	subjectAbsent: false,
	erTemplates: FER.erTemplates,
	regExp: null,
	templatedEditRequestBox: '<code>{{<a title="Template:' + FER.erTemplates[0] + '" \
		href="/wiki/Template:Edit_request">' + FER.erTemplates[0] + '</a>}}</code>',

	install: function ($content) {
		if (conf.wgAction !== 'view' || conf.wgNamespaceNumber % 2 !== 1)
			return;

		FER.$adminAreas = $content.find('.com-edit-request-admin-area');
		if (!FER.$adminAreas.length)
			return;

		mw.loader.using(['jquery.ui'], FER.createUI);
	},

	getRegExp: function () {
		var escRE = [];
		if (FER.regExp)
			return FER.regExp;

		FER.erTemplates.forEach(function (txt, i) {
			escRE[i] = mw.util.escapeRegExp(txt);
		});
		// Needs very strict because the very short "Ep" could also be an alias.
		return (FER.regExp = new RegExp('^(?:' + escRE.join('|') + ') *$', 'i'));
	},

	queryRedirects: function (cb) {
		mw.libs.commons.api.query({
			action: 'query',
			generator: 'backlinks',
			gblfilterredir: 'redirects',
			prop: 'revisions',
			gblnamespace: 10,
			gbltitle: 'Template:' + FER.erTemplates[0]
		}, { cb: function (r) {
			if ((r = r.query) && (r = r.pages)) {
				for (var id in r) {
					var pg = r[id];
					if (pg.title)
						FER.erTemplates.push(pg.title.replace('Template:', ''));

				}
			}
			if (typeof cb === 'function')
				cb();

		}
			// errCb: function (t, r, q) {}
		});
	},

	evt: {
		markDone: function (e) {
			e.preventDefault();
			var $button = $(this),
				$editRequestBox = $button
					.closest('.com-edit-request-admin-area'),
				index = FER.$adminAreas.index($editRequestBox),
				section = FER.$adminAreas.prevObject.find('.mw-headline').
							siblings('.mw-editsection').find('a').prop('href')
							.match(/section=(\d+)/)[1];
			if (!section)
				alert('Section not found!');

			mw.loader.using([
				'mediawiki.util',
				'ext.gadget.jquery.blockUI',
				'ext.gadget.libAPI',
				'ext.gadget.libWikiDOM'
			], function () {
				$button.parent().block();
				FER.queryRedirects(
					function () {
						FER.markDone(
							new mw.Title(conf.wgTitle, conf.wgNamespaceNumber)
								.getPrefixedText(),
							index,
							function (success) {
								$button.parent().unblock();
								if (success) {
									// There can be more edit requests so reload is needed,
									// also other fails can't be recognized
									document.location.reload();
								/* $editRequestBox
								.closest('.com-edit-request')
								.hide()
								.after(FER.templatedEditRequestBox);*/
								}
							},
							section);
					});
			});
		},

		createWith: function (/* e*/) {
			var $button = $(this),
				$ta = $button.data('com-fer-create-text'),
				$wrap = $button.parent(),
				user = FER.revisionUser($wrap.closest('.com-edit-request-admin-area')),
				newText = $ta.val();

			mw.loader.using([
				'ext.gadget.jquery.blockUI',
				'ext.gadget.libAPI',
				'mediawiki.Title'
			], function () {
				$wrap.block();
				FER.createPage(
					new mw.Title(conf.wgTitle, conf.wgNamespaceNumber - 1)
						.getPrefixedText(),
					newText,
					'Fulfilling edit request originating talk page ' +
						'whose last editor is [[User:' + user + '|' + user + ']]',
					function (success) {
						$wrap.unblock();
						if (success) {
							$wrap.delay(700).fadeOut();
							FER.$subjectTab.removeClass('new');
						}
					});
			});
		},

		createLink: function (e) {
			e.preventDefault();
			var $a = $(this),
				$adminArea = $a.closest('.com-edit-request-admin-area'),
				user = FER.revisionUser($adminArea),
				// Unsure fallback only
				lastUser = $adminArea.parent().find('.com-edit-request-revision-user').eq(0).text();
				// Replace unsure default link
			if (user && lastUser !== user) {
				$a.attr('href', function (i, v) {
					lastUser = encodeURIComponent(lastUser + '|' + lastUser);
					user = encodeURIComponent(user);
					return v.replace(lastUser, user);
				});
			}
		}
	},

	/**
	* @brief Get requesting user per DOM
	* @details Searches the first line with a user link and take the last.
	*
	* @param      {node}   $box     $adminArea
	* @return     {string} username
	*/
	revisionUser: function ($box) {
		$box = $box.parent();
		/* TODO: The search is only sure if the template is before a linked user sig,
		* so check also backward to a headline!?
		* Better replace with revisions finder like in AQD.findTemplateAdder FER.regExp
		*/
		var lines = $box.nextAll(),
			reUser;
		$.each(lines, function (i, v) {
			v = $(v);
			var links = v.find('a[href^="/wiki/User"]');
			if (!links[0])
				return;

			v = v.contents().toArray();
			for (var a = links.length - 1, m; a > 0; a--) {
				var c = 0;
				a = links.eq(a);
				m = a.attr('href');
				if (!m)
					continue;

				m = m.match(/^\/wiki\/User(?:[ _]talk)?:([^\n]+)/);
				if (m && m[1]) {
					for (var t = v.length - 1, n; t > 0; t--) {
						n = v[t];
						if (c > 5)
							break;

						c++;
						// Take user link if with date
						if (/\d{4} \(UTC\)[^\d]*?$/.test($(n).text())) {
							reUser = m[1];
							reUser = /\//.test(reUser) ? reUser.split('/')[0] : reUser;
							break;
						}
					}
					if (reUser)
						return false;

				}
			}
		});

		reUser = reUser || $box.find('.com-edit-request-revision-user').eq(0).text(); // fallback revisions-user
		return reUser.replace('_', ' ');
	},

	createPage: function (title, content, summary, cb) {
		mw.libs.commons.api.editPage({
			title: title,
			text: content,
			editType: 'text',
			createonly: true,
			summary: summary,
			cb: function () {
				cb(true);
			},
			errCb: function (e) {
				mw.log.warn(e);
				alert('Page could not be created; edit failed.');
				cb();
			}
		});
	},

	markDone: function (title, index, cb, section) {
		mw.libs.commons.api.$changeText(title, function (content) {
			var parsed = mw.libs.wikiDOM.parser.text2Obj(content),
				user = decodeURI(FER.revisionUser(FER.$adminAreas.eq(index))),
				replaced,
				nodes = parsed.nodesByType,
				ssection = '',
				regExp = FER.regExp || FER.getRegExp();

			$.each(nodes.template || [], function (i, erNode) {
				if (regExp.test(erNode.parts[0][0])) {
					// if (index-- === 0) { // Why count and only first request?
					erNode.prepend('tl');
					FER.addThanks(parsed, erNode);
					replaced = true;
					return false;
					// }
				}
			});
			if (!replaced) {
				alert('Could not find edit request template.\n' +
						'Please report this incident on: ' +
						'[[MediaWiki:FulfillEditRequest.js]]');
				return cb();
			}

			if (nodes.h && nodes.h[0]) {
				ssection = nodes.h[0].parts[0][0];
				ssection = (ssection && /(=+)(\s?[^\n]+\s?)\1/.test(ssection)) ? '/*' + RegExp.$2 + '*/ ' : '';
			}

			return {
				text: mw.libs.wikiDOM.parser.obj2Text(parsed),
				summary: ssection + 'Marking edit request as done. @' +
					'[[User:' + user + '|' + user + ']]'
			};
		}, section).done(function () {
			cb(true);
		}).fail(function (e) {
			mw.log.warn(e);
			alert('Could not mark edit request as done; edit failed.');
			cb();
		});
	},

	addThanks: function (rootNode, erNode) {
		var text = window.prompt('Confirm the reply:', '{{done}} Awesome! Thank you! ~~~~'),
			foundErNode,
			addToThis,
			addToThisIdx;
		if (!text) {
			if (text === '')
				return;

			throw new Error('Confirm canceled');
		}
		text = '\n:' + text + '\n';
		$.each(rootNode.parts[0], function (i, node) {
			if (node === erNode)
				foundErNode = true;

			if (node.type === 'h' && foundErNode)
				return false;

			addToThis = node;
			addToThisIdx = i;
		});
		if (typeof addToThis.after === 'function')
			addToThis.after(text);
		 else
			rootNode.parts[0][addToThisIdx] += text;

	},

	$getUI: function () {
		var $ui = $('<div>').addClass('com-fer-main'),
			$createPageWrap,
			$createPageText;
		$('<button>')
			.text('Mark request as done')
			.attr({
				type: 'button',
				role: 'button'
			})
			.button({ icons: { primary: 'ui-icon-check' } })
			.addClass('com-fer-mark-done')
			.on('click', FER.evt.markDone)
			.appendTo($ui);

		if (FER.subjectAbsent) {
			$createPageWrap = $('<div>').appendTo($ui);
			$createPageText = $('<textarea>')
				.css({
					'width': '100%',
					'height': '5em',
					'box-sizing': 'border-box'
				})
				.attr({ placeholder: 'Create page with this content ...' })
				.addClass('com-fer-create-text')
				.appendTo($createPageWrap);
			$('<button>')
				.text('Create')
				.attr({
					type: 'button',
					role: 'button'
				})
				.button({ icons: { primary: 'ui-icon-document' } })
				.addClass('com-fer-create-button')
				.data('com-fer-create-text', $createPageText)
				.on('click', FER.evt.createWith)
				.appendTo($createPageWrap);
		}
		return $ui;
	},

	createUI: function () {
		FER.$subjectTab = $('#p-namespaces li[id^="ca-nstab"]');
		FER.subjectAbsent = FER.$subjectTab.hasClass('new');
		FER.$adminAreas.each(function (i, el) {
			el = $(el);
			if (el.data('com-fer-enhanced'))
				return;

			el.append(FER.$getUI()).data('com-fer-enhanced', 1);
			el.find('a.external').one('mouseover', FER.evt.createLink);
		});
	}
};

mw.hook('wikipage.content').add(FER.install);

}(jQuery, mediaWiki));
// </nowiki>