User:Greenpickle/rcnst.js: Difference between revisions

From Pikipedia, the Pikmin wiki
Jump to navigation Jump to search
(Created page with "window.onload = function () { if (!"".indexOf || !"".substring || ![].push) return; if (document.body.className.indexOf("page-Special_RecentChanges") == -1 && document.bo...")
No edit summary
 
(2 intermediate revisions by 2 users not shown)
Line 1: Line 1:
window.onload = function () {
if (window.RCNSTDefaultToVisible === undefined)
     if (!"".indexOf || !"".substring || ![].push) return;
     var RCNSTDefaultToVisible = true;
    if (document.body.className.indexOf("page-Special_RecentChanges") == -1 && document.body.className.indexOf("page-Special_Recentchanges") == -1) return;
if (window.RCNSTStartHidden === undefined) var RCNSTStartHidden = [];
    choice = document.getElementById("namespace").childNodes;
if (window.RCNSTStartVisible === undefined) var RCNSTStartVisible = [];
     nslist = [];
if (window.RCNSTControlsID === undefined) var RCNSTControlsID = 'rcnst';
     for (i in choice) if (choice[i].tagName == "OPTION" && choice[i].value != "") nslist[choice[i].value] = choice[i].innerHTML;
if (window.RCNSTClass === undefined) var RCNSTClass = 'rcnst';
    loglist = [];
if (window.RCNSTMain === undefined) var RCNSTMain = '(Main)';
     enhanced = true;
if (window.RCNSTToggleAllLabel === undefined)
     if (document.getElementById("bodyContent").innerHTML.indexOf('<a href="/index.php?title=Special:RecentChanges&amp;hideenhanced=1" title="Special:RecentChanges">Hide</a> grouped recent changes') == -1) enhanced = false;
    var RCNSTToggleAllLabel = 'toggle all';
     if (enhanced) {
if (window.RCNSTInvertLabel === undefined)
         h4s = document.getElementsByTagName("h4");
    var RCNSTInvertLabel = 'invert selection';
        days = [];
if (window.RCNSTRestoreLabel === undefined)
         for (i = 0; i < h4s.length; i++) {
    var RCNSTRestoreLabel = 'restore default';
             days[i] = h4s[i].nextSibling;
 
             while (days[i].tagName != "DIV") days[i] = days[i].nextSibling;
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;
         }
         }
        for (i in days) {
    }
            if (days[i].tagName != "DIV") continue;
    if (isEdit) {
            items = days[i].childNodes;
        // work out namespace
            for (j = 0; j < items.length; j++) {
        var colon = lnk.indexOf(':');
                if (items[j].tagName != "TABLE") continue;
        if (colon == -1) result = RCNSTMain;
                logname = items[j].getElementsByTagName("a");
        else result = lnk.substring(0, colon);
                if (logname[0].getAttribute("href") == "#") logname = logname[2];
    } else result = lnk; // log
                else logname = logname[0];
    return result;
                if (logname.nextSibling) if(logname.nextSibling.nodeValue.substring(0, 1) == ")" && loglist.indexOf(logname.innerHTML) == -1) loglist.push(logname.innerHTML);
};
            }
 
        }
