14,178
edits
Greenpickle (talk | contribs) m (WTF) |
Greenpickle (talk | contribs) No edit summary |
||
(9 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
window. | if (window.RCNSTDefaultToVisible === undefined) | ||
if ( | var RCNSTDefaultToVisible = true; | ||
if (window.RCNSTStartHidden === undefined) var RCNSTStartHidden = []; | |||
if (window.RCNSTStartVisible === undefined) var RCNSTStartVisible = []; | |||
if (window.RCNSTControlsID === undefined) var RCNSTControlsID = 'rcnst'; | |||
if (window.RCNSTClass === undefined) var RCNSTClass = 'rcnst'; | |||
if (window.RCNSTMain === undefined) var RCNSTMain = '(Main)'; | |||
if (window.RCNSTToggleAllLabel === undefined) | |||
var RCNSTToggleAllLabel = 'toggle all'; | |||
if (window.RCNSTInvertLabel === undefined) | |||
var RCNSTInvertLabel = 'invert selection'; | |||
if (window.RCNSTRestoreLabel === undefined) | |||
var RCNSTRestoreLabel = 'restore default'; | |||
if (window.hasClass === undefined) { | |||
var hasClass = (function () { | |||
var reCache = {}; | |||
return function (element, className) { | |||
return (reCache[className] ? reCache[className] : (reCache[className] = | |||
new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"))) | |||
.test(element.className); | |||
}; | |||
})(); | |||
} | |||
function nextElement (e) { | |||
do e = e.nextSibling; | |||
while (e !== null && e.nodeType != 1); | |||
return e; | |||
} | |||
function previousElement (e) { | |||
do e = e.previousSibling; | |||
while (e !== null && e.nodeType != 1); | |||
return e; | |||
} | |||
if (!Array.indexOf) { | |||
Array.prototype.indexOf = function (o) { | |||
var i = this.length; | |||
while (i--) if (this[i] === o) return i; | |||
return -1; | |||
}; | |||
} | |||
var RCNST = {}; | |||
RCNST.getDefault = function (changeType) { | |||
if (RCNSTDefaultToVisible) | |||
return RCNSTStartHidden.indexOf(changeType) == -1; | |||
else | |||
return RCNSTStartVisible.indexOf(changeType) != -1; | |||
}; | |||
RCNST.classRegex = new RegExp('\\b' + RCNSTClass + '\\b', 'g'); | |||
RCNST.getChangeType = function (change) { | |||
var result; | |||
var lnks = change.getElementsByTagName('a'); | |||
var lnk = lnks[0].firstChild.nodeValue; | |||
var isEdit = false; | |||
if (RCNST.enh) { | |||
if (lnks[0].parentNode.firstChild.nodeValue.indexOf('(') == -1) | |||
isEdit = true; | |||
} else { | |||
if (lnk == 'diff' || lnk == 'hist') { | |||
var isEdit = true; | |||
if (lnk == 'diff') lnk = 2; | |||
else lnk = 1; // new page | |||
lnk = lnks[lnk].firstChild.nodeValue; | |||
} | |||
} | } | ||
if (isEdit) { | |||
for (i | // work out namespace | ||
if ( | var colon = lnk.indexOf(':'); | ||
if (colon == -1) result = RCNSTMain; | |||
else result = lnk.substring(0, colon); | |||
} else result = lnk; // log | |||
return result; | |||
}; | |||
RCNST.toggle = function (changeType) { | |||
// show/hide changes of given type according to corresponding checkbox | |||
var show = RCNST.checkboxes[changeType].checked; | |||
var changes = RCNST.changes[changeType]; | |||
if (show) var reg = RCNST.classRegex; | |||
for (var i = 0; i < changes.length; i++) { | |||
if (RCNST.enh) { | |||
var div = nextElement(changes[i]); | |||
if (div !== null && div.tagName.toLowerCase() == 'div') { | |||
// also do the same for the subchanges | |||
if (show) | |||
// remove class | |||
div.className = div.className.replace(reg, ' '); | |||
else div.className += ' ' + RCNSTClass; // add class | |||
} | |||
} | |||
if (show) | |||
// remove class | |||
changes[i].className = changes[i].className.replace(reg, ' '); | |||
else changes[i].className += ' ' + RCNSTClass; // add class | |||
} | } | ||
}; | |||
RCNST(); | RCNST.smartToggle = function (changeType, show) { | ||
} | // set changes of given type to given visibility if not already | ||
function RCNST () { | var c = RCNST.checkboxes[changeType]; | ||
for (i | var shown = c.checked; | ||
if (document. | if (shown != show) { | ||
else | c.checked = show; | ||
RCNST.toggle(changeType); | |||
} | |||
}; | |||
RCNST.toggleAll = function () { | |||
// if any types are hidden, show them all, else hide them all | |||
var show = false; | |||
for (var changeType in RCNST.checkboxes) { | |||
if (!RCNST.checkboxes[changeType].checked) { | |||
show = true; | |||
break; | |||
} | |||
} | |||
for (var changeType in RCNST.checkboxes) | |||
RCNST.smartToggle(changeType, show); | |||
RCNST.updateHeadings(); | |||
}; | |||
RCNST.invert = function () { | |||
for (var changeType in RCNST.checkboxes) | |||
RCNST.smartToggle(changeType, !RCNST.checkboxes[changeType].checked); | |||
RCNST.updateHeadings(); | |||
}; | |||
RCNST.restore = function () { | |||
for (var changeType in RCNST.checkboxes) | |||
RCNST.smartToggle(changeType, RCNST.getDefault(changeType)); | |||
RCNST.updateHeadings(); | |||
}; | |||
RCNST.updateHeadings = function () { | |||
// hide headings if all changes in them are hidden, else show them | |||
var enh = RCNST.enh; | |||
var reg = RCNST.classRegex; | |||
var h4s = document.getElementsByTagName('h4'); | |||
for (var i = 0; i < h4s.length; i++) { | |||
var h4 = h4s[i]; | |||
// check it's a valid header and get change list | |||
var section = nextElement(h4); | |||
if (section === null || section.tagName === undefined) continue; | |||
var sectionTag = section.tagName.toLowerCase(); | |||
if (enh) { | |||
if (sectionTag != 'div') continue; | |||
var changes = getElementsByClassName(section, 'table', | |||
'mw-enhanced-rc'); | |||
} else { | |||
if (sectionTag != 'ul' || !hasClass(section, 'special')) continue; | |||
var changes = section.getElementsByTagName('li'); | |||
} | |||
if (changes.length == 0) continue; | |||
// check changes under this heading | |||
var show = false; | |||
for (var j = 0; j < changes.length; j++) { | |||
if (changes[j].parentNode !== section) continue; | |||
if (!hasClass(changes[j], RCNSTClass)) { | |||
show = true; | |||
break; | |||
} | |||
} | |||
if (show) h4.className = h4.className.replace(reg, ' '); | |||
else if (!hasClass(h4, RCNSTClass)) h4.className += ' ' + RCNSTClass; | |||
} | |||
}; | |||
RCNST.init = function () { | |||
if (!hasClass(document.body, 'page-Special_RecentChanges') | |||
&& !hasClass(document.body, 'page-Special_Recentchanges') | |||
&& !hasClass(document.body, 'page-Special_Watchlist')) | |||
return; | |||
// compile per-type lists of RC changes | |||
var changes = {}; | |||
RCNST.changes = changes; | |||
var uls = getElementsByClassName(document, 'ul', 'special'); | |||
if (uls.length) { | |||
// normal RC | |||
RCNST.enh = false; | |||
for (var i = 0; i < uls.length; i++) { | |||
var lis = uls[i].getElementsByTagName('li'); | |||
for (var j = 0; j < lis.length; j++) { | |||
var change = lis[j]; | |||
var changeType = RCNST.getChangeType(change); | |||
if (changes[changeType] === undefined) | |||
changes[changeType] = [change]; | |||
else changes[changeType].push(change); | |||
} | |||
} | |||
} else { | |||
var tbls = getElementsByClassName(document, 'table', 'mw-enhanced-rc'); | |||
if (tbls.length) { | |||
// enhanced RC | |||
RCNST.enh = true; | |||
for (var i = 0; i < tbls.length; i++) { | |||
var tbl = tbls[i]; | |||
var tds = tbl.getElementsByTagName('td'); | |||
if (!hasClass(tds[0], 'mw-enhanced-rc')) continue; | |||
var changeType = RCNST.getChangeType(tds[1]); | |||
if (changes[changeType] === undefined) | |||
changes[changeType] = [tbl]; | |||
else changes[changeType].push(tbl); | |||
} | |||
} else return; // no changes | |||
} | } | ||
// add controls to page | |||
var rcoptions = getElementsByClassName(document, '*', 'rcoptions'); | |||
if (rcoptions.length) { | |||
for ( | // put with the other controls | ||
rcoptions[0].appendChild(document.createElement('hr')); | |||
var controls = document.createElement('span'); | |||
rcoptions[0].appendChild(controls); | |||
} else { | |||
// put before the first day heading | |||
var h4s = document.getElementsByTagName('h4'); | |||
for (var i = 0; i < h4s.length; i++) { | |||
var e = nextElement(h4s[i]); | |||
if (e !== null && e.tagName.toLowerCase() == 'ul' | |||
&& hasClass(e, 'special')) { | |||
var controls = document.createElement('div'); | |||
h4s[i].parentNode.insertBefore(controls, h4s[i]); | |||
break; | break; | ||
} | } | ||
} | |||
// if there are no day headings, I have no idea what's going on, so | |||
// just don't show them | |||
} | |||
controls.id = RCNSTControlsID; | |||
if ( | |||
// create ordered list of change types | |||
var changeTypes = []; | |||
// namespaces first | |||
var nsSelect = document.getElementById('namespace'); | |||
if (nsSelect !== null) { | |||
var optionList = nsSelect.getElementsByTagName('option'); | |||
for (var i = 0; i < optionList.length; i++) { | |||
if (optionList[i].value == '0') var ns = RCNSTMain; | |||
else var ns = optionList[i].firstChild.nodeValue; | |||
if (changes[ns] !== undefined) changeTypes.push(ns); | |||
} | } | ||
} | } | ||
} | // then logs | ||
var toSort = []; | |||
for (changeType in changes) | |||
if (changeTypes.indexOf(changeType) == -1) toSort.push(changeType); | |||
toSort.sort(); | |||
changeTypes = changeTypes.concat(toSort); | |||
// then create checkboxes in this order | |||
var checkboxes = {}; | |||
RCNST.checkboxes = checkboxes; | |||
for (var i = 0; i < changeTypes.length; i++) { | |||
var c = document.createElement('input'); | |||
checkboxes[changeTypes[i]] = c; | |||
c.type = 'checkbox'; | |||
c.onclick = function () { | |||
RCNST.toggle(this.nextSibling.firstChild.nodeValue); | |||
RCNST.updateHeadings(); | |||
}; | |||
c.checked = true; | |||
controls.appendChild(c); | |||
var label = document.createElement('label'); | |||
label.appendChild(document.createTextNode(changeTypes[i])); | |||
controls.appendChild(label); | |||
} | |||
RCNST.restore(); | |||
// add buttons to controls | |||
function addButton (label, onclick) { | |||
var button = document.createElement('input'); | |||
button.type = 'button'; | |||
button.value = label; | |||
button.onclick = RCNST[onclick]; | |||
controls.appendChild(button); | |||
} | |||
addButton(RCNSTToggleAllLabel, 'toggleAll'); | |||
addButton(RCNSTInvertLabel, 'invert'); | |||
addButton(RCNSTRestoreLabel, 'restore'); | |||
if (RCNST.enh) { | |||
// replace enhanced RC event for the arrow things | |||
window.toggleVisibility = function(idNumber) { | |||
var openarrow = document.getElementById("mw-rc-openarrow-"+idNumber); | |||
var closearrow = document.getElementById("mw-rc-closearrow-"+idNumber); | |||
var subentries = document.getElementById("mw-rc-subentries-"+idNumber); | |||
if (openarrow.className == 'mw-changeslist-expanded') { | |||
openarrow.className = 'mw-changeslist-hidden'; | |||
closearrow.className = 'mw-changeslist-expanded'; | |||
subentries.className = subentries.className.replace( | |||
/\bmw-changeslist-hidden\b/, 'mw-changeslist-expanded'); | |||
} else { | |||
openarrow.className = 'mw-changeslist-expanded'; | |||
closearrow.className = 'mw-changeslist-hidden'; | |||
subentries.className = subentries.className.replace( | |||
/\bmw-changeslist-expanded\b/, 'mw-changeslist-hidden'); | |||
} | |||
}; | |||
} | |||
}; | |||
// initialise on page load | |||
if (window.domReady !== undefined) domReady(RCNST.init); | |||
else $(RCNST.init); |
edits