reptile7's JavaScript blog
Saturday, August 25, 2007
 
Before and After Color Science
Blog Entry #86

Having analyzed the Script Tips #65-68 Scripts in the previous two entries, we will in this post revamp the Script Tips #65-67 Script in the following ways:
(1) We'll separate some (not all) of the script's HTML and JavaScript.
(2) We'll take the presentational stuff out of the script's HTML and put it in a style block.
(3) We'll write the Red, Green, and Blue options with a for loop - in doing so, we'll replace the gargantuan menu string with 10 lines of code.
Most of our remarks today will apply to the Script Tip #68 Script as well.

Separating HTML and JavaScript

For a block of code containing HTML and JavaScript, it is in general a good idea to keep the HTML and JavaScript separate:
• At the very least, both HTML and JavaScript are easier to read if they are free of one another.
• Typically, standalone HTML and JavaScript are maintained/modified more easily than is an HTML-JavaScript mixture.
• Also, externalizing a JavaScript script in a separate .js file* will allow it to be used by more than one document, if this is desired.
• From an accessibility standpoint, a separation of HTML and JavaScript facilitates the creation of alternative-content pages for user agents that do not or are configured to not execute JavaScript.
As you know, analogous considerations encourage a separation between HTML structure and presentation.
(*With respect to XHTML-compliance, the W3C doesn't have a problem with non-external scripts as long as they don't contain the metacharacters < and &.)

However, some HTML-JavaScript mixtures don't lend themselves very well to a clean resolution into HTML and JavaScript units. Consider, for example, the guitar chord chart script of Script Tips #56-59, which creates a 6×7 radio button grid via a pair of nested for loops. To achieve a complete separation of HTML and JavaScript in this case, we'd have to code individually all those radio buttons, and you wouldn't want to do that, would you? Didn't think so.

Two entries ago we noted that the Script Tips #65-67 Script conflates its HTML and JavaScript in a single script element. In this case, a complete separation of HTML and JavaScript would require us to code individually the 768 options of the red/green/blue selection lists, and we're certainly not going to do that, either. (My attempts to create these options with new Option( ) constructor statements, discussed later, met with mixed success.) But we can at least get the table code and the rest of the ColorMix form code out of the script element:

<body>
<table>
<!-- The table element was originally equipped with cellpadding="0" and cellspacing="0" attributes, whose removal does not noticeably affect the table's display. -->
<form name="ColorMix">

<tr><td id="box" colspan="4"></td></tr>
<tr>
<td class="quarter">Red: <select name="red" size="1" onchange="mix(this.form);">
<script type="text/javascript">document.write(threeDigitMenu( ));</script></select></td>

<td class="quarter">Green: <select name="green" size="1" onchange="mix(this.form);">
<script type="text/javascript">document.write(threeDigitMenu( ));</script></select></td>

<td class="quarter">Blue: <select name="blue" size="1" onchange="mix(this.form);">
<script type="text/javascript">document.write(threeDigitMenu( ));</script></select></td>

<td class="quarter"><input name="code" maxlength="7" size="10" value="#000000" />
</td></tr></form></table></body>

The four cells of the second table row have each been given a class="quarter" style identifier; we'll get into some CSS momentarily.

We can shorten the mix( ) function assignment statements a bit by passing to mix( ) this.form, a reference to the ColorMix form:

function mix(myForm) {
document.getElementById("box").style.background = "#" + myForm.red.options[myForm.red.selectedIndex].value + myForm.green.options[myForm.green.selectedIndex].value + myForm.blue.options[myForm.blue.selectedIndex].value;

myForm.code.value = "#" +
myForm.red.options[myForm.red.selectedIndex].value + myForm.green.options[myForm.green.selectedIndex].value + myForm.blue.options[myForm.blue.selectedIndex].value; }

The Red/Green/Blue options will be written by a threeDigitMenu( ) function detailed in the "option loop" section below.

A style block for the Script Tips #65-67 Script

table { border: 0px; width: 100%; }
td#box { background-color: black; height: 25px; }
td.quarter {
color: black;
font-family: sans-serif, serif;
font-size: 16px;
font-weight: bold;
width: 25%; }

Neither the border attribute nor the width attribute of the table element is deprecated, but these attributes/properties belong in the style block, so we'll put them there.

