MediaWiki:Gadget-readableRC-core.js: Difference between revisions
Jump to navigation
Jump to search
Content added Content deleted
(Created page with "// <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 ;(function ($, mw) { function runReadableRC($content) { if (!$content.hasClass('mw-changeslist')) { return; } $content.addClass('gadget-rc-enabled'); let rows = document.querySelectorAll( '.mw-changeslist-src-mw-edit,' + '.mw-changeslist-src-mw...") |
No edit summary |
||
(2 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
"use strict"; |
|||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } |
|||
function _wrapRegExp() { _wrapRegExp = function _wrapRegExp(e, r) { return new BabelRegExp(e, void 0, r); }; var e = RegExp.prototype, r = new WeakMap(); function BabelRegExp(e, t, p) { var o = RegExp(e, t); return r.set(o, p || r.get(e)), _setPrototypeOf(o, BabelRegExp.prototype); } function buildGroups(e, t) { var p = r.get(t); return Object.keys(p).reduce(function (r, t) { var o = p[t]; if ("number" == typeof o) r[t] = e[o];else { for (var i = 0; void 0 === e[o[i]] && i + 1 < o.length;) i++; r[t] = e[o[i]]; } return r; }, Object.create(null)); } return _inherits(BabelRegExp, RegExp), BabelRegExp.prototype.exec = function (r) { var t = e.exec.call(this, r); if (t) { t.groups = buildGroups(t, this); var p = t.indices; p && (p.groups = buildGroups(p, this)); } return t; }, BabelRegExp.prototype[Symbol.replace] = function (t, p) { if ("string" == typeof p) { var o = r.get(this); return e[Symbol.replace].call(this, t, p.replace(/\$<([^>]+)>/g, function (e, r) { var t = o[r]; return "$" + (Array.isArray(t) ? t.join("$") : t); })); } if ("function" == typeof p) { var i = this; return e[Symbol.replace].call(this, t, function () { var e = arguments; return "object" != _typeof(e[e.length - 1]) && (e = [].slice.call(e)).push(buildGroups(e, i)), p.apply(this, e); }); } return e[Symbol.replace].call(this, t, p); }, _wrapRegExp.apply(this, arguments); } |
|||
function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } |
|||
function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } |
|||
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } |
|||
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } |
|||
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } |
|||
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } |
|||
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; } |
|||
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } |
|||
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } |
|||
// <nowiki> |
// <nowiki> |
||
// Formats the rows on Special:RecentChanges where all the information runs together |
// Formats the rows on Special:RecentChanges where all the information runs together |
||
Line 5: | Line 18: | ||
// @author Iiii_I_I_I |
// @author Iiii_I_I_I |
||
; |
|||
;(function ($, mw) { |
|||
(function ($, mw) { |
|||
function runReadableRC($content) { |
|||
if (!$content.hasClass('mw-changeslist')) { |
|||
if (!$content.hasClass('mw-changeslist')) { |
|||
return; |
|||
return; |
|||
} |
|||
} |
|||
$content.addClass('gadget-rc-enabled'); |
|||
var rows = document.querySelectorAll('.mw-changeslist-src-mw-edit,' + '.mw-changeslist-src-mw-log,' + '.mw-changeslist-src-mw-new'); |
|||
var _iterator = _createForOfIteratorHelper(rows), |
|||
let rows = document.querySelectorAll( |
|||
_step; |
|||
'.mw-changeslist-src-mw-edit,' + |
|||
try { |
|||
'.mw-changeslist-src-mw-log,' + |
|||
for (_iterator.s(); !(_step = _iterator.n()).done;) { |
|||
'.mw-changeslist-src-mw-new' |
|||
var row = _step.value; |
|||
); |
|||
// hover text on timestamp column |
|||
addRelativeTime(row); |
|||
for (let row of rows) { |
|||
// hover text on timestamp column |
|||
addRelativeTime(row); |
|||
// nested rows |
|||
if (row.classList.contains('mw-rcfilters-ui-highlights-enhanced-nested')) { |
|||
if (row.classList.contains('mw-changeslist-edit')) { |
|||
cleanNestedEdit(row); |
|||
} else { |
|||
cleanNestedLog(row); |
|||
} |
|||
} |
|||
// top-level rows |
|||
else { |
|||
// grouped row |
|||
if (row.classList.contains('mw-rcfilters-ui-highlights-enhanced-toplevel')) { |
|||
let parent = row.closest('.mw-changeslist-line'); |
|||
if (parent.classList.contains('mw-changeslist-edit')) { |
|||
cleanGroupedEdit(row); |
|||
} else { |
|||
cleanGroupedLog(row); |
|||
} |
|||
} |
|||
// single row |
|||
else { |
|||
if (row.classList.contains('mw-changeslist-edit')) { |
|||
cleanSingleEdit(row); |
|||
} else { |
|||
cleanSingleLog(row); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
// fires every time readableRC runs when new edits come in |
|||
mw.hook('ext.gadget.readableRC').fire(); |
|||
} |
|||
function cleanNestedLog(row) { |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-log', 'gadget-rc-nested'); |
|||
// FIRST COLUMN: log timestamp |
|||
row.querySelector('.mw-enhanced-rc-time').classList.add('gadget-rc-col-1'); |
|||
// SECOND COLUMN: placeholder with separator dots |
|||
row.querySelector('.mw-changeslist-separator').classList.add('gadget-rc-col-2'); |
|||
// THIRD COLUMN: user info |
|||
let col3 = document.createElement('span'); |
|||
col3.classList.add('gadget-rc-col-3'); |
|||
col3.append( |
|||
get('.mw-changeslist-log-entry', row), |
|||
get('.mw-tag-markers', row) |
|||
); |
|||
row.querySelector('.gadget-rc-col-2').after(col3); |
|||
cleanUserLinks(row); |
|||
} |
|||
function cleanNestedEdit(row) { |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-edit', 'gadget-rc-nested'); |
|||
// FIRST COLUMN: revision link |
|||
row.querySelector('.mw-enhanced-rc-time').classList.add('gadget-rc-col-1'); |
|||
// THIRD COLUMN: user info |
|||
let col3 = document.createElement('span'); |
|||
col3.classList.add('gadget-rc-col-3'); |
|||
col3.append( |
|||
get('.mw-userlink', row), |
|||
get('.mw-usertoollinks', row), |
|||
get('.mw-enhanced-rc-nested > .history-deleted', row), // (username removed) |
|||
get('.comment', row), |
|||
get('.mw-pager-tools', row), |
|||
get('.mw-tag-markers', row) |
|||
); |
|||
// SECOND COLUMN: diff text |
|||
let parent = row.querySelector('td.mw-enhanced-rc-nested'); |
|||
let col1 = row.querySelector('.gadget-rc-col-1'); |
|||
// detach first column so remaining elements all go in diff column |
|||
parent.removeChild(col1); |
|||
// wrap elements together inside column 2 |
|||
let col2 = document.createElement('span'); |
|||
col2.classList.add('gadget-rc-col-2'); |
|||
while (parent.firstChild) { |
|||
col2.append(parent.firstChild); |
|||
} |
|||
// put everything back together |
|||
parent.append(col1); |
|||
parent.append(col2); |
|||
parent.append(col3); |
|||
cleanUserLinks(row); |
|||
} |
|||
function cleanGroupedLog(row) { |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-log', 'gadget-rc-grouped'); |
|||
// FIRST COLUMN: log name |
|||
row.querySelector('.mw-rc-unwatched').classList.add('gadget-rc-col-1'); |
|||
// SECOND COLUMN: placeholder with separator dots |
|||
row.querySelector('.mw-changeslist-separator').classList.add('gadget-rc-col-2'); |
|||
// THIRD COLUMN: user info |
|||
row.querySelector('.changedby').classList.add('gadget-rc-col-3'); |
|||
// remove square brackets from grouped usernames; can't use remove() |
|||
// since there might be other text in the same node, eg. "(4×)]" |
|||
let users = row.querySelector('.gadget-rc-col-3').childNodes; |
|||
users[0].textContent = users[0].textContent.slice(1); // [ |
|||
users[users.length - 1].textContent = users[users.length - 1].textContent.slice(0, -1); // ] |
|||
// remove empty text nodes - convert live NodeList to array |
|||
let children = [...row.querySelector('.mw-changeslist-line-inner').childNodes]; |
|||
// nested rows |
|||
for (let child of children) { |
|||
if (row.classList.contains('mw-rcfilters-ui-highlights-enhanced-nested')) { |
|||
if (child.nodeType === Node.TEXT_NODE) { |
|||
if (row.classList.contains('mw-changeslist-edit')) { |
|||
child.remove(); |
|||
cleanNestedEdit(row); |
|||
} |
|||
} else { |
|||
} |
|||
cleanNestedLog(row); |
|||
} |
|||
} |
|||
} |
|||
// top-level rows |
|||
else { |
|||
// grouped row |
|||
if (row.classList.contains('mw-rcfilters-ui-highlights-enhanced-toplevel')) { |
|||
var parent = row.closest('.mw-changeslist-line'); |
|||
if (parent.classList.contains('mw-changeslist-edit')) { |
|||
cleanGroupedEdit(row); |
|||
} else { |
|||
cleanGroupedLog(row); |
|||
} |
|||
} |
|||
// single row |
|||
else { |
|||
if (row.classList.contains('mw-changeslist-edit')) { |
|||
cleanSingleEdit(row); |
|||
} else { |
|||
cleanSingleLog(row); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
// fires every time readableRC runs when new edits come in |
|||
function cleanGroupedEdit(row) { |
|||
} catch (err) { |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-edit', 'gadget-rc-grouped'); |
|||
_iterator.e(err); |
|||
} finally { |
|||
_iterator.f(); |
|||
} |
|||
mw.hook('ext.gadget.readableRC').fire(); |
|||
} |
|||
function cleanNestedLog(row) { |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-log', 'gadget-rc-nested'); |
|||
// FIRST COLUMN: log timestamp |
|||
row.querySelector('.mw-enhanced-rc-time').classList.add('gadget-rc-col-1'); |
|||
// SECOND COLUMN: placeholder with separator dots |
|||
row.querySelector('.mw-changeslist-separator').classList.add('gadget-rc-col-2'); |
|||
let col2 = document.createElement('span'); |
|||
// THIRD COLUMN: user info |
|||
col2.classList.add('gadget-rc-col-2'); |
|||
var col3 = document.createElement('span'); |
|||
col2.append( |
|||
col3.classList.add('gadget-rc-col-3'); |
|||
get('.mw-changeslist-links', row), |
|||
col3.append(get('.mw-changeslist-log-entry', row), get('.mw-tag-markers', row)); |
|||
row.querySelector('.gadget-rc-col-2').after(col3); |
|||
); |
|||
cleanUserLinks(row); |
|||
row.querySelector('.gadget-rc-col-1').after(col2); |
|||
} |
|||
function cleanNestedEdit(row) { |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-edit', 'gadget-rc-nested'); |
|||
// FIRST COLUMN: revision link |
|||
// "x changes" -> "diff" |
|||
row.querySelector('.mw-enhanced-rc-time').classList.add('gadget-rc-col-1'); |
|||
row.querySelector('.mw-changeslist-groupdiff').textContent = 'diff'; |
|||
} |
|||
// new pages have a text node instead of a link |
|||
else { |
|||
row.querySelector('.mw-changeslist-links span:first-child').textContent = 'diff'; |
|||
} |
|||
// THIRD COLUMN: user info |
|||
// "history" -> "hist" |
|||
var col3 = document.createElement('span'); |
|||
if (row.querySelector('.mw-changeslist-history')) { |
|||
col3.classList.add('gadget-rc-col-3'); |
|||
row.querySelector('.mw-changeslist-history').textContent = 'hist'; |
|||
col3.append(get('.mw-userlink', row), get('.mw-usertoollinks', row), get('.mw-enhanced-rc-nested > .history-deleted', row), |
|||
} |
|||
// (username removed) |
|||
// nonexistent pages (redirect-suppressed move or deleted) have a text node instead of a link |
|||
get('.comment', row), get('.mw-pager-tools', row), get('.mw-tag-markers', row)); |
|||
// @todo check for new classname/structure; no example rn |
|||
else { |
|||
// let newHist = row.querySelector('.mw-changeslist-line-inner').childNodes[4].nodeValue.replace('history', 'hist'); |
|||
// row.querySelector('.mw-changeslist-line-inner').childNodes[4].nodeValue = newHist; |
|||
} |
|||
// SECOND COLUMN: diff text |
|||
var parent = row.querySelector('td.mw-enhanced-rc-nested'); |
|||
var col1 = row.querySelector('.gadget-rc-col-1'); |
|||
// detach first column so remaining elements all go in diff column |
|||
// remove square brackets from grouped usernames; cannot simply use remove() |
|||
parent.removeChild(col1); |
|||
// since there might be other text in the same node, eg. "(4×)]" |
|||
let users = row.querySelector('.gadget-rc-col-3').childNodes; |
|||
// wrap elements together inside column 2 |
|||
users[0].textContent = users[0].textContent.slice(1); // [ |
|||
var col2 = document.createElement('span'); |
|||
users[users.length - 1].textContent = users[users.length - 1].textContent.slice(0, -1); // ] |
|||
col2.classList.add('gadget-rc-col-2'); |
|||
while (parent.firstChild) { |
|||
col2.append(parent.firstChild); |
|||
} |
|||
// put everything back together |
|||
// remove empty text nodes - convert live NodeList to array |
|||
parent.append(col1); |
|||
let children = [...row.querySelector('.mw-changeslist-line-inner').childNodes]; |
|||
parent.append(col2); |
|||
parent.append(col3); |
|||
cleanUserLinks(row); |
|||
} |
|||
function cleanGroupedLog(row) { |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-log', 'gadget-rc-grouped'); |
|||
// FIRST COLUMN: log name |
|||
for (let child of children) { |
|||
row.querySelector('.mw-rc-unwatched').classList.add('gadget-rc-col-1'); |
|||
if (child.nodeType === Node.TEXT_NODE) { |
|||
child.remove(); |
|||
} |
|||
} |
|||
} |
|||
// SECOND COLUMN: placeholder with separator dots |
|||
function cleanSingleLog(row) { |
|||
row.querySelector('.mw-changeslist-separator').classList.add('gadget-rc-col-2'); |
|||
// THIRD COLUMN: user info |
|||
row.querySelector('.changedby').classList.add('gadget-rc-col-3'); |
|||
// remove square brackets from grouped usernames; can't use remove() |
|||
// SECOND COLUMN: placeholder with separator dots |
|||
// since there might be other text in the same node, eg. "(4×)]" |
|||
row.querySelector('.mw-changeslist-line-inner-separatorAfterLinks').classList.add('gadget-rc-col-2'); |
|||
var users = row.querySelector('.gadget-rc-col-3').childNodes; |
|||
users[0].textContent = users[0].textContent.slice(1); // [ |
|||
users[users.length - 1].textContent = users[users.length - 1].textContent.slice(0, -1); // ] |
|||
// remove empty text nodes - convert live NodeList to array |
|||
// THIRD COLUMN: user info |
|||
var children = _toConsumableArray(row.querySelector('.mw-changeslist-line-inner').childNodes); |
|||
let col3 = document.createElement('span'); |
|||
var _iterator2 = _createForOfIteratorHelper(children), |
|||
_step2; |
|||
try { |
|||
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { |
|||
var child = _step2.value; |
|||
if (child.nodeType === Node.TEXT_NODE) { |
|||
child.remove(); |
|||
} |
|||
} |
|||
} catch (err) { |
|||
_iterator2.e(err); |
|||
} finally { |
|||
_iterator2.f(); |
|||
} |
|||
} |
|||
function cleanGroupedEdit(row) { |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-edit', 'gadget-rc-grouped'); |
|||
// FIRST COLUMN: page name |
|||
col3.classList.add('gadget-rc-col-3'); |
|||
row.querySelector('.mw-title').classList.add('gadget-rc-col-1'); |
|||
col3.append( |
|||
get('.mw-changeslist-line-inner-logEntry', row), |
|||
get('.mw-changeslist-line-inner-tags', row), |
|||
get('.mw-changeslist-line-inner-watchingUsers', row) |
|||
); |
|||
row.querySelector('.gadget-rc-col-2').after(col3); |
|||
cleanUserLinks(row); |
|||
} |
|||
// SECOND COLUMN: diff text |
|||
function cleanSingleEdit(row) { |
|||
var col2 = document.createElement('span'); |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-edit'); |
|||
col2.classList.add('gadget-rc-col-2'); |
|||
col2.append(get('.mw-changeslist-links', row), get('.mw-diff-bytes', row)); |
|||
row.querySelector('.gadget-rc-col-1').after(col2); |
|||
// "x changes" -> "diff" |
|||
// FIRST COLUMN: page name |
|||
if (row.querySelector('.mw-changeslist-groupdiff')) { |
|||
row.querySelector('.mw-changeslist-groupdiff').textContent = 'diff'; |
|||
} |
|||
// new pages have a text node instead of a link |
|||
else { |
|||
row.querySelector('.mw-changeslist-links span:first-child').textContent = 'diff'; |
|||
} |
|||
// "history" -> "hist" |
|||
// SECOND COLUMN: diff text |
|||
if (row.querySelector('.mw-changeslist-history')) { |
|||
let col2 = document.createElement('span'); |
|||
row.querySelector('.mw-changeslist-history').textContent = 'hist'; |
|||
} |
|||
// nonexistent pages (redirect-suppressed move or deleted) have a text node instead of a link |
|||
// @todo check for new classname/structure; no example rn |
|||
else { |
|||
// let newHist = row.querySelector('.mw-changeslist-line-inner').childNodes[4].nodeValue.replace('history', 'hist'); |
|||
// row.querySelector('.mw-changeslist-line-inner').childNodes[4].nodeValue = newHist; |
|||
} |
|||
// THIRD COLUMN: user info |
|||
col2.classList.add('gadget-rc-col-2'); |
|||
row.querySelector('.changedby').classList.add('gadget-rc-col-3'); |
|||
col2.append( |
|||
get('.mw-changeslist-line-inner-historyLink', row), |
|||
get('.mw-changeslist-line-inner-characterDiff', row) |
|||
); |
|||
row.querySelector('.gadget-rc-col-1').after(col2); |
|||
// remove square brackets from grouped usernames; cannot simply use remove() |
|||
// THIRD COLUMN: user info |
|||
// since there might be other text in the same node, eg. "(4×)]" |
|||
let col3 = document.createElement('span'); |
|||
var users = row.querySelector('.gadget-rc-col-3').childNodes; |
|||
users[0].textContent = users[0].textContent.slice(1); // [ |
|||
users[users.length - 1].textContent = users[users.length - 1].textContent.slice(0, -1); // ] |
|||
// remove empty text nodes - convert live NodeList to array |
|||
col3.classList.add('gadget-rc-col-3'); |
|||
var children = _toConsumableArray(row.querySelector('.mw-changeslist-line-inner').childNodes); |
|||
col3.append( |
|||
var _iterator3 = _createForOfIteratorHelper(children), |
|||
get('.mw-changeslist-line-inner-userLink', row), |
|||
_step3; |
|||
get('.mw-changeslist-line-inner-userTalkLink', row), |
|||
try { |
|||
get('.mw-changeslist-line-inner-comment', row), |
|||
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { |
|||
get('.mw-changeslist-line-inner-rollback', row), |
|||
var child = _step3.value; |
|||
get('.mw-changeslist-line-inner-tags', row), |
|||
if (child.nodeType === Node.TEXT_NODE) { |
|||
get('.mw-changeslist-line-inner-watchingUsers', row) |
|||
child.remove(); |
|||
); |
|||
} |
|||
col2.after(col3); |
|||
} |
|||
cleanUserLinks(row); |
|||
} catch (err) { |
|||
} |
|||
_iterator3.e(err); |
|||
} finally { |
|||
_iterator3.f(); |
|||
} |
|||
} |
|||
function cleanSingleLog(row) { |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-log'); |
|||
// FIRST COLUMN: log name |
|||
function cleanUserLinks(row) { |
|||
row.querySelector('.mw-changeslist-line-inner-logLink').classList.add('gadget-rc-col-1'); |
|||
// if username has been revdeled (shows "(username removed)"), it has no links |
|||
if (row.querySelector('.history-deleted')) return; |
|||
// SECOND COLUMN: placeholder with separator dots |
|||
// replace links with first letter of each link |
|||
row.querySelector('.mw-changeslist-line-inner-separatorAfterLinks').classList.add('gadget-rc-col-2'); |
|||
let links = row.querySelectorAll('.mw-usertoollinks a'); |
|||
// THIRD COLUMN: user info |
|||
for (let link of links) { |
|||
var col3 = document.createElement('span'); |
|||
link.textContent = link.textContent.slice(0, 1); |
|||
col3.classList.add('gadget-rc-col-3'); |
|||
} |
|||
col3.append(get('.mw-changeslist-line-inner-logEntry', row), get('.mw-changeslist-line-inner-tags', row), get('.mw-changeslist-line-inner-watchingUsers', row)); |
|||
row.querySelector('.gadget-rc-col-2').after(col3); |
|||
cleanUserLinks(row); |
|||
} |
|||
function cleanSingleEdit(row) { |
|||
row.classList.add('gadget-rc-row', 'gadget-rc-edit'); |
|||
// FIRST COLUMN: page name |
|||
// rollback link doesn't exist if page creation or user does not have the right |
|||
row.querySelector('.mw-changeslist-line-inner-articleLink').classList.add('gadget-rc-col-1'); |
|||
row.querySelector('.mw-rollback-link a').textContent = 'rollback'; |
|||
} |
|||
} |
|||
// SECOND COLUMN: diff text |
|||
// add relative time (eg. "25m ago") to timestamp column as hover text |
|||
var col2 = document.createElement('span'); |
|||
function addRelativeTime(row) { |
|||
col2.classList.add('gadget-rc-col-2'); |
|||
// if row is a single row |
|||
col2.append(get('.mw-changeslist-line-inner-historyLink', row), get('.mw-changeslist-line-inner-characterDiff', row)); |
|||
let timestamp = row.getAttribute('data-mw-ts'); |
|||
row.querySelector('.gadget-rc-col-1').after(col2); |
|||
// THIRD COLUMN: user info |
|||
// if row is a grouped row |
|||
var col3 = document.createElement('span'); |
|||
if (timestamp === null) { |
|||
col3.classList.add('gadget-rc-col-3'); |
|||
timestamp = row.closest('table.mw-enhanced-rc').getAttribute('data-mw-ts'); |
|||
col3.append(get('.mw-changeslist-line-inner-userLink', row), get('.mw-changeslist-line-inner-userTalkLink', row), get('.mw-changeslist-line-inner-comment', row), get('.mw-changeslist-line-inner-rollback', row), get('.mw-changeslist-line-inner-tags', row), get('.mw-changeslist-line-inner-watchingUsers', row)); |
|||
} |
|||
col2.after(col3); |
|||
cleanUserLinks(row); |
|||
} |
|||
function cleanUserLinks(row) { |
|||
// if username has been revdeled (shows "(username removed)"), it has no links |
|||
if (row.querySelector('.history-deleted')) return; |
|||
// replace links with first letter of each link |
|||
// convert mw timestamp (eg. 20240906020749) to Date (equal to 2024-09-06, 02:07:49 UTC) |
|||
var links = row.querySelectorAll('.mw-usertoollinks a'); |
|||
let {y, m, d, h, min, s} = timestamp.match(/(?<y>\d{4})(?<m>\d{2})(?<d>\d{2})(?<h>\d{2})(?<min>\d{2})(?<s>\d{2})/).groups; |
|||
var _iterator4 = _createForOfIteratorHelper(links), |
|||
let timestampObj = new Date(`${y}-${m}-${d}T${h}:${min}:${s}.000Z`); |
|||
_step4; |
|||
try { |
|||
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { |
|||
var link = _step4.value; |
|||
link.textContent = link.textContent.slice(0, 1); |
|||
} |
|||
// rollback link doesn't exist if page creation or user does not have the right |
|||
// get time difference, then format into hours and minutes |
|||
} catch (err) { |
|||
let minsAgo = Math.floor((new Date() - timestampObj) / 1000 / 60); |
|||
_iterator4.e(err); |
|||
let timeAgo; |
|||
} finally { |
|||
_iterator4.f(); |
|||
} |
|||
if (row.querySelector('.mw-rollback-link')) { |
|||
row.querySelector('.mw-rollback-link a').textContent = 'rollback'; |
|||
} |
|||
} |
|||
// add relative time (eg. "25m ago") to timestamp column as hover text |
|||
if (minsAgo === 0) { |
|||
function addRelativeTime(row) { |
|||
timeAgo = 'Now!'; |
|||
// if row is a single row |
|||
var timestamp = row.getAttribute('data-mw-ts'); |
|||
timeAgo = minsAgo + 'm ago'; |
|||
} else { |
|||
timeAgo = Math.floor(minsAgo / 60) + 'h ' + minsAgo % 60 + 'm ago'; |
|||
} |
|||
// if row is a grouped row |
|||
get('.mw-enhanced-rc', row).setAttribute('title', timeAgo); |
|||
if (timestamp === null) { |
|||
} |
|||
timestamp = row.closest('table.mw-enhanced-rc').getAttribute('data-mw-ts'); |
|||
} |
|||
// convert mw timestamp (eg. 20240906020749) to Date (equal to 2024-09-06, 02:07:49 UTC) |
|||
// return element if it exists; if not, fail silently (unlike querySelector, which returns null) |
|||
var _timestamp$match$grou = timestamp.match(/*#__PURE__*/_wrapRegExp(/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/, { |
|||
function get(selector, scope = document) { |
|||
y: 1, |
|||
let element = scope.querySelector(selector); |
|||
m: 2, |
|||
return (element) ? element : ''; |
|||
d: 3, |
|||
} |
|||
h: 4, |
|||
min: 5, |
|||
s: 6 |
|||
})).groups, |
|||
y = _timestamp$match$grou.y, |
|||
m = _timestamp$match$grou.m, |
|||
d = _timestamp$match$grou.d, |
|||
h = _timestamp$match$grou.h, |
|||
min = _timestamp$match$grou.min, |
|||
s = _timestamp$match$grou.s; |
|||
var timestampObj = new Date("".concat(y, "-").concat(m, "-").concat(d, "T").concat(h, ":").concat(min, ":").concat(s, ".000Z")); |
|||
// get time difference, then format into hours and minutes |
|||
function init() { |
|||
var minsAgo = Math.floor((new Date() - timestampObj) / 1000 / 60); |
|||
mw.hook('structuredChangeFilters.ui.initialized').add(function () { |
|||
var timeAgo; |
|||
// initial load |
|||
if (minsAgo === 0) { |
|||
runReadableRC($('.mw-changeslist')); |
|||
timeAgo = 'Now!'; |
|||
} else if (minsAgo < 60) { |
|||
timeAgo = minsAgo + 'm ago'; |
|||
} else { |
|||
timeAgo = Math.floor(minsAgo / 60) + 'h ' + minsAgo % 60 + 'm ago'; |
|||
} |
|||
get('.mw-enhanced-rc', row).setAttribute('title', timeAgo); |
|||
} |
|||
// return element if it exists; if not, fail silently (unlike querySelector, which returns null) |
|||
// page refreshed with new edits / "Live updates" on |
|||
function get(selector) { |
|||
mw.hook('wikipage.content').add(runReadableRC); |
|||
var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document; |
|||
}); |
|||
var element = scope.querySelector(selector); |
|||
} |
|||
return element ? element : ''; |
|||
} |
|||
function init() { |
|||
mw.hook('structuredChangeFilters.ui.initialized').add(function () { |
|||
// initial load |
|||
runReadableRC($('.mw-changeslist')); |
|||
// page refreshed with new edits / "Live updates" on |
|||
$(init); |
|||
mw.hook('wikipage.content').add(runReadableRC); |
|||
}); |
|||
} |
|||
$(init); |
|||
})(jQuery, mediaWiki); |
})(jQuery, mediaWiki); |
||
Latest revision as of 12:06, 20 October 2024
"use strict";
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
function _wrapRegExp() { _wrapRegExp = function _wrapRegExp(e, r) { return new BabelRegExp(e, void 0, r); }; var e = RegExp.prototype, r = new WeakMap(); function BabelRegExp(e, t, p) { var o = RegExp(e, t); return r.set(o, p || r.get(e)), _setPrototypeOf(o, BabelRegExp.prototype); } function buildGroups(e, t) { var p = r.get(t); return Object.keys(p).reduce(function (r, t) { var o = p[t]; if ("number" == typeof o) r[t] = e[o];else { for (var i = 0; void 0 === e[o[i]] && i + 1 < o.length;) i++; r[t] = e[o[i]]; } return r; }, Object.create(null)); } return _inherits(BabelRegExp, RegExp), BabelRegExp.prototype.exec = function (r) { var t = e.exec.call(this, r); if (t) { t.groups = buildGroups(t, this); var p = t.indices; p && (p.groups = buildGroups(p, this)); } return t; }, BabelRegExp.prototype[Symbol.replace] = function (t, p) { if ("string" == typeof p) { var o = r.get(this); return e[Symbol.replace].call(this, t, p.replace(/\$<([^>]+)>/g, function (e, r) { var t = o[r]; return "$" + (Array.isArray(t) ? t.join("$") : t); })); } if ("function" == typeof p) { var i = this; return e[Symbol.replace].call(this, t, function () { var e = arguments; return "object" != _typeof(e[e.length - 1]) && (e = [].slice.call(e)).push(buildGroups(e, i)), p.apply(this, e); }); } return e[Symbol.replace].call(this, t, p); }, _wrapRegExp.apply(this, arguments); }
function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
// <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
;
(function ($, mw) {
function runReadableRC($content) {
if (!$content.hasClass('mw-changeslist')) {
return;
}
$content.addClass('gadget-rc-enabled');
var rows = document.querySelectorAll('.mw-changeslist-src-mw-edit,' + '.mw-changeslist-src-mw-log,' + '.mw-changeslist-src-mw-new');
var _iterator = _createForOfIteratorHelper(rows),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var row = _step.value;
// hover text on timestamp column
addRelativeTime(row);
// nested rows
if (row.classList.contains('mw-rcfilters-ui-highlights-enhanced-nested')) {
if (row.classList.contains('mw-changeslist-edit')) {
cleanNestedEdit(row);
} else {
cleanNestedLog(row);
}
}
// top-level rows
else {
// grouped row
if (row.classList.contains('mw-rcfilters-ui-highlights-enhanced-toplevel')) {
var parent = row.closest('.mw-changeslist-line');
if (parent.classList.contains('mw-changeslist-edit')) {
cleanGroupedEdit(row);
} else {
cleanGroupedLog(row);
}
}
// single row
else {
if (row.classList.contains('mw-changeslist-edit')) {
cleanSingleEdit(row);
} else {
cleanSingleLog(row);
}
}
}
}
// fires every time readableRC runs when new edits come in
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
mw.hook('ext.gadget.readableRC').fire();
}
function cleanNestedLog(row) {
row.classList.add('gadget-rc-row', 'gadget-rc-log', 'gadget-rc-nested');
// FIRST COLUMN: log timestamp
row.querySelector('.mw-enhanced-rc-time').classList.add('gadget-rc-col-1');
// SECOND COLUMN: placeholder with separator dots
row.querySelector('.mw-changeslist-separator').classList.add('gadget-rc-col-2');
// THIRD COLUMN: user info
var col3 = document.createElement('span');
col3.classList.add('gadget-rc-col-3');
col3.append(get('.mw-changeslist-log-entry', row), get('.mw-tag-markers', row));
row.querySelector('.gadget-rc-col-2').after(col3);
cleanUserLinks(row);
}
function cleanNestedEdit(row) {
row.classList.add('gadget-rc-row', 'gadget-rc-edit', 'gadget-rc-nested');
// FIRST COLUMN: revision link
row.querySelector('.mw-enhanced-rc-time').classList.add('gadget-rc-col-1');
// THIRD COLUMN: user info
var col3 = document.createElement('span');
col3.classList.add('gadget-rc-col-3');
col3.append(get('.mw-userlink', row), get('.mw-usertoollinks', row), get('.mw-enhanced-rc-nested > .history-deleted', row),
// (username removed)
get('.comment', row), get('.mw-pager-tools', row), get('.mw-tag-markers', row));
// SECOND COLUMN: diff text
var parent = row.querySelector('td.mw-enhanced-rc-nested');
var col1 = row.querySelector('.gadget-rc-col-1');
// detach first column so remaining elements all go in diff column
parent.removeChild(col1);
// wrap elements together inside column 2
var col2 = document.createElement('span');
col2.classList.add('gadget-rc-col-2');
while (parent.firstChild) {
col2.append(parent.firstChild);
}
// put everything back together
parent.append(col1);
parent.append(col2);
parent.append(col3);
cleanUserLinks(row);
}
function cleanGroupedLog(row) {
row.classList.add('gadget-rc-row', 'gadget-rc-log', 'gadget-rc-grouped');
// FIRST COLUMN: log name
row.querySelector('.mw-rc-unwatched').classList.add('gadget-rc-col-1');
// SECOND COLUMN: placeholder with separator dots
row.querySelector('.mw-changeslist-separator').classList.add('gadget-rc-col-2');
// THIRD COLUMN: user info
row.querySelector('.changedby').classList.add('gadget-rc-col-3');
// remove square brackets from grouped usernames; can't use remove()
// since there might be other text in the same node, eg. "(4×)]"
var users = row.querySelector('.gadget-rc-col-3').childNodes;
users[0].textContent = users[0].textContent.slice(1); // [
users[users.length - 1].textContent = users[users.length - 1].textContent.slice(0, -1); // ]
// remove empty text nodes - convert live NodeList to array
var children = _toConsumableArray(row.querySelector('.mw-changeslist-line-inner').childNodes);
var _iterator2 = _createForOfIteratorHelper(children),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var child = _step2.value;
if (child.nodeType === Node.TEXT_NODE) {
child.remove();
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
function cleanGroupedEdit(row) {
row.classList.add('gadget-rc-row', 'gadget-rc-edit', 'gadget-rc-grouped');
// FIRST COLUMN: page name
row.querySelector('.mw-title').classList.add('gadget-rc-col-1');
// SECOND COLUMN: diff text
var col2 = document.createElement('span');
col2.classList.add('gadget-rc-col-2');
col2.append(get('.mw-changeslist-links', row), get('.mw-diff-bytes', row));
row.querySelector('.gadget-rc-col-1').after(col2);
// "x changes" -> "diff"
if (row.querySelector('.mw-changeslist-groupdiff')) {
row.querySelector('.mw-changeslist-groupdiff').textContent = 'diff';
}
// new pages have a text node instead of a link
else {
row.querySelector('.mw-changeslist-links span:first-child').textContent = 'diff';
}
// "history" -> "hist"
if (row.querySelector('.mw-changeslist-history')) {
row.querySelector('.mw-changeslist-history').textContent = 'hist';
}
// nonexistent pages (redirect-suppressed move or deleted) have a text node instead of a link
// @todo check for new classname/structure; no example rn
else {
// let newHist = row.querySelector('.mw-changeslist-line-inner').childNodes[4].nodeValue.replace('history', 'hist');
// row.querySelector('.mw-changeslist-line-inner').childNodes[4].nodeValue = newHist;
}
// THIRD COLUMN: user info
row.querySelector('.changedby').classList.add('gadget-rc-col-3');
// remove square brackets from grouped usernames; cannot simply use remove()
// since there might be other text in the same node, eg. "(4×)]"
var users = row.querySelector('.gadget-rc-col-3').childNodes;
users[0].textContent = users[0].textContent.slice(1); // [
users[users.length - 1].textContent = users[users.length - 1].textContent.slice(0, -1); // ]
// remove empty text nodes - convert live NodeList to array
var children = _toConsumableArray(row.querySelector('.mw-changeslist-line-inner').childNodes);
var _iterator3 = _createForOfIteratorHelper(children),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var child = _step3.value;
if (child.nodeType === Node.TEXT_NODE) {
child.remove();
}
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
}
function cleanSingleLog(row) {
row.classList.add('gadget-rc-row', 'gadget-rc-log');
// FIRST COLUMN: log name
row.querySelector('.mw-changeslist-line-inner-logLink').classList.add('gadget-rc-col-1');
// SECOND COLUMN: placeholder with separator dots
row.querySelector('.mw-changeslist-line-inner-separatorAfterLinks').classList.add('gadget-rc-col-2');
// THIRD COLUMN: user info
var col3 = document.createElement('span');
col3.classList.add('gadget-rc-col-3');
col3.append(get('.mw-changeslist-line-inner-logEntry', row), get('.mw-changeslist-line-inner-tags', row), get('.mw-changeslist-line-inner-watchingUsers', row));
row.querySelector('.gadget-rc-col-2').after(col3);
cleanUserLinks(row);
}
function cleanSingleEdit(row) {
row.classList.add('gadget-rc-row', 'gadget-rc-edit');
// FIRST COLUMN: page name
row.querySelector('.mw-changeslist-line-inner-articleLink').classList.add('gadget-rc-col-1');
// SECOND COLUMN: diff text
var col2 = document.createElement('span');
col2.classList.add('gadget-rc-col-2');
col2.append(get('.mw-changeslist-line-inner-historyLink', row), get('.mw-changeslist-line-inner-characterDiff', row));
row.querySelector('.gadget-rc-col-1').after(col2);
// THIRD COLUMN: user info
var col3 = document.createElement('span');
col3.classList.add('gadget-rc-col-3');
col3.append(get('.mw-changeslist-line-inner-userLink', row), get('.mw-changeslist-line-inner-userTalkLink', row), get('.mw-changeslist-line-inner-comment', row), get('.mw-changeslist-line-inner-rollback', row), get('.mw-changeslist-line-inner-tags', row), get('.mw-changeslist-line-inner-watchingUsers', row));
col2.after(col3);
cleanUserLinks(row);
}
function cleanUserLinks(row) {
// if username has been revdeled (shows "(username removed)"), it has no links
if (row.querySelector('.history-deleted')) return;
// replace links with first letter of each link
var links = row.querySelectorAll('.mw-usertoollinks a');
var _iterator4 = _createForOfIteratorHelper(links),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var link = _step4.value;
link.textContent = link.textContent.slice(0, 1);
}
// rollback link doesn't exist if page creation or user does not have the right
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
if (row.querySelector('.mw-rollback-link')) {
row.querySelector('.mw-rollback-link a').textContent = 'rollback';
}
}
// add relative time (eg. "25m ago") to timestamp column as hover text
function addRelativeTime(row) {
// if row is a single row
var timestamp = row.getAttribute('data-mw-ts');
// if row is a grouped row
if (timestamp === null) {
timestamp = row.closest('table.mw-enhanced-rc').getAttribute('data-mw-ts');
}
// convert mw timestamp (eg. 20240906020749) to Date (equal to 2024-09-06, 02:07:49 UTC)
var _timestamp$match$grou = timestamp.match(/*#__PURE__*/_wrapRegExp(/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/, {
y: 1,
m: 2,
d: 3,
h: 4,
min: 5,
s: 6
})).groups,
y = _timestamp$match$grou.y,
m = _timestamp$match$grou.m,
d = _timestamp$match$grou.d,
h = _timestamp$match$grou.h,
min = _timestamp$match$grou.min,
s = _timestamp$match$grou.s;
var timestampObj = new Date("".concat(y, "-").concat(m, "-").concat(d, "T").concat(h, ":").concat(min, ":").concat(s, ".000Z"));
// get time difference, then format into hours and minutes
var minsAgo = Math.floor((new Date() - timestampObj) / 1000 / 60);
var timeAgo;
if (minsAgo === 0) {
timeAgo = 'Now!';
} else if (minsAgo < 60) {
timeAgo = minsAgo + 'm ago';
} else {
timeAgo = Math.floor(minsAgo / 60) + 'h ' + minsAgo % 60 + 'm ago';
}
get('.mw-enhanced-rc', row).setAttribute('title', timeAgo);
}
// return element if it exists; if not, fail silently (unlike querySelector, which returns null)
function get(selector) {
var scope = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document;
var element = scope.querySelector(selector);
return element ? element : '';
}
function init() {
mw.hook('structuredChangeFilters.ui.initialized').add(function () {
// initial load
runReadableRC($('.mw-changeslist'));
// page refreshed with new edits / "Live updates" on
mw.hook('wikipage.content').add(runReadableRC);
});
}
$(init);
})(jQuery, mediaWiki);
// </nowiki>