reptile7's JavaScript blog
Monday, December 04, 2006
In Any Colour You Like
Blog Entry #59

HTML Goodies' JavaScript Script Tip #19 is titled "Using JavaScript To Create HTML [T]ags," and we'll do just that in this post as we discuss a script that custom-builds a <body> tag and consequently sets on-the-fly two global document object properties:
(a) the document background color, and
(b) the document text color, a.k.a. the document foreground color.
(We've set the document background color via document.bgColor statements several times previously - see the Primer #17 Script, for example - but this'll be the first time that we can choose our own color value.)

Our script du jour spans Script Tips #19 and #20, is demonstrated by Joe here, and is detailed below:

<html><title>Title text</title>
<script language="javascript">
var color = prompt("What color would you like the page's background to be?","");
var txtcolor = prompt("What color would you like the text to be?","");
document.write("<body bgcolor=" + color + " text=" + txtcolor + ">");
defaultStatus = "Here's your " + color + " background and " + txtcolor + " text.";
Page text...

By design, the script's script element necessarily straddles the document head and body; the script contains no <head>/</head> tags, which are in any case optional.

The script's process is quite straightforward.
(1) A first prompt( ) box pops up, soliciting the user for a document background color choice; the user types in a color, which is assigned to the variable color after the user clicks the prompt( ) box's button.
(2) A second prompt( ) box pops up, soliciting the user for a document text color choice; the user types in a color, which (after clicking OK) is assigned to the variable txtcolor.
(3) Subsequently, color and txtcolor are plugged into a document.write( ) command that writes the document's <body> tag; color and txtcolor serve as the values for the body element's bgcolor and text attributes, respectively.
(4) Finally, color and txtcolor are concatenated with three short text strings to form a message that is written to the browser window's status bar.

For the two prompts, the user can enter a 'natural language' color - white, blue, etc.; see HTML Goodies' indispensable "So, You Want A Basic Color Code, Huh?" for possible values in this regard - or a 3-digit or 6-digit RGB code or even an rgb( ) function, if desired.

Of course, we can further build up the <body> tag via additional prompts that collect values for other body element attributes: link, vlink, etc. More generally, it should also be clear that we can apply the script's tag-construction methodology to an <img> tag, an <input> tag, or any other HTML tag. The overall approach here is reminiscent of Primer #12, in which we assembled from scratch an HTML document in a newly opened window by a series of document.write( ) commands; note that the Primer #12 Assignment similarly uses a prompt( ) output to custom-build the content of a title element.

Don't leave it blank, part 3

"What happens if the user leaves the prompt( ) boxes blank, doesn't fill in any colors, and then clicks 'OK' and/or 'Cancel'?"

Somehow I knew you'd ask that...well, what would you think? Let's first consider the blank-OK/blank-OK possibility. In this case, color and txtcolor are outputted as empty strings, so when we plug them into the document.write( ) command, the <body> tag in effect becomes:

<body bgcolor="" text="">

The document's background and foreground colors should then default to those set by the browser's Preferences pane (typically black text on a white background), and this is indeed what happens if we tighten up the <body> tag code. The body element attribute values should be quoted but are not, so let's add some single quotes:

document.write("<body bgcolor='" + color + "' text='" + txtcolor + "'>");

Without the single quotes, the blank-OK/blank-OK input on my iMac gives, for reasons beyond my understanding, a black page when using either MSIE 5.1.6 or Netscape 7.02; the returns for document.bgColor and document.fgColor are #0e0000 and #000000, respectively.

We learned in Blog Entry #11 that clicking the button on a prompt( ) box outputs the primitive value null. I observe that MSIE and Netscape treat a color value of null differently. MSIE evidently ignores the null value in this instance and gives the black-text-on-white-background default in response to blank-OK/blank-Cancel, blank-Cancel/blank-OK, and blank-Cancel/blank-Cancel inputs. In contrast, Netscape converts null to 0 and gives
(a) a black page in response to the blank-Cancel/blank-OK and blank-Cancel/blank-Cancel inputs, or
(b) the black-text-on-white-background default in response to the blank-OK/blank-Cancel input.
Netscape's behavior is consistent with the JavaScript 1.5 Core Guide's "Evaluating Variables" section, which states, When you evaluate a null variable, the null value behaves as 0 in numeric contexts and as false in Boolean contexts.

It is left to the reader to craft if statements that intercept and deal with these possibilities.

Customizing a body onload attribute

In Script Tip #20, Joe says:
"Up until now you might have been used to putting text into the status [bar] by a JavaScript Event Handler, then window.status. Well, you don't always have such an event to attach a window.status statement to. This is one of those cases...[The defaultStatus statement] can be plopped basically anywhere and whatever follows it shows up in the status bar."
However, I noted here in Blog Entry #18 that when using MSIE I am unable to write the window.defaultStatus or window.status property unless I assign it to an event handler. To see the status bar effect of the Script Tips #19-20 Script with MSIE, then, it is necessary that I coordinate the defaultStatus statement with the page-loading process via a suitable body onload attribute. Coding a customizable onload attribute is trickier than coding the corresponding bgcolor and text attributes but is doable:

<script type="text/javascript">
var color = window.prompt("What color would you like the page's background to be?");
var txtcolor = window.prompt("What color would you like the text to be?");
var colormessage = "Here&#39;s your " + color + " background and " + txtcolor + " text.";
document.write("<body bgcolor='" + color + "' text='" + txtcolor + "' onload='window.defaultStatus=\"" + colormessage + "\";'>");

As shown above, to get this to work, I had to escape
(a) the Here's apostrophe in the status bar message with the &#39; numeric character reference, and
(b) the double quotes surrounding the colormessage value; either \", &quot;, or &#34; can be used for this purpose.
But work it does with both MSIE and Netscape.

As for that demo page...

The Script Tips #19-20 Script demo page is interesting for a couple of reasons.

(1) Looking at the demo page's source code, we see that the demo document contains a nobr element. Never heard of it? Me neither. And you won't find it on the W3C's HTML 4.01 Specification "Index of Elements" page. It turns out that the nobr element is a 'proprietary' Microsoft (but also recognized by Netscape) HTML extension, and its function is opposite that of the br element, i.e., the nobr element forces multiline content to not wrap but to extend indefinitely to the right (presumably it would prevent wrapping on the left for a right-to-left language), e.g.:

Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the Government for a redress of grievances.

Getting back to the demo page source, there's no need to prevent any of the six printed lines of the nobr element from wrapping - none of them is long enough to wrap, anyway - and Joe himself breaks up the nobr element with no fewer than five br elements, thus killing the nobr effect; it follows that the nobr element here serves no purpose and should be removed.
(I'm not sure why anyone would want to use the nobr element to structure text in the first place, speaking as someone who would like to see horizontal scrolling go the way of smallpox and the dinosaurs.)

(2) The demo page behaves as expected when using Netscape but not when using MSIE, at least on my computer. With MSIE, both script prompt( ) boxes pop up, but regardless of what I enter (or don't enter) into them, the resulting page displays blue (#0000c0) text on a black (#0c0000) background. With a little detective work, I was able to source the problem to the nonscript, printed part of the page, specifically the 4th printed line of the nobr element:

<br>document.write("<body BGCOLOR=" +color+ " TEXT=" +txtcolor+ ">")

When the HTML parsers of Netscape and MSIE hit the <body character sequence, then they begin writing a new body element. Subsequently, Netscape is able to recognize the color and txtcolor prompt( ) outputs and renders the page normally, whereas MSIE does not recognize color and txtcolor and the resulting new <body> tag is:

<body bgcolor=" +color+ " text=" +txtcolor+ ">

I have no clue as to how MSIE converts illegal color values to legal color values. In any case, the creation of the new body element can be easily stopped by escaping the angle brackets in the document.write( ) command:

document.write("&lt;body bgcolor=" +color+ " text=" +txtcolor+ "&gt;")

This simple change allows MSIE to render the demo page without incident.

A style-based script

If you've visited my links above for the bgcolor, text, link, and vlink attributes of the body element, then you probably noticed that all of these attributes are, uh, deprecated, and I'm sure you know what that means: according to "those who run the coding show" (Joe's description of the W3C), they should be replaced by equivalent style information. Fortunately, applying CSS to the Script Tips #19-20 Script is not at all difficult. The HTML body bgcolor attribute maps onto the CSS background-color property, whereas the HTML body text attribute maps onto the CSS color property. We can therefore retool the script's document.write( ) command with a body style attribute as follows:

var color = window.prompt("What color would you like the page's background to be?");
var txtcolor = window.prompt("What color would you like the text to be?");
document.write("<body style='background-color: " + color + "; color: " + txtcolor + ";'>");

Alternatively, we could use a header style element; from

<style type="text/css">
body {background-color: <color>; color: <color>;}

we obtain:

var color = window.prompt("What color would you like the page's background to be?");
var txtcolor = window.prompt("What color would you like the text to be?");
document.write("<style type='text/css'>");
document.write("body {background-color: " + color + "; color: " + txtcolor + ";}");

A second style-based approach

When I first looked at the Script Tips #19-20 Script, it seemed unnatural to me. I thought, "Why are we using JavaScript to write an HTML tag? Why should JavaScript muscle in on HTML's turf? Aren't JavaScript and HTML supposed to complement each other? Why don't we use a more purely JavaScriptic method to achieve the script's color effects?" And of course, classic (pre-DOM) JavaScript provides bgColor and fgColor document object properties for this very sort of thing. However, Mozilla's DOM Reference notes that the document.bgColor and document.fgColor expressions are now deprecated and should be updated to and, respectively. Application thereof to the Script Tips #19-20 Script gives:

<script type="text/javascript">
var color = window.prompt("What color would you like the page's background to be?");
var txtcolor = window.prompt("What color would you like the text to be?"); = color; = txtcolor;
window.defaultStatus = "Here's your " + color + " background and " + txtcolor + " text.";

Try it out below:

Here's some document body text.

If you're using a modern browser (as I trust you are), then the defaultStatus assignment probably won't work for you - actually, your browser may not even have a status bar - so I'll also print out your color choices below.

Background color:
Text color:

In the next entry we'll check out an old-school guestbook script spanning Script Tips #21-24.


Comments: Post a Comment

<< Home

Powered by Blogger

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