RCNST.toggle = function (changeType) {
    } else {
    // show/hide changes of given type according to corresponding checkbox
        days = document.getElementsByClassName("special");
    var show = RCNST.checkboxes[changeType].checked;
        for (i in days) {
    var changes = RCNST.changes[changeType];
            if (days[i].tagName != "UL") continue;
    if (show) var reg = RCNST.classRegex;
            items = days[i].childNodes;
    for (var i = 0; i < changes.length; i++) {
            for (j = 0; j < items.length; j++) {
        if (RCNST.enh) {
                if (items[j].tagName != "LI") continue;
            var div = nextElement(changes[i]);
                logname = items[j].getElementsByTagName("a")[0].innerHTML;
            if (div !== null && div.tagName.toLowerCase() == 'div') {
                if (logname != "diff" && logname != "hist" && loglist.indexOf(logname) == -1) loglist.push(logname);
                // 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
     }
     }
     temp = RCNSTList;
};
     RCNSTList = [];
 
     for (i in nslist) {
RCNST.smartToggle = function (changeType, show) {
         if (!include && (temp.indexOf(nslist[i]) != -1)) RCNSTList[i] = false;
    // set changes of given type to given visibility if not already
         else if (include && (temp.indexOf(nslist[i])) == -1) RCNSTList[i] = false;
     var c = RCNST.checkboxes[changeType];
     var shown = c.checked;
     if (shown != show) {
         c.checked = show;
         RCNST.toggle(changeType);
     }
     }
     for (i in loglist) {
};
         if (!include && (temp.indexOf(loglist[i]) != -1)) RCNSTList[loglist[i]] = false;
 
         else if (include && (temp.indexOf(loglist[i])) == -1) RCNSTList[loglist[i]] = false;
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;
         }
     }
     }
     s = RCNSTbeforecheckboxes;
     for (var changeType in RCNST.checkboxes)
     for (i in nslist) {
        RCNST.smartToggle(changeType, show);
        if (RCNSTList[i] == false) insert = '';
    RCNST.updateHeadings();
        else insert = 'checked="checked"';
};
         s += RCNSTbeforecheckbox + '<input type="checkbox" ' + insert + 'name="RCNST' + i + '" onclick="RCNSTupdate()" /><label for="RCNST' + i + '">' + nslist[i] + '</label>' + RCNSTaftercheckbox;
 
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;
     }
     }
    for (i in loglist) {
};
        if (RCNSTList[loglist[i]] == false) insert = '';
 
         else insert = 'checked="checked"';
