User:Mikevoir/betterDiff.js

$(function {   // Load dependencies and cache    importScriptPage('User:Mikevoir/lib.js', 'community');	var lib;	var api = new mw.Api;	var config = mw.config.get(['wgDiffNewId', 'wgAction', 'wgCanonicalSpecialPageName']);	// Main class	var betterDiff = {		init: function {			// Each mutation array represents a reload (e.g., through filter change)			var newDiffLinkReload = new MutationObserver(function (mutations, me) { if (					mutations[0] &&					mutations[0].target &&					mutations[0].target.classList.contains('mw-rcfilters-ui-changesListWrapperWidget')				) {betterDiff.newDiffLink;} });			// Check we're in Special:RecentChanges			if (config.wgCanonicalSpecialPageName == 'Recentchanges') {				lib.waitFor('.mw-changeslist div', function{ betterDiff.newDiffLink; betterDiff.quickDiff; lib.waitFor('.mw-rcfilters-ui-filterWrapperWidget-top', function {						mw.user.getGroups(betterDiff.userPatrol);					}); document.addEventListener('click', function(event){						if (event.target && (event.target.classList.includes('mw-changeslist-groupdiff') || event.target.classList.includes('mw-changeslist-diff'))) {							event.preventDefault;						}					}); // start observing newDiffLinkReload.observe(document.querySelector('.mw-changeslist'), {					 childList: true,					  subtree: true					}); });			}			// Check we're in Special:Contributions			else if (config.wgCanonicalSpecialPageName == 'Contributions') {				lib.waitFor('ul.mw-contributions-list li', function{ betterDiff.newDiffLink; // start observing newDiffLinkReload.observe(document.querySelector('ul.mw-contributions-list'), {					 childList: true,					  subtree: true					}); });			}			// Check we're in a history page			else if (config.wgAction == 'history') {				lib.waitFor('.mw-history-histlinks', betterDiff.newDiffLink);			}			// Check we're in a diff page			else if (config.wgDiffNewId) {				lib.waitFor('#mw-diff-ntitle1', betterDiff.newDiff);			}		},		// Properly build diff links with page creation edits		newDiffLink: function {			var newDiffLink = {				searchRevid: function (row) {					var O = {						row: row,						revid: []					};					// Special:Contributions					if ( O.row.nodeName == 'LI' && O.row.getAttribute('data-mw-revid')) { 						O.revid.push(O.row.getAttribute('data-mw-revid')); // Page creation revision					// Special:RecentChanges					} else {						// sole edit						if (O.row.getAttribute('data-mw-revid')) { 							O.revid.push(O.row.getAttribute('data-mw-revid'));						// Top edit						} else if (O.row.classList.contains('mw-rcfilters-ui-highlights-enhanced-toplevel')) { O.revid.push(O.row.nextElementSibling.getAttribute('data-mw-revid')); // Last revision O.revid.push(O.row.parentElement.lastElementChild.getAttribute('data-mw-revid')); // Page creation revision }					}					if (O.revid.length>0) { return newDiffLink.buildLink(O); } else { return; }				},				buildLink: function(options) { var target = newDiffLink.getTarget(options.row); var page = newDiffLink.getTitle(options.row); if (target) { var link = document.createElement('a'); var from = options.revid[options.revid.length-1]; var to = options.revid[0]; var href = '/wiki/' + page + '?diff=' + to; if (from == to) { link.classList.add('mw-changeslist-diff'); } else { href = href + '&oldid=' + from; options.label = options.revid.length + ' changes'; link.classList.add('mw-changeslist-groupdiff'); }						link.href = href; link.title = page; if (target.nodeType == 3) { var split = /^([^\d\w]*)([\d\w\s]*)([^\d\w]*)$/.exec(target.textContent); link.innerHTML = split[2]; if (split[1].length>0) {target.parentNode.insertBefore(document.createTextNode(split[1]), target);} target.parentNode.insertBefore(link, target); if (split[3].length>0) {target.parentNode.insertBefore(document.createTextNode(split[3]), target);} target.remove; return; } else { link.innerHTML = options.label; target.replaceChildren(link); return; }					} else { return; } },				getTitle: function(row) { var title; var queries = [ '.mw-changeslist-title', // Normal Special:RecentChanges '.mw-changeslist-date', // Nested Special:RecentChanges '.mw-enhanced-rc-time > a' // Special:Contributions ];					queries.forEach(function(query) {						if (!title && row.querySelector(query) && row.querySelector(query).getAttribute('title')) {							title = row.querySelector(query).getAttribute('title');						}					}); return title || ''; },				getTarget: function(row) { var target; var queries = [ '.mw-changeslist-links:not(.mw-history-histlinks, .mw-usertoollinks) > span:first-child', // Special:Contributions && Normal Special:RecentChanges '.mw-changeslist-diff-cur + .mw-changeslist-separator', // Nested Special:RecentChanges '.mw-changeslist-links.mw-history-histlinks:not(.mw-usertoollinks) > span:last-child', // ?action=history ];					queries.forEach(function(query) {						var test = row.querySelector(query);						if (!target && test && test.classList.length==0) {							target = test.firstChild;						} else if (!target && test && test.classList.length>0 && test.classList.length>0) {							target = test.previousSibling;						}					}); return target; }			};			// Check we're in Special:RecentChanges if (config.wgCanonicalSpecialPageName == 'Recentchanges') { if (					document.querySelector('.mw-changeslist-src-mw-new') &&					( !document.querySelector('.mw-changeslist-src-mw-new .mw-changeslist-groupdiff') || !document.querySelector('.mw-changeslist-src-mw-new .mw-changeslist-diff') )				){					document.querySelectorAll('.mw-changeslist-src-mw-new').forEach(function(node){if (node) {newDiffLink.searchRevid(node);}}); }			}			// Check we're in Special:Contributions else if (config.wgCanonicalSpecialPageName == 'Contributions') { if (document.querySelector('ul.mw-contributions-list abbr.newpage')) { document.querySelectorAll('ul.mw-contributions-list abbr.newpage').forEach(function(node){						var row = node.parentElement;						if (row) {newDiffLink.searchRevid(row);}					}); }			}			// Check we're in a history page else if (config.wgAction == 'history') { if (!document.querySelector('ul.mw-contributions-list:last-of-type li:last-of-type .mw-history-histlinks > span:nth-child(2) > a')) { var node = document.querySelector('ul.mw-contributions-list:last-of-type li:last-of-type'); if (node) {newDiffLink.searchRevid(node);} }			}		},		// Properly display diff for page creation edits newDiff: function { if (document.querySelector('#mw-diff-ntitle1 > strong > a')) { var table = document.querySelector('.diff'); var revid = document.querySelector('#mw-diff-ntitle1 > strong > a').href.replace(/^.+\?oldid=/g, ''); var api_opt = { action: 'compare', torev: revid, fromslots: 'main', 'fromtext-main': '', prop: 'diff|ids', formatversion: 2 };				if ( revid && document.querySelector('#mw-diff-otitle1 > strong > a') && !document.querySelector('#differences-prevlink') ) { //Add edit link to page creation diff table.querySelector('#mw-diff-otitle4').innerHTML = ' strong > a').title +					'?diff=' +					document.querySelector('#mw-diff-otitle1 > strong > a').href.replace(/^.+\?oldid=/g, '') +					'&oldid=0" title="' +					document.querySelector('#mw-diff-otitle1 > strong > a').title +					'" id="differences-prevlink">← Older edit'; } else if (revid && !document.querySelector('#differences-prevlink')) { table.querySelector('.diff-ntitle').colSpan = 4; table.querySelector('.diff-notice').parentNode.remove; api.get(api_opt).then(function(data) {						table.innerHTML = '  ' + table.innerHTML;						table.querySelector('tbody').innerHTML = table.querySelector('tbody').innerHTML + data.compare.body;					}); }			}		},		// Mass patrol recent edits from specific user userPatrol: function(groups) { if (groups.indexOf('sysop') !== -1 || groups.indexOf('content-moderator') !== -1) { var wrapper = $(					' '+						'User to mass patrol: '+						' '+						' '+						' '+						' Patrol User '+					' '				); $('.mw-rcfilters-ui-filterWrapperWidget-top').after(wrapper); document.querySelector('#submitUserPatrol').addEventListener('click', function(event) {					var user = document.querySelector('#userPatrol').value; // Username without the "User:" prefix					if (user.length>0) {						api.get({ action: 'query', list: 'recentchanges', rcshow: '!patrolled', rcprop: 'ids', rcuser: user, format: 'json', formatversion: '2', rclimit: 'max', meta: 'tokens', type: 'patrol' }).then(function(data){ if (data.query.recentchanges.length>0) { document.querySelector('#userPatrolDetails').innerHTML = 'Patrolling '+data.query.recentchanges.length+' edits...'; var patrolID = function(page) { api.post({										action: 'patrol',										format: 'json',										revid: page.revid,										token: data.query.tokens.patroltoken									}); };								data.query.recentchanges.forEach(patrolID); document.querySelector('#userPatrolDetails').innerHTML = 'Patrolled '+data.query.recentchanges.length+' edits!'; } else { document.querySelector('#userPatrolDetails').innerHTML = 'User has no edits to patrol!'; }						});					} else { document.querySelector('#userPatrolDetails').innerHTML = 'No user specified.'; }				}); }		},		// Diff pages but without moving away from the page, allowing patrolling still quickDiff: function { // Add the extra liks var addQuick = function(diff) { if (diff && diff.getAttribute('href')) { var href = diff.getAttribute('href'); var newid = /diff=(\d+)/.exec(href)[1]; var oldid = /oldid=\d+/.test(href) ? /oldid=(\d+)/.exec(href)[1] : '0'; var link = document.createElement('a'); link.setAttribute('newid', newid); link.setAttribute('oldid', oldid); link.setAttribute('data-target-page', diff.closest('.mw-changeslist-line-inner').getAttribute('data-target-page')); link.innerHTML = 'preview'; link.style.cursor = 'pointer'; var span = document.createElement('span'); span.appendChild(link); diff.parentElement.after(span); }			};			document.querySelectorAll('.mw-changeslist-groupdiff').forEach(addQuick); document.querySelectorAll('.mw-changeslist-diff').forEach(addQuick); }	};	// Start when API and LIB are loaded mw.loader.using('mediawiki.api').then(function{		mw.hook('userjs._LIB').add(function(_LIB){ lib = _LIB; betterDiff.init; });	}); });