The Red/Green/Blue labels are given a basic black color, but you might prefer colored Red, Green, and Blue labels, and that's simple enough to arrange:
(a) To the td element start-tags of the first three cells of the second table row, add id="redcell", id="greencell", and id="bluecell" attributes, respectively.
(b) In the style block, subtract or comment out td.quarter's color:black; declaration and then add the following rules:

td#redcell { color: red; }
td#greencell { color: lime; }
td#bluecell { color: blue; }
/* These rules will not color the numbers on the Red/Green/Blue options. */

In the Script Tips #65-68 Scripts, the Red/Green/Blue labels are marked up with a face='arial, geneva, times new roman' attribute. Arial and Geneva are both sans-serif fonts, whereas Times New Roman is a serif font, and I have accordingly given the style block a td.quarter { font-family:sans-serif, serif; } rule. There seems to be a general preference on the Web for sans-serif fonts, understandably so given their clean appearance.

The Red/Green/Blue labels are also marked up with a size='2' attribute. On my computer, size='2' is equivalent to a font-size:13pt; CSS declaration. My style block's td.quarter { font-size:16px; } rule reflects
(a) my own preference for a larger font size, and
(b) the W3C's recommendation that Web authors use relative length units and not absolute length units.

An option loop

As noted earlier, the Script Tips #56-59 Script uses two for loops to create a set of radio buttons, and I thought, "There must be some way to use a for loop to generate the menu option string in the Script Tips #65-68 Scripts." This example on the JavaScript 1.3 Client-Side Reference's option object page seemed to offer the general approach I was looking for. After some experimentation, I found that the following code, when put in or referenced by a script element placed after the ColorMix form element, would slowly (>30 seconds) generate the Red/Green/Blue options when using MSIE but not when using Netscape:

optionarray = new Array( );

for (i = 255; i >= 0; i--) {
var hexvalue = i.toString(16);
if (/^\w$/.test(hexvalue)) hexvalue = "0" + hexvalue;
var threedigit = i;
if (/^\d{2}$/.test(threedigit)) threedigit = "0" + threedigit;
if (/^\d$/.test(threedigit)) threedigit = "00" + threedigit;

optionarray[i] = new Option(threedigit, hexvalue);

document.ColorMix.red.options[i] = optionarray[i];
document.ColorMix.green.options[i] = optionarray[i];
document.ColorMix.blue.options[i] = optionarray[i];

document.ColorMix.red.options[0].selected = true;
document.ColorMix.green.options[0].selected = true;
document.ColorMix.blue.options[0].selected = true; }

This script creates an option object array, optionarray[ ], whose elements are assigned, one by one, to the options[ ] properties of the red/green/blue selection lists. (Without getting into the details, Netscape did create the optionarray[ ] array but would not assign its elements to the red/green/blue options[ ] arrays.)

The loop counter i doubles as an optionarray[ ]/options[ ] index number and decrements from 255 to 0. For reasons beyond my understanding, a for (i = 0; i < 256; i++) loop would generate all three option lists but only the last-in-source-order list (for the code above, the blue list) was functional.

Each option is created by a constructor statement as opposed to an HTML option element:

optionarray[i] = new Option(threedigit, hexvalue);

The text (content) of each option is represented by the variable threedigit. Initially, i is assigned to threedigit, which is sufficient for the 255threedigit100 options. For the 99threedigit10 and 9threedigit0 options - ranges for which threedigit matches the /^\d{2}$/ and /^\d$/ regular expressions, respectively - a pair of if statements prepend "0" and "00" to threedigit, respectively; the leading zeros are of course unnecessary and thus these if statements can be removed, if desired.

The value of each option is represented by the variable hexvalue. floR in the Netherlands helpfully points out that decimal numbers are easily converted to their hexadecimal equivalents via the toString( ) method of the core JavaScript Number object, in this case:

var hexvalue = i.toString(16);
// 16 is the radix (base) of the outputted number string.

For the fhexvalue0 options - a range for which hexvalue matches the /^\w$/ regular expression - an if statement prepends "0" to hexvalue; unlike the threedigit conditionals, this if statement cannot be deleted without harming the script.

Finally, the selected properties of the 000 option objects of the red/green/blue selection lists are set to true.

