3

So I've read a few similar questions, and I've managed to do things like change the background colour, but I have not yet been able to get this to work;

What I want, is for each subsequent letter on a page to be randomly coloured. The colour space used isn't really important, as that's easy to fix once it actually works (am using this one at the moment), but I can't even get the text to change colour yet. I'm hoping I'm just making a silly mistake somewhere...

This is what i'm trying at the moment; and it kind of works, but it's very dependant on what tagName i use, and because of the nature of most webpages, it can break a lot of things if i'm not careful...

jsFiddle

var elements = document.getElementsByTagName('p');
for(var i=0,l=elements.length;i<l;++i) {

    var str = elements[i].textContent;
    elements[i].innerHTML = '';

    for(var j=0,ll=str.length;j<ll;++j) {
        var n = document.createElement('span');
        elements[i].appendChild(n);
        n.textContent = str[j];
        n.style.color = get_random_colour();
    }
}
function get_random_colour() {
    var letters = '0123456789ABCDEF'.split('');
    var colour = '#';
    for (var i = 0; i < 6; i++ ) {
        colour += letters[Math.round(Math.random() * 15)];
    }
    return colour;
}​

In this example, p works fine, and doesn't seem to break anything, but if I do * or html or body then it breaks the page. Is there a way to get all the text on the page, and not break it?

And another thing; I later changed the colour function to hopefully only pick colours that are in HSV(random,1,1) so that i only get nice bright colours, but it's not working. I'm presuming I just have some JS error in there, but I'm not that familiar with JS, so I'm finding it hard to find...

Here are the changes

Community
  • 1
  • 1
will
  • 10,260
  • 6
  • 46
  • 69
  • If you're trying to do this on a long complicated page, then what you are asking for will be hard. There are elements and sub-elements that will break if you try things like this. What I would advise is that you try changing letter color only on `

    `, `

    `, and `` tags.
    – Ashley Strout May 14 '12 at 15:56
  • @David I realised this, using it on `
    ` is a complete no go, so many pages use `
    ` for formatting and it's nested so much.
    – will May 14 '12 at 16:06
  • ``, then? How does that work? – Ashley Strout May 14 '12 at 16:11

1 Answers1

2

To do this, you will want to recurse through just the text nodes, careful not to trash child HTML elements.

See the demo at jsFiddle.

var x  = document.querySelector ("body"); // Etc.
buggerTextNodesIn (x);

function buggerTextNodesIn (node) {
    var wrapClass   = 'gmColorBarf';

    function turnerizeTextNodes (node) {
        if (node.nodeType === Node.TEXT_NODE) {
            //--- Skip this node if it's already been wrapped.
            if ( ! node.parentNode.classList.contains (wrapClass) ) {
                var oldText = node.nodeValue;
                var parent  = node.parentNode;

                for (var J = 0, len = oldText.length;  J < len;  ++J) {
                    var wrapSpan    = document.createElement ("span");
                    wrapSpan.classList.add (wrapClass);
                    wrapSpan.textContent = oldText[J];
                    wrapSpan.style.color = getRandomColor ();

                    parent.insertBefore (wrapSpan, node);
                }
                parent.removeChild (node);
            }
        }
        else if (node.nodeType === Node.ELEMENT_NODE) {
            /*--- IMPORTANT! Start "bottom up" since we will be adding
                gazillions of nodes and "top down" would skew our length measurement.
            */
            for (var K = node.childNodes.length - 1;  K >= 0;  --K) {
                turnerizeTextNodes (node.childNodes[K] );
            }
        }
    }

    turnerizeTextNodes (node);
}


function getRandomColor () {
    var letters = '0123456789ABCDEF'.split ('');
    var color   = '#';
    for (var J = 0;  J < 6; ++J) {
        color += letters[Math.round(Math.random() * 15)];
    }
    return color;
}



Note that to get iframed content, the easiest way is to tune the @include, @exclude, and/or @match directives to trigger on the iframe URL(s) -- if they don't already.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • Okay this seems to work amazingly well in jsFiddle, but not at all when i put it in greasemonkey (or at least they don't work in TamperMonkey on chrome, which claims to be the same...). Any idea how i could get that to work? – will May 15 '12 at 06:31
  • This works perfectly well in a script, Greasemonkey on FF, Tampermonkey on Chrome, and plain content-script on Chrome. Just double-checked to make sure. **Link or post the exact script you tried.** Does your target page use frames, iframes, flash or AJAX? **Link to the target page.** – Brock Adams May 15 '12 at 14:33
  • Ah, brilliant, i guess i must have just been doing something wrong!! thanks... I will put this to, a good use... – will May 16 '12 at 20:41