MediaWiki:Gadget-readableRC-core.js: Difference between revisions
Jump to navigation
Jump to search
mNo edit summary |
No edit summary |
||
| Line 3: | Line 3: | ||
// into three columns (page, diff/byte change, and user links) to make it more readable | // 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($, mw) { | ||
function | function runReadableRC($content) { | ||
if ($content.hasClass('mw-changeslist')) { | if (!$content.hasClass('mw-changeslist')) { | ||
var rows = document. | 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({ | var button = new OO.ui.ButtonWidget({ | ||
icon: 'viewCompact', | icon: 'viewCompact', | ||
label: 'ReadableRC', | label: 'ReadableRC', | ||
title: 'Format RecentChanges into columns for readability', | title: 'Format RecentChanges into columns for readability', | ||
classes: ['gadget-rc-button'] | classes: ['gadget-rc-button'], | ||
flags: [ | |||
'primary', | |||
'progressive' | |||
] | |||
}); | }); | ||
button.on('click', function() { | button.on('click', function() { | ||
runReadableRC($('.mw-changeslist')); | |||
mw.hook('wikipage.content').add( | mw.hook('wikipage.content').add(runReadableRC); | ||
button.setDisabled(true); | button.setDisabled(true); | ||
}); | }); | ||
mw.hook('structuredChangeFilters.ui.initialized').add(function() { | mw.hook('structuredChangeFilters.ui.initialized').add(function() { | ||
$('.mw-rcfilters-ui-liveUpdateButtonWidget').append(button.$element); | $('.mw-rcfilters-ui-liveUpdateButtonWidget').append(button.$element); | ||
| Line 199: | Line 268: | ||
} | } | ||
$(init); | |||
})(jQuery, mediaWiki); | })(jQuery, mediaWiki); | ||
// </nowiki> | // </nowiki> | ||
Latest revision as of 18:46, 9 August 2021
// <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>