RCNST.init = function () {
         s += RCNSTbeforecheckbox + '<input type="checkbox" ' + insert + 'name="RCNSTl' + i + '" onclick="RCNSTupdate()" /><label for="RCNSTl' + i + '">' + loglist[i] + '</label>' + RCNSTaftercheckbox;
    if (!hasClass(document.body, 'page-Special_RecentChanges')
    }
         && !hasClass(document.body, 'page-Special_Recentchanges')
     s += RCNSTbeforecheckbox + '<input type="button" onclick="RCNSTall()" value="toggle all" />' + RCNSTaftercheckbox;
         && !hasClass(document.body, 'page-Special_Watchlist'))
    s += RCNSTbeforecheckbox + '<input type="button" onclick="RCNSTinvert()" value="invert selection" />' + RCNSTaftercheckbox;
        return;
     s += RCNSTbeforecheckbox + '<input type="button" onclick="RCNSTrestore()" value="restore default" />' + RCNSTaftercheckbox;
 
     document.getElementsByClassName("rcoptions")[0].innerHTML += s;
     // compile per-type lists of RC changes
     RCNSTupdate();
     var changes = {};
     RCNSTListStore = [];
     RCNST.changes = changes;
    for (i in RCNSTList) RCNSTListStore[i] = RCNSTList[i];
     var uls = getElementsByClassName(document, 'ul', 'special');
}
     if (uls.length) {
function RCNSTupdate () {
        // normal RC
    for (i in nslist) {
         RCNST.enh = false;
         if (document.getElementsByName("RCNST" + i)[0].checked) RCNSTList[i] = true;
         for (var i = 0; i < uls.length; i++) {
         else RCNSTList[i] = false;
            var lis = uls[i].getElementsByTagName('li');
    }
            for (var j = 0; j < lis.length; j++) {
    for (i in loglist) {
                var change = lis[j];
        if (document.getElementsByName("RCNSTl" + i)[0].checked) RCNSTList[loglist[i]] = true;
                var changeType = RCNST.getChangeType(change);
        else RCNSTList[loglist[i]] = false;
                if (changes[changeType] === undefined)
    }
                    changes[changeType] = [change];
    if (enhanced) {
                else changes[changeType].push(change);
        h4s = document.getElementsByTagName("h4");
            }
        days = [];
        for (i = 0; i < h4s.length; i++) {
            days[i] = h4s[i].nextSibling;
            while (days[i].tagName != "DIV") days[i] = days[i].nextSibling;;
         }
         }
         for (i in days) {
    } else {
            needh4 = false;
         var tbls = getElementsByClassName(document, 'table', 'mw-enhanced-rc');
            if (days[i].tagName != "DIV") continue;
        if (tbls.length) {
             items = days[i].childNodes;
            // enhanced RC
             for (j = 0; j < items.length; j++) {
             RCNST.enh = true;
                 if (items[j].tagName != "TABLE") continue;
             for (var i = 0; i < tbls.length; i++) {
                 page = items[j].getElementsByTagName("a");
                 var tbl = tbls[i];
                 if (page[0].getAttribute("href") == "#") page = page[2];
                 var tds = tbl.getElementsByTagName('td');
                else page = page[0];
                 if (!hasClass(tds[0], 'mw-enhanced-rc')) continue;
                if (page.nextSibling) if(page.nextSibling.nodeValue.substring(0, 1) == ")") visible = RCNSTList[page.innerHTML];
                 var changeType = RCNST.getChangeType(tds[1]);
                 else {
                if (changes[changeType] === undefined)
                    if (RCNSTPageListInclude.indexOf(page.innerHTML) != -1) visible = true;
                     changes[changeType] = [tbl];
                    else if (RCNSTPageListExclude.indexOf(page.innerHTML) != -1) visible = false;
                 else changes[changeType].push(tbl);
                    else {
                        page = page.innerHTML;
                        page = page.substring(0, page.indexOf(":")).replace("_", " ").replace("_", " ");
                        page = nslist.indexOf(page);
                        if (page == -1) page = 0;
                        visible = RCNSTList[page];
                    }
                }
                div = items[j].nextSibling;
                if (!div.tagName) div = div.nextSibling;
                if (visible) {
                     if (items[j].className.indexOf(" rcnsthidden") != -1) items[j].className = items[j].className.substring(0, items[j].className.indexOf(" rcnsthidden"));
                    if (div) if (div.tagName == "DIV") if (div.className.indexOf(" rcnsthidden") != -1) div.className = div.className.substring(0, div.className.indexOf(" rcnsthidden"));
                    needh4 = true;
                 } else {
                    if (items[j].className.indexOf(" rcnsthidden") == -1) items[j].className += " rcnsthidden";
                    if (div) if (div.tagName == "DIV") if (div.className.indexOf(" rcnsthidden") == -1) div.className += " rcnsthidden";
                }
             }
             }
            h4 = days[i].previousSibling;
        } else return; // no changes
            while (h4.tagName != "H4") h4 = h4.previousSibling;
    }
            if (needh4) h4.removeAttribute("class");
 
            else h4.className = "rcnsthidden";
    // add controls to page
         }
    var rcoptions = getElementsByClassName(document, '*', 'rcoptions');
    if (rcoptions.length) {
        // put with the other controls
        rcoptions[0].appendChild(document.createElement('hr'));
        var controls = document.createElement('span');
         rcoptions[0].appendChild(controls);
     } else {
     } else {
         days = document.getElementsByClassName("special");
         // put before the first day heading
         for (i in days) {
        var h4s = document.getElementsByTagName('h4');
            needh4 = false;
         for (var i = 0; i < h4s.length; i++) {
            if (days[i].tagName != "UL") continue;
            var e = nextElement(h4s[i]);
            items = days[i].childNodes;
            if (e !== null && e.tagName.toLowerCase() == 'ul'
            for (j = 0; j < items.length; j++) {
                && hasClass(e, 'special')) {
                if (items[j].tagName != "LI") continue;
                var controls = document.createElement('div');
                page = items[j].getElementsByTagName("a");
                 h4s[i].parentNode.insertBefore(controls, h4s[i]);
                if (page[0].innerHTML == "diff") n = 2;
                 break;
                else if (page[0].innerHTML == "hist") n = 1;
                if (page[0].innerHTML == "diff" || page[0].innerHTML == "hist") {
                    if (RCNSTPageListInclude.indexOf(page[n].innerHTML) != -1) visible = true;
                    else if (RCNSTPageListExclude.indexOf(page[n].innerHTML) != -1) visible = false;
                    else {
                        page = page[0].href;
                        page = page.substring(page.indexOf("?title=") + 7);
                        page = page.substring(0, page.indexOf("&curid="));
                        page = page.substring(0, page.indexOf(":")).replace("_", " ").replace("_", " ");
                        page = nslist.indexOf(page);
                        if (page == -1) page = 0;
                        visible = RCNSTList[page];
                    }
                 } else visible = RCNSTList[page[0].innerHTML];
                if (visible) {
                    if (items[j].className.indexOf(" rcnsthidden") != -1) items[j].className =  items[j].className.substring(0, items[j].className.indexOf(" rcnsthidden"));
                    needh4 = true;
                 } else if (items[j].className.indexOf(" rcnsthidden") == -1) items[j].className += " rcnsthidden";
             }
             }
            h4 = days[i].previousSibling;
        }
            while (h4.tagName != "H4") h4 = h4.previousSibling;
        // if there are no day headings, I have no idea what's going on, so
             if (needh4) h4.removeAttribute("class");
        // just don't show them
             else h4.className = "rcnsthidden";
    }
    controls.id = RCNSTControlsID;
 
    // 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
function RCNSTall () {
    var toSort = [];
     on = false;
    for (changeType in changes)
     for (i in RCNSTList) if (!RCNSTList[i]) on = true;
        if (changeTypes.indexOf(changeType) == -1) toSort.push(changeType);
    for (i in nslist) RCNSTList[i] = on;
    toSort.sort();
     for (i in loglist) RCNSTList[loglist[i]] = on;
    changeTypes = changeTypes.concat(toSort);
     RCNSTsetboxes();
 
     RCNSTupdate();
    // then create checkboxes in this order
}
    var checkboxes = {};
function RCNSTinvert () {
     RCNST.checkboxes = checkboxes;
    for (i in RCNSTList) {
     for (var i = 0; i < changeTypes.length; i++) {
        if (RCNSTList[i]) RCNSTList[i] = false;
        var c = document.createElement('input');
        else RCNSTList[i] = true;
        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');
            }
        };
     }
     }
    RCNSTsetboxes();
};
    RCNSTupdate();
 
}
// initialise on page load
function RCNSTrestore () {
if (window.domReady !== undefined) domReady(RCNST.init);
    for (i in RCNSTListStore) RCNSTList[i] = RCNSTListStore[i];
else $(RCNST.init);
    RCNSTsetboxes();
    RCNSTupdate();
}
function RCNSTsetboxes () {
    for (i in nslist) document.getElementsByName("RCNST" + i)[0].checked = RCNSTList[i];
    for (i in loglist) document.getElementsByName("RCNSTl" + i)[0].checked = RCNSTList[loglist[i]];
}

Latest revision as of 16:18, August 13, 2018

if (window.RCNSTDefaultToVisible === undefined)
    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) {
        // work out namespace
        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.smartToggle = function (changeType, show) {
    // set changes of given type to given visibility if not already
    var c = RCNST.checkboxes[changeType];
    var shown = c.checked;
    if (shown != show) {
        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) {
        // 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;
            }
        }
        // if there are no day headings, I have no idea what's going on, so
        // just don't show them
    }
    controls.id = RCNSTControlsID;

    // 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);