Colour Bag

Lets you colour inventory text in KOL. Click on inventory item text to rotate colours.

// ==UserScript==
// @name           Colour Bag
// @namespace      kol.interface.unfinished
// @description    Lets you colour inventory text in KOL.  Click on inventory item text to rotate colours.
// @include        https://*kingdomofloathing.com/inventory.php*
// @include        https://*kingdomofloathing.com/storage.php*
// @include        https://*kingdomofloathing.com/managestore.php*
// @include        https://*kingdomofloathing.com/multiuse.php*
// @include        https://*kingdomofloathing.com/managecollection.php*
// @include        https://*kingdomofloathing.com/town_sellflea.php*
// @include        https://*kingdomofloathing.com/wand.php*
// @include        https://*kingdomofloathing.com/familiar.php*
// @include        https://*kingdomofloathing.com/craft.php*
// @include        https://*kingdomofloathing.com/knoll.php*
// @include        https://*kingdomofloathing.com/hiddencity.php*
// @include        https://*kingdomofloathing.com/closet.php*
// @include        https://*kingdomofloathing.com/clan_stash.php*
// @include        https://*kingdomofloathing.com/lair*
// @include        https://*kingdomofloathing.com/fight.php*
// @include        https://*kingdomofloathing.com/town_right.php?place=untinker*
// @include        https://*kingdomofloathing.com/account.php
// @grant          GM_getValue
// @grant          GM_setValue
// @version        2.12
// ==/UserScript==

// Version 2.12
// - switch to https
// Version 2.11
// - add @grant, convert GM_log to console.log
// Version 2.1
// - now allows colours to be set in Hagnk's
// - added a lock option to avoid accidental re-settings
// Version 2.0.1
//  - added fight page so combat items are coloured (old style combat only)
// Version 2.0
//  - major redesign, now based on item id instead of descitem
//  - now applies to many more lists
//  - now applies when extra drop-downs are created (mall, collection, etc)
//  - now applies to recently equipped list
//  - as a tradeoff, colour does not show up in actual equipped items any more
// Version 1.1
//  - now colours items in many lists (Hagnks, mall, zapping, flea market)
// Version 1.0

// Feel free to add or remove colour names.
// (the first entry is special, don't change it.)
var colourarray = ['','red','green','blue','orange', 'brown', 'purple', 'steelblue', 'silver', 'seagreen', 'SandyBrown', 'crimson' ];

// attribute name for storing colour in clickable entries
var tddcolour='colourbagcolour';
// attribute name for storing item id in clickable entries
var tdditemid='colourbagitem';
// id of script holding inserted css text
var finalcssid='colourbagcssid';
// greasemonkey global var for storing colour list
var clist='colourlist2';

// permanent storage, and update the current css
function saveColourlist(cl) {
    var s = '';
    for (var d in cl) {
        if (cl[d])
            s += d+':'+cl[d]+';';
    }
    GM_setValue(clist,s);
    createCss(cl);
}

// load the colourlist; consists of itemid:colour pairs
function loadColourlist() {
    var colourlist={};
    var s = GM_getValue(clist,'');
    if (s!='') {
        var sp = s.split(';');
        for (var i=0;i<sp.length;i++) {
            var r = sp[i].split(':');
            if (r.length==2) {
                colourlist[r[0]]=r[1];
            }
        }
    }
    return colourlist;
}

// main function to add colour toggling links in the inventory pane
function addEditLinks(page,doc) {
    var colourlist=loadColourlist();
    // look for td's with an id attribute consisting of
    // 'i' followed by numbers
    var elts = document.getElementsByTagName('td');
    for (var i=0;i<elts.length;i++)  {
        var tdd = elts[i];
        var tddid = tdd.getAttribute('id');
        if (tddid && tddid.match(/i[0-9]*/)) {
            // found an entry
            tddid=tddid.substr(1);
            // the text is the first bold therein
            var bref = tdd.getElementsByTagName('b');
            if (bref.length>0) {
                // found text
                var t = bref[0];
                t.title='Click to change colour.';
                t.setAttribute(tdditemid,tddid);
                if (colourlist[tddid]) {
                    t.setAttribute(tddcolour,colourlist[tddid]);
                }
                // add up and down event listeners
                t.addEventListener("click", changeColourUp, true);
                t.addEventListener("contextmenu", changeColourDown, true);
            } 
        }
    }
}

// handler for left clicking
function changeColourUp(e) {
    changeColour(this,false);
}

// handler for right clicking
function changeColourDown(e) {
    changeColour(this,true);
    if (e.stopPropagation) 
        e.stopPropagation();
}

// common handler function for changing colour
function changeColour(x,dec) {
    // get original colour
    var orgcolour=x.getAttribute(tddcolour);
    // get item id
    var desc=x.getAttribute(tdditemid);
    var newcolour;
    if (!orgcolour) {
        if (!dec)
            newcolour=colourarray[1];
        else
            newcolour=colourarray[colourarray.length-1];
    } else {
        for (var i=0;i<colourarray.length;i++) {
            if (colourarray[i]==orgcolour) {
                if (!dec)
                    newcolour = colourarray[(i+1)%(colourarray.length)];
                else
                    newcolour = colourarray[((i-1)<0) ? (colourarray.length-1) : i-1];
                break;
            }
        }
    }
    var colourlist=loadColourlist();
    if (newcolour=='') {
        colourlist[desc]=null;
        x.removeAttribute(tddcolour);
    } else if (newcolour) {
        colourlist[desc]=newcolour;
        x.setAttribute(tddcolour,newcolour);
    }
    saveColourlist(colourlist);
}