Desiring a cross-browser loop, and recalling the use of img element strings in the random banner script of Script Tip #34, I decided to scrap the new Option( ) constructor statements and return to the Script Tips #65-67 Script's original

document.write("<option value='##'>###</option>")

approach to creating the Red/Green/Blue options. After further experimentation, I found that the function below will effectively substitute for the menu option string when using either MSIE or Netscape:

function threeDigitMenu( ) {
var optionarray = new Array( );
for (i = 0; i < 256; i++) {
var hexvalue = i.toString(16);
if (/^\w$/.test(hexvalue)) hexvalue = "0" + hexvalue;
var threedigit = i;
if (/^\d{2}$/.test(threedigit)) threedigit = "0" + threedigit;
if (/^\d$/.test(threedigit)) threedigit = "00" + threedigit;
optionarray[i] = "<option value='" + hexvalue + "'>" + threedigit + "</option>"; }
return optionarray; }

As shown in the "Separating HTML and JavaScript" section above, the red/green/blue select elements can call the threeDigitMenu( ) function via a

<script type="text/javascript">document.write(threeDigitMenu( ));</script>

script element; threeDigitMenu( ) returns to each select element the entire optionarray[ ] option array, which is then written to the page normally.

In the next entry, we'll move on to the Script Tips #69-72 Script, which codes a rotating series of hyperlinking headlines.

reptile7

Wednesday, August 15, 2007
 
Paint It Non-Black
Blog Entry #85

Deconstructing the Script Tips #65-67 Script's effect

We return now to the color creation script of HTML Goodies' JavaScript Script Tips #65-67. For the following discussion, let's assume that the user is browsing with MSIE4+. Here are our initial conditions:
• The background color of the first table row's cell is set to black (#000000).
• The Red, Green, and Blue selection lists all read 000 (in the menu string, the final 000 option element is equipped with a minimized selected attribute).
• The value in the text box at the end of the second table row is set to #000000.
Imagine it's nighttime, and you're in a room with the shades pulled down and the lights off. Pitch black. This is the starting point for additive color.

document.write("<select onchange='mix( );' size='1'>" + menu + "</select>");
<!-- name='red'|'green'|'blue' -->

Let there be light! The user chooses or does not choose an option from the Red, Green, and Blue menus. Each selection calls the script's mix( ) function via an onchange event handler.

