MediaWiki:Gadget-readableRC-core.js
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.
// <nowiki>
// Formats the rows on Special:RecentChanges where all the information runs together
// into three columns (page, diff/byte change, and user links) to make it more readable
//
// @author Iiii_I_I_I
//
// @TODO: - how to make it run automatically instead of on button click?
// - column-ize and format nested rows too?
(function($, mw) {
function runReadableRC($content) {
if (!$content.hasClass('mw-changeslist')) {
return;
}
$content.addClass('gadget-rc-enabled');
var rows = document.querySelectorAll('.mw-changeslist-line');
for (var i = 0, total = rows.length; i < total; i++) {
var row = rows[i];
// nested rows
if (row.classList.contains('mw-rcfilters-ui-changesListWrapperWidget-enhanced-nested')) {
row.setAttribute('colspan', '3');
row.classList.add('gadget-rc-nested');
cleanUserLinks(row);
cleanSummary(row);
}
// top-level rows
else if (row.classList.contains('mw-changeslist-log') && row.classList.contains('mw-collapsible')) {
// multiple logs, eg.:
// 09:55 (Upload log) . . [Ohana; Jezwin ANO (2×); Mustawa (5×); Gaga Lady (8×)]
cleanMultipleLogs(row);
}
else if (row.className.includes('mw-changeslist-log')) {
// single log, eg.:
// 19:01 (User creation log) . . User account Kyooraku (talk | contribs | block) was created
cleanSingleLog(row);
}
else if (row.classList.contains('mw-collapsible')) {
// multiple edits, eg.:
// 07:40 Defender of Varrock (3 changes | history) . . (+100) . . [Alchez; 173.216.229.37 (2×)]
cleanMultipleEdits(row);
}
else {
// single edit, eg.:
// 08:23 Huge XP lamp (Thieving) (diff | hist) . . (+36) . . Thingummywut (talk | contribs | block) (Noting its single use.) [rollback 1 edit]
cleanSingleEdits(row);
}
}
}
function insert(row, newNode, referenceNode) {
return row.querySelector(referenceNode).parentNode.insertBefore(row.querySelector(newNode), row.querySelector(referenceNode));
}
function wrap(referenceNode, wrapperEl, wrapperClass) {
var wrapper = document.createElement(wrapperEl);
referenceNode.parentNode.insertBefore(wrapper, referenceNode);
wrapper.appendChild(referenceNode);
wrapper.classList.add(wrapperClass);
}
function cleanMultipleLogs(row) {
// log name
wrap(row.querySelector('.mw-rc-unwatched'), 'td', 'gadget-rc-logname');
// remove square brackets from grouped usernames
var users = row.querySelector('.changedby').childNodes;
users[0].textContent = users[0].textContent.slice(1); // [
users[users.length - 1].textContent = users[users.length - 1].textContent.slice(0, -1); // ]
// placeholder column with separator dots
wrap(row.querySelector('.mw-changeslist-separator'), 'td', 'gadget-rc-logdots');
// rename <td>
row.querySelector('.mw-changeslist-line-inner').className = 'gadget-rc-logentry';
// rearrange newly created <td>s
insert(row, '.gadget-rc-logname', '.gadget-rc-logentry');
insert(row, '.gadget-rc-logdots', '.gadget-rc-logentry');
// stupid empty node
row.querySelector('.gadget-rc-logentry').removeChild(row.querySelector('.gadget-rc-logentry').childNodes[1]);
}
function cleanSingleLog(row) {
// log name
wrap(row.querySelector('.mw-changeslist-line-inner').childNodes[1], 'td', 'gadget-rc-logname');
// add parentheses back around log name
row.querySelector('.gadget-rc-logname').innerHTML = '(' + row.querySelector('.gadget-rc-logname').innerHTML + ')';
// remove leftover parentheses from original location
var parentheses = row.querySelector('.mw-changeslist-line-inner').childNodes;
row.querySelector('.mw-changeslist-line-inner').removeChild(parentheses[0]); // (
row.querySelector('.mw-changeslist-line-inner').removeChild(parentheses[1]); // )
// placeholder column with separator dots
wrap(row.querySelector('.mw-changeslist-separator'), 'td', 'gadget-rc-logdots');
cleanUserLinks(row);
cleanSummary(row);
// rename <td>
row.querySelector('.mw-changeslist-line-inner').className = 'gadget-rc-logentry';
// rearrange newly created <td>s
insert(row, '.gadget-rc-logname', '.gadget-rc-logentry');
insert(row, '.gadget-rc-logdots', '.gadget-rc-logentry');
}
function cleanMultipleEdits(row) {
// page name
wrap(row.querySelector('.mw-title'), 'td', 'gadget-rc-pagename');
// "x changes" -> "x diffs"
if (row.querySelector('.mw-changeslist-groupdiff')) {
var newDiff = row.querySelector('.mw-changeslist-groupdiff').childNodes[0].nodeValue.replace('changes', 'diffs');
row.querySelector('.mw-changeslist-groupdiff').childNodes[0].nodeValue = newDiff;
}
// new pages have a text node instead of a link
else {
var newDiff = row.querySelector('.mw-changeslist-line-inner').childNodes[2].nodeValue.replace('changes', 'diffs');
row.querySelector('.mw-changeslist-line-inner').childNodes[2].nodeValue = newDiff;
}
// "history" -> "hist"
if (row.querySelector('.mw-changeslist-history')) {
row.querySelector('.mw-changeslist-history').childNodes[0].nodeValue = 'hist';
}
// nonexistent pages (redirect-suppressed move or deleted) have a text node instead of a link
else {
var newHist = row.querySelector('.mw-changeslist-line-inner').childNodes[4].nodeValue.replace('history', 'hist');
row.querySelector('.mw-changeslist-line-inner').childNodes[4].nodeValue = newHist;
}
// list of user(s)
wrap(row.querySelector('.changedby'), 'td', 'gadget-rc-userlinks');
// remove square brackets from grouped usernames
var users = row.querySelector('.changedby').childNodes;
users[0].textContent = users[0].textContent.slice(1); // [
users[users.length - 1].textContent = users[users.length - 1].textContent.slice(0, -1); // ]
// rename <td>
row.querySelector('.mw-changeslist-line-inner').className = 'gadget-rc-diff';
// rearrange newly created <td>s
insert(row, '.gadget-rc-userlinks', '.gadget-rc-diff');
insert(row, '.gadget-rc-pagename', '.gadget-rc-userlinks');
insert(row, '.gadget-rc-diff', '.gadget-rc-userlinks');
}
function cleanSingleEdits(row) {
// page name
wrap(row.querySelector('.mw-title'), 'td', 'gadget-rc-pagename');
// "rollback x edit(s)" -> "rollback"
// link does not exist if it is a page creation or user does not have the right
if (row.querySelector('.mw-rollback-link')) {
row.querySelector('.mw-rollback-link a').childNodes[0].nodeValue = 'rollback';
}
// user info
$('.mw-userlink, .mw-usertoollinks, .comment, .mw-rollback-link, .mw-tag-markers, .history-deleted', row).wrapAll('<td class="gadget-rc-userlinks" />');
cleanUserLinks(row);
cleanSummary(row);
// rename <td>
row.querySelector('.mw-changeslist-line-inner').className = 'gadget-rc-diff';
// rearrange newly created <td>s
insert(row, '.gadget-rc-userlinks', '.gadget-rc-diff');
insert(row, '.gadget-rc-pagename', '.gadget-rc-userlinks');
insert(row, '.gadget-rc-diff', '.gadget-rc-userlinks');
}
function cleanUserLinks(row) {
// (talk | contribs | block) -> (t | c | b)
// possible variations: (talk), (talk | contribs), (talk | block), (talk | contribs | block), (username removed)
// if username has been revdeled (shows "(username removed)"), leave
if (row.querySelector('.history-deleted')) {
return;
}
row.querySelector('.mw-usertoollinks-talk').childNodes[0].nodeValue = 't';
// IPs don't have dedicated contribs link, it's linked in their username
if (row.querySelector('.mw-usertoollinks-contribs')) {
row.querySelector('.mw-usertoollinks-contribs').childNodes[0].nodeValue = 'c';
}
// non-admins don't have block link
if (row.querySelector('.mw-usertoollinks-block')) {
row.querySelector('.mw-usertoollinks-block').childNodes[0].nodeValue = 'b';
}
// remove spaces around pipes
var toolLinks = row.querySelector('.mw-usertoollinks').childNodes;
if (toolLinks.length > 3) {
toolLinks[2].nodeValue = '|';
if (toolLinks[4].nodeValue === ' | ') toolLinks[4].nodeValue = '|';
}
}
function cleanSummary(row) {
if (row.querySelector('.comment')) {
var nodes = row.querySelector('.comment').childNodes;
var firstNode = nodes[0].textContent;
var lastNode = nodes[nodes.length - 1].textContent;
// remove parentheses around edit summary
// if summary is pure text, ie. no links
if (nodes.length === 1) {
nodes[0].textContent = firstNode.slice(1, -1);
}
// else there are links in the summary (section links, user-created links, etc.)
else {
nodes[0].textContent = firstNode.slice(1); // (
nodes[nodes.length - 1].textContent = lastNode.slice(0, -1); // )
}
// in eg. "(→ Trivia)" only the arrow, not the section title, is a link;
// move title into <a> for a larger click target
if (row.querySelector('.autocomment')) {
var arrow = row.querySelector('.comment a');
arrow.appendChild(row.querySelector('.autocomment'));
arrow.nextSibling.remove(); // remove leftover whitespace node
}
}
}
function init() {
var button = new OO.ui.ButtonWidget({
icon: 'viewCompact',
label: 'ReadableRC',
title: 'Format RecentChanges into columns for readability',
classes: ['gadget-rc-button'],
flags: [
'primary',
'progressive'
]
});
button.on('click', function() {
runReadableRC($('.mw-changeslist'));
mw.hook('wikipage.content').add(runReadableRC);
button.setDisabled(true);
});
mw.hook('structuredChangeFilters.ui.initialized').add(function() {
$('.mw-rcfilters-ui-liveUpdateButtonWidget').append(button.$element);
});
}
$(init);
})(jQuery, mediaWiki);
// </nowiki>