reptile7's JavaScript blog
Friday, January 11, 2008
 
Coloring by Elements
Blog Entry #100

We continue today our discussion of the rainbow text script of HTML Goodies' JavaScript Script Tips #81-83. We noted in the previous post that the Script Tips #81-83 Script commingles its document body HTML with some of its JavaScript, which raises a portability issue: for a separate document that, unlike the script document, has some real structure, can we apply the script and its coloring effects to specific text strings therein? Gratifyingly, with a little help from the Document Object Model (DOM), we can indeed transform the Script Tips #81-83 Script from an ad hoc generator of colored strings into a targeting color machine; in this post, we'll modify the script's ColoredText( ) function so that it adds color to text elements on the basis of
(a) id attribute value,
(b) tag name, and
(c) class attribute value.
A demo illustrating our handiwork will follow.

We'll apply our modified JavaScript to the following document body:

<body>
<h1>A sample with shades of green</h1>
<p>
<span class="rainbow">This is a text sample written using the function ColoredText.</span>
<br />
<span id="span1">Another text sample, this time only with red and orange repeatedly</span>
</p>
<h1>This is another H1 heading</h1>
<p id="p1" class="rainbow">Try refreshing the page a couple of times!</p>
</body>

setColorsById( )

We begin with the one-off coloring of a unique element. Consider the string Another text sample, this time only with red and orange repeatedly, whose characters are alternately colored red and orange by the Script Tips #81-83 Script and which my sample document wraps in a <span id="span1"> ... </span> container. This string can now be accessed and overwritten by the ColoredText( ) function via

document.getElementById("span1").innerHTML

expressions. (As noted in Blog Entry #70, innerHTML is not a standard (W3C-approved) DOM property. The DOM Level 3 Core Specification introduces a textContent property that is similar to innerHTML and that I would use below if the browsers on my computer supported it, which they do not.)

By combining the document.getElementById("span1").innerHTML expressions with parts of the Script Tips #81-83 Script and with some statements analogous to those appearing in the "To return or not to return" section of the previous post, I came up with the following JavaScript module that successfully colors the Another text sample, this time only with red and orange repeatedly string à la the Script Tips #81-83 Script:

var redorangeArray = new Array("red", "orange");
var myString = document.getElementById("span1").innerHTML;
var redorangeString = "";
for (i = 0; i < myString.length; i++) {
var charColor = myString.charAt(i);
colorCode = i % redorangeArray.length;
tempStr = charColor.fontcolor(redorangeArray[colorCode]);
redorangeString += tempStr; }
document.getElementById("span1").innerHTML = redorangeString;

The span1 string is replaced by a redorangeString string that is assembled on a character-by-character basis. The red and orange color keyword values are assigned on the first line to a redorangeArray array; their respective redorangeArray indexes, 0 and 1, match the colorCode % returns, which thus do not need to be incremented as was necessary in the else block of the original script.

setColorsByTagName( )

We set our sights higher in this section as we apply the sequence of green shades in the Script Tips #81-83 Script's third ColoredText( ) function call to both of the h1 elements in the above sample document. The A sample with shades of green and This is another H1 heading strings are smoothly colored with the #00x000 sequence via the following JavaScript module:

var headings1 = document.getElementsByTagName("h1");
var greenArray = new Array("#006000", "#007000", "#008000", "#009000", "#00a000", "#00b000");
var greenString = new Array( );
for (i = 0; i < headings1.length; i++) {
greenString[i] = "";
var myString = headings1[i].innerHTML;
for (j = 0; j < myString.length; j++) {
var charColor = myString.charAt(j);
colorCode = j % greenArray.length;
tempStr = charColor.fontcolor(greenArray[colorCode]);
greenString[i] += tempStr; }
headings1[i].innerHTML = greenString[i]; }

In brief:
(1) The h1 elements are scooped up and arrayed via the DOM's getElementsByTagName( ) method.
(2) Separate arrays are set up for the
(a) #00x000 green hex codes and
(b) greened variants of the h1 element strings.
(3) A parent for loop sequentially accesses the h1 element strings and then overwrites them with their greened variants.
(4) A nested for loop creates the greened strings à la the previous section.

setColorsByClass( )

Finally, in this section we'll randomly color the text strings of the sample document's first span element and second p element, which have a common class="rainbow" identifier, with the color values of the defClrsArray array. Unfortunately, the DOM does not have a "getElementsByClass( )" method that would allow us to directly array these elements and thus color them via the "setColorsByTagName( )" approach above. Fortunately, a Google search led me to a script posted at The JavaScript Source and authored by Dustin Diaz that uses the getElementsByTagName( ) method and the DOM className property to indirectly (more circuitously) array elements with a given class attribute value. A watered-down version of Mr. Diaz's script that is suitable for our present purpose is given below:

var classElements = new Array( );
var els = document.getElementsByTagName("*");
var elsLen = els.length;
for (i = 0, j = 0; i < elsLen; i++) {
if (els[i].className == "rainbow") {
classElements[j] = els[i];
j++; } }

Much like a document.all expression, the document.getElementsByTagName("*") expression returns an array of all of a document's elements, which is assigned in the code above to the variable els. We then loop through the els array and use an

if (els[i].className == "rainbow") { classElements[j] = els[i]; j++; }

conditional to fish out those elements whose className value is rainbow; the class="rainbow" elements are sequentially assigned to a classElements array.

The strings contained by the classElements elements can now be accessed and colored per the previous section:

var defClrsArray = new Array("red", "purple", "cyan", "green", "blue", "magenta");
var rainbowString = new Array( );
for (i = 0; i < classElements.length; i++) {
rainbowString[i] = "";
var myString = classElements[i].innerHTML;
for (j = 0; j < myString.length; j++) {
var charColor = myString.charAt(j);
colorCode = Math.floor(Math.random( ) * defClrsArray.length);
/* For periodic coloring, replace the preceding line with: colorCode = j % defClrsArray.length; */
tempStr = charColor.fontcolor(defClrsArray[colorCode]);
rainbowString[i] += tempStr; }
classElements[i].innerHTML = rainbowString[i]; }

FYI: Mr. Diaz's script addresses the complication that an element can belong to more than one class, e.g.,

<p class="class1 class2 class3">This is a paragraph.</p>
<!-- The HTML class attribute is detailed here. -->

by comparing the els[i].className expression to (simplifying once again) a (^|\s)classValue(\s|$)-like regular expression.

Demo

Here's what it all looks like:

A sample with shades of green

This is a text sample written using the function ColoredText.
Another text sample, this time only with red and orange repeatedly

This is another H1 heading

Try refreshing the page a couple of times!


Relevant demo CSS:

div { background-color: #ffffcc; font-size: 16px; }
#p1 { font-family: Courier, monospace; font-size: 24px; text-align: center; }

A couple of points:
#ffffcc is a member of the set of so-called Web-safe colors, which are discussed by Wikipedia here.
• In the Script Tips #81-83 Script, the Try refreshing the page a couple of times! string is marked up with a size="+2" attribute that should in this case be reproducible by a font-size:x-large; declaration, which in practice (without getting into the details) performed as expected with Netscape but not with MSIE on my computer, so I decided to use <length> font-size values for the div and p1 elements instead.

In the following entry, we'll look at the Script Tips #84-86 Script, which codes an image-based digital clock.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)