function mix( ) {
if (document.all) {

The mix( ) function first tests if the browser supports the all collection (and we wouldn't have gotten this far if it didn't) - check.

document.all("box").style.background = "#" + document.ColorMix.red.options[document.ColorMix.red.selectedIndex].value +
document.ColorMix.green.options[document.ColorMix.green.selectedIndex].value
+ document.ColorMix.blue.options[document.ColorMix.blue.selectedIndex].value;

In much the same way that document.forms[ ] and document.images[ ] are arrays of a document's forms and images, respectively, the document all collection is an array of all of the elements in a document, including the html, head, and body elements and all elements in between. Like a document's forms and images, a document's all array elements can be indexed either with ordinal numbers (0, 1, 2, ...) or associatively with strings. In the left side of the statement above, document.all("box") references the document element whose id or name attribute value is box, i.e., the first table row's td element. As to why the Microsoft people decided to enclose the all index in parentheses and not in square brackets, well, your guess is as good as mine.

(An aside: the all collection is not only associated with the document object but can be used by any element that contains other elements. For example, consider a form named myForm comprising five radio buttons named myRadio: we can reference the third-in-source-order radio button with: document.myForm.all("myRadio", 2).)

The right side of the statement concatenates #, the value of the selected Red option, the value of the selected Green option, and the value of the selected Blue option. The resulting #RRGGBB string is then assigned to the value of the CSS background property of the box table cell.

Comments
• The options[ ] property of the select object, the selectedIndex property of the select object, and the value property of the option object were all introduced in the URL menu scripts of Script Tips #38-40, which we covered in Blog Entry #66.
• MSIE was the first browser to implement a style scripting object; MSDN's style object page is here.
The "shorthand" background property can be used to write individually or collectively CSS's various background properties (background-color, background-image, etc.).

document.ColorMix.code.value = "#" + document.ColorMix.red.options[document.ColorMix.red.selectedIndex].value + document.ColorMix.green.options[document.ColorMix.green.selectedIndex].value + document.ColorMix.blue.options[document.ColorMix.blue.selectedIndex].value;

Similarly, this statement assigns the #RRGGBB string to the value of the value property of the code control - i.e., the text box at the end of the second table row - in the ColorMix form.

Example: The user selects Red: 200, Green: 150, and Blue: 100. The mix( ) function combines the values of these options to give the hex code #c89664, which is loaded into the code text box and displays as a milk-chocolate color in the box table cell.

else {
alert("Sorry, your browser does not support the programming needed to run this script."); } }

As noted in the previous post, the script's initial display, and thus the ability to call the mix( ) function, has been 'conditioned out' for non-MSIE4+ users, who thus never see this alert( ) message, which is intended for them. Pretty sloppy design for an outfit calling itself "the Silicon Valley Garage".

The Script Tip #68 Script

The cross-browser Script Tip #68 Script can be accessed here and is demonstrated here. Here's how it differs from the Script Tips #65-67 Script:

(1) Joe first ditches (a) the two if (document.all) declarations and the { and } characters that delimit the if 'bodies' and (b) the else code in the mix( ) function - so far, so good. Strangely and quite unnecessarily, he then surrounds the menu option string and table/ColorMix document.write( ) commands with an always-true

var zork = 1;
if (zork == 1) { ... }

conditional; this silly code can and should be removed.

(2) The mix( ) function is moved to the end of the script. In Script Tip #68, Joe 'explains':
You have to flip the script upside down for NN [Netscape Navigator] to run it. You see, in order for NN to run hierarchy statements, the elements must already be loaded into the browser memory. In the case of the MSIE-only script, the commands came first and then the table was built. It's opposite here. First you have to build the table, then you can post the function.
Actually, both MSIE and Netscape will throw runtime errors if they encounter unfunctionized hierarchy statements containing identifiers for elements that appear subsequently in the source, BUT the statements in question here are in a function that is only called after the script document has loaded, and consequently the mix( ) move is unnecessary. Joe's to run hierarchy statements, the elements must already be loaded into the browser memory comment is correct as far as it goes, but merely loading into memory such statements in a function isn't 'running' them, and thus it's OK if they precede the element(s) they reference.

(3) Joe removes the box table cell and equips the body element start-tag with a bgcolor="000000" attribute. Next, he replaces the document.all("box").style.background expression on the left side of mix( )'s first assignment statement with document.bgColor so that the statement writes the document background color - fair enough, given Netscape's capabilities at the time the script was written.

A cross-browser Script Tips #65-67 Script

With some minor modifications, however, we can get the Script Tips #65-67 Script to work for Netscape 6+ and other current browsers exactly as it does for MSIE, as follows:

(1) As for the Script Tip #68 Script, let's first subtract the if (document.all) { } 'containers' and also mix( )'s else code.

(2) It has probably occurred to you that a document.all("elementID") expression is functionally equivalent to a document.getElementById("elementID") expression. Accordingly, in the mix( ) function we then replace document.all("box").style.background with document.getElementById("box").style.background.

And that'll do it, folks. Try it out:


(FYI: getElementById( ) is not at all a new method but was introduced in the DOM Level 1 HTML Specification, which 'went live' as a W3C Recommendation on 1 October 1998, but apparently the Script Tips #65-67 Script predates this.)

We'll wrap up our discussion of the Script Tips #65-68 Scripts in the next entry - we'll spiff up the code a bit and also look at a loop-based generation of the menu option string.

reptile7

Wednesday, August 08, 2007
 
Dialing for Colors
Blog Entry #84

Visual browsers are capable of rendering a broad array of nice colors on a Web page, and the CSS background-color property can theoretically apply these colors to "all" HTML elements. In choosing a color for this or that purpose, I for my part would consult the color chart of HTML Goodies' "So, You Want A Basic Color Code, Huh?" or perhaps Wikipedia's List of colors. You, however, might be a DIY-type who would rather create your own colors; HTML Goodies' JavaScript Script Tips #65, #66, #67, and #68, our focus for the next few posts, discuss a pair of related scripts that will help you do just that.

The W3C has deprecated all of HTML's color-related attributes - e.g., the color attribute of the font element and the bgcolor attribute of the body element - and recommends that Web page colors (more generally, colors for any visual media type) be set via CSS. For specifying colors and color values, both HTML and CSS use an additive color model in which red (R), green (G), and blue (B) are primary colors and are combined to give other colors.

Joe takes a not-so-successful stab at a description of the RGB color space in HTML Goodies' "A Quick Color Explanation". This article does not meaningfully distinguish between additive color and subtractive color, incorrectly states that red, blue, and yellow (Y) are "the" primary colors (when defined strictly, R, B, and Y collectively are not primary colors even in a subtractive sense), and misleadingly labels green a "composite color" (this can be true in a subtractive sense but is not true with respect to the additive RGB model). But perhaps I should cut Joe some slack here - the science of color and its perception is not so easily picked up on the fly. And do check out the article's "Basic Hexadecimal Notation" section, which is worth reading.

In their effects, the Script Tips #65-68 Scripts emulate a device that uses 24 bits per screen pixel - 1 byte each for R, G, and B - to display color. The scripts code separate "Red", "Green", and "Blue" selection lists, each comprising 256 options. For these lists:
(a) the contents of the option elements are three-digit decimal numbers running from 000 to 255, inclusive, and
(b) the values of the option elements are the corresponding two-digit hexadecimal numbers running from 00 to ff, inclusive, e.g.:

<option value='0a'>010</option>
<!-- The corresponding bit sequence would be: 00001010 -->

The user makes selections from the Red, Green, and/or Blue menus; the values of the user's chosen or unchosen options from all three menus are concatenated and appended to a number sign (#) to give a hexadecimal #RRGGBB color value.
(1) Script Tips #65-67 cover a script that was written specifically for Internet Explorer and that assigns the #RRGGBB value to the CSS background(-color) property of a td (table cell) element.
(2) In Script Tip #68, Joe presents a cross-browser script that assigns the #RRGGBB value to the bgColor property of the document object.

The Script Tips #65-67 Script

The main script of Script Tips #65-67 can be accessed via the "Here's the Code" links in all three script tips and is reproduced in the div below:

<script language="javascript">

// This javascript is property of the Silicon Valley Garage.

function mix( )
{
if (document.all)
{
document.all("box").style.background = "#" + document.ColorMix.red.options[document.ColorMix.red.selectedIndex].value + document.ColorMix.green.options[document.ColorMix.green.selectedIndex].value + document.ColorMix.blue.options[document.ColorMix.blue.selectedIndex].value;

document.ColorMix.code.value = "#" + document.ColorMix.red.options[document.ColorMix.red.selectedIndex].value + document.ColorMix.green.options[document.ColorMix.green.selectedIndex].value + document.ColorMix.blue.options[document.ColorMix.blue.selectedIndex].value;
}
else
{
alert("Sorry, your browser does not support the programming needed to run this script.");
}
}

if (document.all)
{
var menu = "
<option value=\"ff\">255</option>
<option value=\"fe\">254</option>
<option value=\"fd\">253</option>
<option value=\"fc\">253</option>
<option value=\"fb\">252</option>
<option value=\"fa\">251</option>
<option value=\"f9\">250</option>
<option value=\"f8\">249</option>
<option value=\"f7\">248</option>
<option value=\"f6\">247</option>
<option value=\"f5\">246</option>
<option value=\"f4\">245</option>
<option value=\"f3\">244</option>
<option value=\"f2\">243</option>
<option value=\"f1\">242</option>
<option value=\"f0\">241</option>
<option value=\"ef\">240</option>
<option value=\"ee\">239</option>
<option value=\"ed\">238</option>
<option value=\"ec\">237</option>
<option value=\"eb\">236</option>
<option value=\"ea\">234</option>
<option value=\"e9\">233</option>
<option value=\"e8\">232</option>
<option value=\"e7\">231</option>
<option value=\"e6\">230</option>
<option value=\"e5\">229</option>
<option value=\"e4\">228</option>
<option value=\"e3\">227</option>
<option value=\"e2\">226</option>
<option value=\"e1\">225</option>
<option value=\"e0\">224</option>
<option value=\"df\">223</option>
<option value=\"de\">222</option>
<option value=\"dd\">221</option>
<option value=\"dc\">220</option>
<option value=\"db\">219</option>
<option value=\"da\">218</option>
<option value=\"d9\">217</option>
<option value=\"d8\">216</option>
<option value=\"d7\">215</option>
<option value=\"d6\">214</option>
<option value=\"d5\">213</option>
<option value=\"d4\">212</option>
<option value=\"d3\">211</option>
<option value=\"d2\">210</option>
<option value=\"d1\">209</option>
<option value=\"d0\">208</option>
<option value=\"cf\">207</option>
<option value=\"ce\">206</option>
<option value=\"cd\">205</option>
<option value=\"cc\">204</option>
<option value=\"cb\">203</option>
<option value=\"ca\">202</option>
<option value=\"c9\">201</option>
<option value=\"c8\">200</option>
<option value=\"c7\">199</option>
<option value=\"c6\">198</option>
<option value=\"c5\">197</option>
<option value=\"c4\">196</option>
<option value=\"c3\">195</option>
<option value=\"c2\">194</option>
<option value=\"c1\">193</option>
<option value=\"c0\">192</option>
<option value=\"bf\">191</option>
<option value=\"be\">190</option>
<option value=\"bd\">189</option>
<option value=\"bc\">188</option>
<option value=\"bb\">187</option>
<option value=\"ba\">186</option>
<option value=\"b9\">185</option>
<option value=\"b8\">184</option>
<option value=\"b7\">183</option>
<option value=\"b6\">182</option>
<option value=\"b5\">181</option>
<option value=\"b4\">180</option>
<option value=\"b3\">179</option>
<option value=\"b2\">178</option>
<option value=\"b1\">177</option>
<option value=\"b0\">176</option>
<option value=\"af\">175</option>
<option value=\"ae\">174</option>
<option value=\"ad\">173</option>
<option value=\"ac\">172</option>
<option value=\"ab\">171</option>
<option value=\"aa\">170</option>
<option value=\"a9\">169</option>
<option value=\"a8\">168</option>
<option value=\"a7\">167</option>
<option value=\"a6\">166</option>
<option value=\"a5\">165</option>
<option value=\"a4\">164</option>
<option value=\"a3\">163</option>
<option value=\"a2\">162</option>
<option value=\"a1\">161</option>
<option value=\"a0\">160</option>
<option value=\"9f\">159</option>
<option value=\"9e\">158</option>
<option value=\"9d\">157</option>
<option value=\"9c\">156</option>
<option value=\"9b\">155</option>
<option value=\"9a\">154</option>
<option value=\"99\">153</option>
<option value=\"98\">152</option>
<option value=\"97\">151</option>
<option value=\"96\">150</option>
<option value=\"95\">149</option>
<option value=\"94\">148</option>
<option value=\"93\">147</option>
<option value=\"92\">146</option>
<option value=\"91\">145</option>
<option value=\"90\">144</option>
<option value=\"8f\">143</option>
<option value=\"8e\">142</option>
<option value=\"8d\">141</option>
<option value=\"8c\">140</option>
<option value=\"8b\">139</option>
<option value=\"8a\">138</option>
<option value=\"89\">137</option>
<option value=\"88\">136</option>
<option value=\"87\">135</option>
<option value=\"86\">134</option>
<option value=\"85\">133</option>
<option value=\"84\">132</option>
<option value=\"83\">131</option>
<option value=\"82\">130</option>
<option value=\"81\">129</option>
<option value=\"80\">128</option>
<option value=\"7f\">127</option>
<option value=\"7e\">126</option>
<option value=\"7d\">125</option>
<option value=\"7c\">124</option>
<option value=\"7b\">123</option>
<option value=\"7a\">122</option>
<option value=\"79\">121</option>
<option value=\"78\">120</option>
<option value=\"77\">119</option>
<option value=\"76\">118</option>
<option value=\"75\">117</option>
<option value=\"74\">116</option>
<option value=\"73\">115</option>
<option value=\"72\">114</option>
<option value=\"71\">113</option>
<option value=\"70\">112</option>
<option value=\"6f\">111</option>
<option value=\"6e\">110</option>
<option value=\"6d\">109</option>
<option value=\"6c\">108</option>
<option value=\"6b\">107</option>
<option value=\"6a\">106</option>
<option value=\"69\">105</option>
<option value=\"68\">104</option>
<option value=\"67\">103</option>
<option value=\"66\">102</option>
<option value=\"65\">101</option>
<option value=\"64\">100</option>
<option value=\"63\">099</option>
<option value=\"62\">098</option>
<option value=\"61\">097</option>
<option value=\"60\">096</option>
<option value=\"5f\">095</option>
<option value=\"5e\">094</option>
<option value=\"5d\">093</option>
<option value=\"5c\">092</option>
<option value=\"5b\">091</option>
<option value=\"5a\">090</option>
<option value=\"59\">089</option>
<option value=\"58\">088</option>
<option value=\"57\">087</option>
<option value=\"56\">086</option>
<option value=\"55\">085</option>
<option value=\"54\">084</option>
<option value=\"53\">083</option>
<option value=\"52\">082</option>
<option value=\"51\">081</option>
<option value=\"50\">080</option>
<option value=\"4f\">079</option>
<option value=\"4e\">078</option>
<option value=\"4d\">077</option>
<option value=\"4c\">076</option>
<option value=\"4b\">075</option>
<option value=\"4a\">074</option>
<option value=\"49\">073</option>
<option value=\"48\">072</option>
<option value=\"47\">071</option>
<option value=\"46\">070</option>
<option value=\"45\">069</option>
<option value=\"44\">068</option>
<option value=\"43\">067</option>
<option value=\"42\">066</option>
<option value=\"41\">065</option>
<option value=\"40\">064</option>
<option value=\"3f\">063</option>
<option value=\"3e\">062</option>
<option value=\"3d\">061</option>
<option value=\"3c\">060</option>
<option value=\"3b\">059</option>
<option value=\"3a\">058</option>
<option value=\"39\">057</option>
<option value=\"38\">056</option>
<option value=\"37\">055</option>
<option value=\"36\">054</option>
<option value=\"35\">053</option>
<option value=\"34\">052</option>
<option value=\"33\">051</option>
<option value=\"32\">050</option>
<option value=\"31\">049</option>
<option value=\"30\">048</option>
<option value=\"2f\">047</option>
<option value=\"2e\">046</option>
<option value=\"2d\">045</option>
<option value=\"2c\">044</option>
<option value=\"2b\">043</option>
<option value=\"2a\">042</option>
<option value=\"29\">041</option>
<option value=\"28\">040</option>
<option value=\"27\">039</option>
<option value=\"26\">038</option>
<option value=\"25\">037</option>
<option value=\"24\">036</option>
<option value=\"23\">035</option>
<option value=\"22\">034</option>
<option value=\"21\">033</option>
<option value=\"20\">032</option>
<option value=\"1f\">031</option>
<option value=\"1e\">030</option>
<option value=\"1d\">029</option>
<option value=\"1c\">028</option>
<option value=\"1b\">027</option>
<option value=\"1a\">026</option>
<option value=\"19\">025</option>
<option value=\"18\">024</option>
<option value=\"17\">023</option>
<option value=\"16\">022</option>
<option value=\"15\">021</option>
<option value=\"14\">020</option>
<option value=\"13\">019</option>
<option value=\"12\">018</option>
<option value=\"11\">017</option>
<option value=\"10\">016</option>
<option value=\"0f\">015</option>
<option value=\"0e\">014</option>
<option value=\"0d\">013</option>
<option value=\"0c\">012</option>
<option value=\"0b\">011</option>
<option value=\"0a\">010</option>
<option value=\"09\">009</option>
<option value=\"08\">008</option>
<option value=\"07\">007</option>
<option value=\"06\">006</option>
<option value=\"05\">005</option>
<option value=\"04\">004</option>
<option value=\"03\">003</option>
<option value=\"02\">002</option>
<option value=\"01\">001</option>
<option selected value=\"00\">000</option>";
document.write("<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"100%\">");
document.write("<form name=\"ColorMix\">");
document.write("<td bgcolor=\"#000000\" height=\"25\" id=\"box\" colspan=\"4\"></td><tr>");
document.write("<td width=\"25%\"><font color=\"#ffffff\" face=\"arial, geneva, times new roman\" size=\"2\"><b>Red: </b></font><select name=\"red\" onchange=\"mix( );\" size=\"1\">" + menu + "</select></td><td width=\"25%\"><font color=\"#ffffff\" face=\"arial, geneva, times new roman\" size=\"2\"><b>Green: </b></font><select name=\"green\" onchange=\"mix( );\" size=\"1\">" + menu + "</select></td><td width=\"25%\"><font color=\"#ffffff\" face=\"arial, geneva, times new roman\" size=\"2\"><b>blue: </b></font><select name=\"blue\" onchange=\"mix( );\" size=\"1\">" + menu + "</select></td><td width=\"25%\"><input name=\"code\" maxlength=\"7\" size=\"10\" type=\"text\" value=\"#000000\"></td><tr>");
document.write("</form>");
document.write("</table>");
}
</script>

The Script Tips #65-67 Script comprises one large script element - there's no separation between the script's HTML and JavaScript. Relatedly, the script makes compulsive use of the \" escape sequence to quote HTML attribute values; the script would definitely be easier to read if the script's author(s) had used single quotes for this purpose. (The author could have simply written the code without any quotes, Joe remarks in Script Tip #65, but if we want the script to be XHTML-compliant, then the attribute values must be quoted.)

The Script Tips #65-67 Script's demo page is here. The script's display is housed in a two-row, five-cell table. The first table row, whose (required) tr element start-tag has sloppily been omitted, contains a contentless cell that spans the width of the browser window (because the parent table element's width attribute is set to %100):

document.write("<td bgcolor='#000000' height='25' id='box' colspan='4'></td>");

This cell will "receive the color" of the #RRGGBB value described above. As noted earlier, the td bgcolor attribute is now deprecated, as is the td height attribute; we'll write a style block for the Script Tips #65-67 Script in due course.

The four cells of the second table row each span 25% of the width of the browser window. The first three of these cells each have two immediate 'children':
(1) a (deprecated) font element containing a boldened Red, Green, or Blue label; and
(2) a select element containing the 000-to-255 set of options described above, e.g.:

document.write("<td width='25%'><font color='#ffffff' face='arial, geneva, times new roman' size='2'><b>Red: </b></font><select name='red' onchange='mix( );' size='1'>" + menu + "</select></td>");

Quick comments:
The td width attribute is deprecated.
• Bizarrely, the color attribute of the font element is set to white; consequently, the Red/Green/Blue labels will be 'invisible' unless the user's default browser background color is set to a non-white color.

All of the selection list options are lumped into a single, humongously long string that is variabilized with the identifier menu. Notwithstanding menu's appearance on the "Here's the Code" page and in the iframe above, the menu string must be all on one command line (check the demo page's source), or the browser will throw an error:

Unterminated string constant error message

Specifically, you'll see this error when using MSIE but not when using Netscape - we'll explain why in just a bit. JavaScript can be surprisingly tolerant of line breaks (we demonstrated this early on in Blog Entry #3), but strings in JavaScript cannot contain line breaks. It's rather odd that Joe doesn't make a 'You need to put this all on one line' comment here, given his penchant for doing so.

Anyway, menu is plugged into all three select elements and thus the menu option string need only appear once in the script. Of course, the menu string itself might still be too long for your tastes, and we'll detail an automated generation of the select element options in a subsequent post.

The last cell in the second table row contains a text field -

<input name='code' maxlength='7' size='10' type='text' value='#000000' />

- to which the #RRGGBB color value will also be written.

When the page loads: MSIE vs. Netscape

The script's display differs radically depending on whether the user's browser is MSIE or not. The menu options and the document.write( ) commands that write the display table to the page sit in a

if (document.all) { ... }

conditional. The document.all condition references the proprietary, MSIE-specific all collection/property of the document object. We'll have more to say about the all collection in the following entry, but for our present purposes, the if (document.all) command line merely tests the browser's support for the all collection; if the user is using MSIE4+, then document.all converts to true and the display table renders normally.

For non-MSIE4+ browsers, the document.all condition converts to false. (On my computer, Netscape 7.02 returns undefined for document.all, although JavaScript Kit claims that the return here should be null. However, both undefined and null convert to false in a Boolean context.) So what happens? The browser skips over the if (document.all) { ... } block, which runs to the end of the script and is not followed by an alternate-code-containing else block. As a result, we see...nothing. Just a blank page.

The display table code is not MSIE-specific and thus there's no point in enveloping it with the if (document.all), {, and } command lines, which should be removed so that the non-MSIE4+ folks can at least see the script's initial display, even if they can't make subsequent use of the script as originally written.

We'll go through the 'action' parts of the Script Tips #65-68 Scripts in the next entry.

reptile7


Powered by Blogger

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