// routine to add or modify our css; heavily modified from Dive Into Greasemonkey
function addGlobalStyle(css,id) {
    var head, style;
    head = document.getElementsByTagName('head')[0];
    if (!head) { return; }
    style = document.getElementById(id);
    if (!style) {
        //console.log("Creating first css");
        style = document.createElement('style');
        style.type = 'text/css';
        style.setAttribute('id',id);
        style.innerHTML = css;
        head.appendChild(style);
    } else {
        //console.log("Replacing existing css");
        style.innerHTML = css;
    }
}

// main function to create or modify the css for our colours
// idea: have a rule for each colour
// with a big selector, choosing 
//  1) bold elements as first children of a td with the corresponding item id
//  2) option elements with a value of the id
function createCss(cl) {
    var icl={};
    for (var d in cl) {
        var c = cl[d];
        if (!c)
            continue;
        if (icl[c])
            icl[c]=icl[c]+', td[id="i'+d+'"]>b, option[value="'+d+'"]';
        else
            icl[c]='td[id="i'+d+'"]>b, option[value="'+d+'"]';
    }
    var finalcss='';
    for (var c in icl) {
        if (icl[c])
            finalcss += icl[c]+' { color:'+c+'; } ';
    }
    //console.log("finalcss="+finalcss);
    addGlobalStyle(finalcss,finalcssid);
}


// --------------------------------------------
// ---------- account menu option -------------
// --------------------------------------------


// Charon's code
function buildPrefs() {
    if (!document.querySelector('#privacy'))
        return;
    if (!document.querySelector('#scripts')) {
        //scripts tab is not built, do it here
        var scripts = document.querySelector('ul').appendChild(document.createElement('li'));
        scripts.id = 'scripts';
        var a = scripts.appendChild(document.createElement('a'));
        a.href = '#';
        var img = a.appendChild(document.createElement('img'));
        img.src = 'http://images.kingdomofloathing.com/itemimages/cmonkey1.gif';
        img.align = 'absmiddle';
        img.border = '0';
        img.style.paddingRight = '10px';
        a.appendChild(document.createTextNode('Scripts'));
        a.addEventListener('click', function (e) {
                //make our new tab active when clicked, clear out the #guts div and add our settings to it
                e.stopPropagation();
                document.querySelector('.active').className = '';
                document.querySelector('#scripts').className = 'active';
                document.querySelector('#guts').innerHTML = '<div class="scaffold"></div>';
                document.querySelector('#guts').appendChild(getSettings());
            }, false);
    } else {
        //script tab already exists
         document.querySelector('#scripts').firstChild.addEventListener('click', function (e) {
                //some other script is doing the activation work, just add our settings
                e.stopPropagation();
                document.querySelector('#guts').appendChild(getSettings());
            }, false);
    }
}

function getSettings() {
    //build our settings and return them for appending
    var contents = document.createElement('div');
    contents.id = 'recipecounterprefs';
    var fieldset = contents.appendChild(document.createElement('fieldset'));
    fieldset.setAttribute('style', 'width:33%; margin-top:20px');
    var legend = fieldset.appendChild(document.createElement('legend'));
    legend.className = 'subhead';
    legend.textContent = 'Colour Bag';
    var section = fieldset.appendChild(document.createElement('div'));
    section.className = 'indent';
    section.appendChild(buildSettings());
    return contents;
}

function buildSettings() {
    var d = document.createElement('div');
    d.appendChild(document.createTextNode('Lock colour settings: '));
    var ar = document.createElement('a');
    ar.setAttribute('href','#');
    if (GM_getValue('locked',false)) {
        ar.appendChild(document.createTextNode('now locked'));
        ar.setAttribute('title','Changing text colours is now prevented.  Click to toggle.');
    } else {
        ar.appendChild(document.createTextNode('now unlocked'));
        ar.setAttribute('title','Changing text colours is now allowed.  Click to toggle.');
    }
    ar.addEventListener('click',toggleLock,false);
    ar.setAttribute('id','colourbaglock');
    //li.appendChild(ar);
    //ul.appendChild(li);
    d.appendChild(ar);
    return d;
}

function toggleLock() {
    var ar = document.getElementById('colourbaglock');
    if (GM_getValue('locked',false)) {
        GM_setValue('locked','');
        ar.replaceChild(document.createTextNode('now unlocked'),ar.firstChild);
        ar.setAttribute('title','Changing text colours is now allowed.  Click to toggle.');
    } else {
        GM_setValue('locked','true');
        ar.replaceChild(document.createTextNode('now locked'),ar.firstChild);
        ar.setAttribute('title','Changing text colours is now prevented.  Click to toggle.');
    }
}

// grab the stored colour list
var firstcl = loadColourlist();
// create the css
createCss(firstcl);

// if in inventory frame, add edit links too
if (window.location.pathname.indexOf('/inventory.php')>=0 || window.location.pathname.indexOf('/storage.php')>=0) {
    if (!GM_getValue('locked',false))
        addEditLinks();
} else if (window.location.pathname.indexOf('/account.php')==0) {
    buildPrefs();
}