User:Bradv/Scripts/CategoryMonitor.js

Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
catmon = {
    enabled: true,
    paused: false,
    category: '',
    cmcontinue: '',
    sortbytimestamp: false,
    refreshfrequency: 0,
    zIndex: 101,
    width: '200',
    history: '',

    loadCookies: function() {
        catmon.enabled = (catmon.readCookie('catmon_enabled')=='true');
        catmon.category = (catmon.readCookie('catmon_category'));
        catmon.cmcontinue = (catmon.readCookie('catmon_cmcontinue'));
        catmon.sortbytimestamp = (catmon.readCookie('catmon_sortbytimestamp')=='true');
        catmon.history = (catmon.readCookie('catmon_history'));
        catmon.width = (catmon.readCookie('catmon_width'));
        if (!catmon.width || !catmon.width.length) catmon.width='200';
    },

    saveCookies: function() {
        var cend = "; expires=Tue, 31-Dec-2030 23:59:59 GMT; path=/";
        
        document.cookie = 'catmon_enabled=' + catmon.enabled.toString() + cend;
        document.cookie = 'catmon_category=' + catmon.category.toString() + cend;
        document.cookie = 'catmon_cmcontinue=' + catmon.cmcontinue.toString() + cend;
        document.cookie = 'catmon_sortbytimestamp=' + catmon.sortbytimestamp.toString() + cend;
        document.cookie = 'catmon_width=' + catmon.width.toString() + cend;
        document.cookie = 'catmon_history=' + catmon.history.toString() + cend;
    },

    pause: function () {
        catmon.paused=true;
        p = document.getElementById('catmon_ovl');
        if (p) {
	    p.style.display='';
        }
    },

    refresh: function () {
        if(catmon.paused) {
	    catmon.paused=false;
	    p = document.getElementById('catmon_ovl');
	    if (p) {
	        p.style.display='none';
	    }
	    catmon.loadCookies();
	    catmon.draw();
        } else {
            catmon.populate();
        }
    },

    init: function () {
        catmon.loadCookies();
        catmon.makeStartLink();
        catmon.draw();

        window.onblur = catmon.pause;
        window.onfocus = catmon.refresh;
        importStylesheetURI('/skins-1.5/common/diff.css');
    },

    makeStartLink: function () {
        if (mw.config.get('wgCanonicalNamespace') == 'Category') {
            var heading = document.getElementById('firstHeading');
            var span = document.createElement('span');
            span.style.fontSize='50%';
            span.appendChild(document.createTextNode(' ['));
            var a = document.createElement('a');
            a.setAttribute('href', '#');
            a.onclick = function () {
                catmon.category = mw.config.get('wgPageName');
                catmon.enabled = true;
                catmon.cmcontinue = '';
                catmon.draw();
                return false;
            }
            a.appendChild(document.createTextNode('Load this category in sidebar'));
            span.appendChild(a);
            span.appendChild(document.createTextNode(']'));
            heading.appendChild(span);
        }
    },

    resize: function() {
        if (catmon.width < 25) {
            catmon.width = 0;
        } else if (catmon.width < 200) {
            catmon.width = 200;
        } else if (catmon.width > (document.body.clientWidth / 2)) {
            catmon.width = (document.body.clientWidth / 2);
        }
        var sb = document.getElementById('catmon');
        sb.style.width=catmon.width + 'px';
        var rb = document.getElementById('catmon_resize');
        rb.style.right=catmon.width + 'px';

        //Set the spacer between the main body and the sidebar
        var spacer = (sb.offsetWidth+rb.offsetWidth)+'px';        
        topbar = document.evaluate('//div[@id="p-personal"]//div[@class="pBody"]', 
            document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
        if (topbar.singleNodeValue) {
            topbar.singleNodeValue.style.marginRight=spacer;
        }
        sb.parentNode.style.marginRight=spacer;
    },

    draw: function() {
        catmon.saveCookies();
        var sb = document.getElementById('catmon');        
        if (catmon.enabled && catmon.category.length) {
	    if (sb) {
	        sb.style.display='';
                rb.style.display='';
	    } else {
	        //Create the main sidebar
	        sb = document.createElement('div');
	        sb.id='catmon';
	        sb.className='portlet';
                if (document.getElementById('menubar')) {
                    sb.style.top=document.getElementById('menubar').offsetHeight + 'px';
                }
                else {
      	            sb.style.top='0px';
                }
	        sb.style.right='0px';
	        sb.style.bottom='0px';
	        sb.style.zIndex=90;
	        sb.style.margin='0';//'.1em';
	        sb.style.padding='0em';
                sb.style.backgroundColor='gray';
	        sb.style.position='absolute';
	        sb.style.borderLeft='1px solid #bbbbbb;';
	        sb.style.backgroundColor=document.defaultView.getComputedStyle(document.body, null).backgroundColor;
	        sb.style.position='fixed';

	        //Find the container where the sprint bar goes.
	        //This differs between monobook and modern skins.
	        container = document.getElementById('content');
	        if (!container) {
	            container = document.getElementById('mw_content');
	        }
	        container.appendChild(sb);

                //Create the resize bar
                rb = document.createElement('div');
                rb.id='catmon_resize';
                rb.style.display='';
                rb.style.position='fixed';
                rb.style.top='0px';
                rb.style.height='100%';
                rb.style.width='5px';
                rb.style.cursor='ew-resize';
                rb.onmouseover = function (evt) {
                    rb.style.backgroundColor='lightgray';
                };
                rb.onmouseout = function (evt) {
                    rb.style.backgroundColor='';
                };
                rb.onmousedown = function () {
                    var w = catmon.width;
                    rb.onmouseout = null;
                    window.onmousemove = function (evt) {
                        catmon.width = document.body.clientWidth - evt.pageX;
                        catmon.resize();
                    };
                    window.onmouseup = function (evt) {
                        if ((document.body.clientWidth - evt.pageX)<25) {
                            catmon.enabled=false;
                            catmon.width=w;
                            catmon.draw();
                        }
                        window.onmousemove = null;
                        window.onmouseup = null;
                        rb.style.backgroundColor='';
                        rb.onmouseout = function (evt) {
                            rb.style.backgroundColor='';
                        };
                        catmon.saveCookies();
                    };
                    return false;
                };
                container.appendChild(rb);

	        //Create the overlay for when it is paused (out of focus)
	        ovl = document.createElement('div');
	        ovl.id='catmon_ovl';
	        ovl.style.position='absolute';
	        ovl.style.top='0px';
	        ovl.style.right='0px';
	        ovl.style.width='100%';
	        ovl.style.height='100%';
	        ovl.style.borderLeft='1px solid #bbbbbb;';
	        ovl.style.backgroundColor=document.defaultView.getComputedStyle(document.body, null).backgroundColor;
	        ovl.zIndex=100;
	        ovl.style.display='none';
	        
	        p = document.createElement('p');
	        p.style.position='absolute';
	        p.style.top='5em';
	        p.style.width='100%';
	        p.style.fontSize='1em';
	        p.style.lineHeight='2em';
	        p.style.textAlign='center';
	        p.style.color='#bbbbbb';
	        p.appendChild(document.createTextNode('Updates paused'));
	        p.appendChild(document.createElement('br'));
	        p.appendChild(document.createTextNode('Click to resume'));
	        ovl.appendChild(p);
	        sb.appendChild(ovl);
	    }

            catmon.resize();
	
	    //TODO: Draw the category data
	    catmon.drawList();
	
        } else { //Hide the sprint bar, if it has already been drawn
	    topbar = document.evaluate('//div[@id="p-personal"]//div[@class="pBody"]', 
	        document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
	    if (topbar.singleNodeValue) {
	        topbar.singleNodeValue.style.marginRight='';
	    }
	    if (sb) {
	        sb.parentNode.style.marginRight='';
	        sb.style.display='none';     
                rb.style.display='none';  
	    }
        }
    },

    drawList: function() {
        var cmtitlehdr = catmon.category.replace('Category:','').replace('_',' ');
        var cmtitlehref = '/wiki/' + catmon.category;

        var sb = document.getElementById('catmon');
        var a;
        var hdr = document.getElementById('catmon_hdr');
        if (hdr) {
	    while (hdr.firstChild) {
	        hdr.removeChild(hdr.firstChild);
	    }
        } else {
	    hdr = document.createElement('p');
	    hdr.id = 'catmon_hdr';
            hdr.style.marginLeft='5px';
            hdr.style.marginRight='5px';
            hdr.style.fontSize='90%';
	    sb.appendChild(hdr);
        }
        var a = document.createElement('a');
        a.setAttribute('nopopup', 'true');
        a.id = 'catmon_link';
        a.setAttribute('href', cmtitlehref);
        a.appendChild(document.createTextNode(cmtitlehdr.replace('_', ' ', 'g')));
        hdr.appendChild(a);

        var p = document.getElementById('catmon_body');
        if (!p) {
	    p = document.createElement('div');
	    p.setAttribute('class', 'pBody');
	    p.setAttribute('id', 'catmon_body');
            p.style.top=hdr.offsetTop+hdr.offsetHeight+'px';
            p.style.bottom='2em';
            p.style.right='5px';
            p.style.left='5px';
            p.style.overflow='hidden';
            p.style.position='absolute';
	    sb.appendChild(p);
        }

        var foot = document.getElementById('catmon_foot');
        if (!foot) {
            foot = document.createElement('div');
            foot.setAttribute('id', 'catmon_foot');
            foot.style.position='fixed';
            foot.style.bottom='5px';
            foot.style.right='5px';
            foot.style.fontSize='90%';
            sb.appendChild(foot);
        }

        catmon.populate();

    },

    populate: function() {
        var cmtitle = catmon.category;
        var cmlimit = 50;
        var cmcontinue = catmon.cmcontinue;
        var sortbytimestamp = catmon.sortbytimestamp;
        var query = '/w/api.php?action=query&format=xml&list=categorymembers';
        if (sortbytimestamp) {
            query += '&cmsort=timestamp&cmprop=title|timestamp&cmtitle=' + catmon.category + '&cmlimit=' + cmlimit;
            if (cmcontinue.length) query += '&cmstart=' + cmcontinue;
        } else {
            query += '&cmprop=title|sortkey&cmtitle=' + catmon.category + '&cmlimit=' + cmlimit;
            if (cmcontinue.length) query += '&cmcontinue=' + cmcontinue;
        }
//document.getElementById('firstHeading').textContent=query;

        var callback = function(xml) {
            pBody = document.getElementById('catmon_body');
            while (pBody.firstChild) {
                pBody.removeChild(pBody.firstChild);
            }
            var items = xml.documentElement.getElementsByTagName('cm');
            for (var i=0; i<items.length; i++) {
                var title = items[i].getAttribute('title');
                var p = document.createElement('p');
                p.setAttribute('sortkey', items[i].getAttribute('sortkey'));
                p.setAttribute('timestamp', items[i].getAttribute('timestamp'));
                p.style.lineHeight='1.1em';
                p.style.fontSize='95%';
                var a = document.createElement('a');
                //a.setAttribute('nopopup', 'true');
                a.href='/wiki/' + encodeURIComponent(title);
                a.appendChild(document.createTextNode(title));
                p.appendChild(a);
                pBody.appendChild(p);
                
            }

            var foot = document.getElementById('catmon_foot');
            while (foot.firstChild) {
                foot.removeChild(foot.firstChild);
            }
            var aRf = document.createElement('a');
            aRf.setAttribute('id', 'catmon_refresh');
            aRf.setAttribute('href', '#');
            aRf.appendChild(document.createTextNode('refresh'));
            aRf.onclick = function () {
                catmon.refresh();
                return false;
            }
            foot.appendChild(aRf);
            foot.appendChild(document.createTextNode(' | '));

            var ahide = document.createElement('a');
            ahide.id = 'catmon_hide';
            ahide.setAttribute('href', '#');
            ahide.appendChild(document.createTextNode('hide'));
            ahide.onclick = function () {
                catmon.enabled = false;
                catmon.draw();
                return false;
            };
            foot.appendChild(ahide);
            foot.appendChild(document.createTextNode(' | '));

            var aSort = document.createElement('a');
            aSort.setAttribute('id', 'catmon_sort');
            aSort.setAttribute('href', '#');
            aSort.appendChild(document.createTextNode('sort'));
            aSort.title = catmon.sortbytimestamp ? 'Sort alphabetically' : 'Sort by timestamp';
            aSort.onclick = function() {
                catmon.sortbytimestamp = !catmon.sortbytimestamp;
                catmon.cmcontinue='';
                catmon.saveCookies();
                catmon.refresh();
                return false;
            }
            foot.appendChild(aSort);
            foot.appendChild(document.createTextNode(' | '));

            if (cmcontinue.length) {
                var aTop = document.createElement('a');
                aTop.setAttribute('id', 'catmon_top');
                aTop.setAttribute('href', '#');
                aTop.appendChild(document.createTextNode('top'));
                aTop.onclick = function () {
                    catmon.cmcontinue = '';
                    catmon.saveCookies();
                    catmon.populate();
                    return false;
                }
                foot.appendChild(aTop);
            } else {
                foot.appendChild(document.createTextNode('top'));
            }
            foot.appendChild(document.createTextNode(' | '));
            var next = catmon.firstHidden();
            if (next.length) {
                var aMore = document.createElement('a');
                aMore.setAttribute('id', 'catmon_more');
                aMore.setAttribute('href', '#');
                aMore.appendChild(document.createTextNode('next'));
                aMore.onclick = function () {
                    catmon.cmcontinue = next;
                    catmon.saveCookies();
                    catmon.populate();
                    return false;
                }
                foot.appendChild(aMore);
            } else {
                foot.appendChild(document.createTextNode('next'));
            }
        }

        catmon.getUrl(query, callback);
        if (catmon.refreshfrequency) {
            window.setTimeout(catmon.refresh, catmon.refreshfrequency);
        }
    },

    firstHidden: function () {
        var pBody = document.getElementById('catmon_body');
        var p = pBody.firstChild;
        var limit = pBody.offsetHeight;
        while (p) {
            //var cs = window.getComputedStyle(p, null);
            if ((p.offsetTop + p.offsetHeight) > limit) {
                break;
            } else {
                p = p.nextSibling;
            }
        }
        if (p) {
            if (p.getAttribute('sortkey').length) return encodeURIComponent(p.getAttribute('sortkey')) + '|';
            else return p.getAttribute('timestamp');
        } else {
            return '';
        }
    },

    getUrlTimer: new Date(),

    getUrl: function (url, callback) {
        var now = new Date();
 
        catmon.getUrlTimer = now;
 
        var aj = sajax_init_object();
        aj.onreadystatechange = function () {
            if (aj.readyState == 4) {// && aj.status == 200) {
                callback(aj.responseXML);
            }
        }
        aj.open('GET', url, true);
        aj.send(null);
    },

    readCookie: function(name) {
        var nameEQ = name + "=";
        var ca = document.cookie.split(';');
        for(var i=0;i < ca.length;i++) {
	    var c = ca[i];
	    while (c.charAt(0)==' ') { c = c.substring(1,c.length); }
	    if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); }
        }
        return '';
    }
}
addOnloadHook(catmon.init);