reptile7's JavaScript blog
Tuesday, November 26, 2013
 
Coloring by Character, Part 2
Blog Entry #307

We return now to our discussion of the Java Goodies Multi-Colored Text script. Continuing from the previous post, we have in place
(1) a to-be-colored text string and
(2) a hexa array of hexadecimal digits
and we are ready to color the text string with the colours( ) function, which is called and passed text just before the page has finished loading.

function colours(text) { var posa = 0; var posb = 1; while (posa <= text.length) { ... } }

The colours( ) function first initializes posa and posb variables that will respectively serve as indexA and indexB delimiters for various text.substring( ) operations. The rest of the colours( ) function comprises a while loop that walks through and processes the text string.

Random bits

The while loop body begins with six statements that generate random integers in the range running from 0 to 14, inclusive.

var r = Math.floor(Math.random( ) * 15);
var rr = Math.floor(Math.random( ) * 15);
var g = Math.floor(Math.random( ) * 15);
var gg = Math.floor(Math.random( ) * 15);
var b = Math.floor(Math.random( ) * 15);
var bb = Math.floor(Math.random( ) * 15);


Near the end of the colours( ) function, the r-to-bb variables are plugged into the hexa array to give random hexadecimal digits that are concatenated in order to form a hex code for coloring a text character. FYI: If the preceding statements were placed before the loop, then every text character would have the same color.

When I first looked at these statements I thought, "Why aren't we using Math.floor(Math.random( ) * 16) expressions so we can go all the way up to 15/F?" It subsequently occurred to me that stopping at 14/E ensures that all of the text characters are dark enough to show up on a white background.

Tag encounter

Next we have an if statement that handles HTML tags (the text string could begin with an HTML tag, after all):

if (text.substring(posa,posb) == "<") { var posaa = 0; posaa = posa; while (text.substring(posaa,posb) != ">") { posaa++; posb++; } document.write(text.substring(posa, posb)); posa = posb; posb = posa + 1; }

Deconstruction

Here's what happens if posa indexes a < left angle bracket character:

(1) A posaa variable is initialized to 0 and then given posa's value.

(2) posaa and posb are via a while loop stepped forward through the text string until posaa hits a > right angle bracket character (the end of the tag).

(3) A document.write( ) command writes the tag (text.substring(posa, posb)) to the page.

(4) posa is laddered* to posb's position; posb is increased by 1.
(*Chutes and Ladders is my favorite board game.)

It follows from the above that text should not contain any stray < characters: a
var text = "Experts agree that 4 < 5 most of the time.";
string would give rise to an infinite loop, and you definitely don't want that.

A new, random color

We are at long last ready to color text's #PCDATA text; each character thereof is colored and written to the page one at a time by the following code:

document.write("<font color='#" + hexa[r] + hexa[rr] + hexa[g] + hexa[gg] + hexa[b] + hexa[bb] + "'>");
document.write(text.substring(posa, posb) + "</font>");


Each digit of the color attribute's hex code value is randomized - it doesn't get any more random than that. In contrast, the HTML Goodies JavaScript Script Tips #81-83 script, with which I compared the Multi-Colored Text script last time, randomly colors text characters via a defClrsArray color array that is defined in advance.

The colours( ) function concludes by moving posa and posb to the next character(s):

posa++;
posb++;


Other coloring formulations

If you're not happy about using a font element - I'm not happy about using a font element - then you can replace it with a corresponding span element:

document.write("<span style='color:#" + hexa[r] + hexa[rr] + hexa[g] + hexa[gg] + hexa[b] + hexa[bb] + "'>");
document.write(text.substring(posa, posb) + "</span>");


The Script Tips #81-83 script uses the fontcolor( ) method of the String object to color its charColor characters. If we wanted to use the fontcolor( ) method to hexa-color the posa character, here's how we'd do it:

text.substring(posa, posb).fontcolor("#" + hexa[r] + hexa[rr] + hexa[g] + hexa[gg] + hexa[b] + hexa[bb])

However, Mozilla discommends the fontcolor( ) method: Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future. So we should probably go with the span approach.

Adjacent HTML tags

Let's go back to the Tag encounter section's if statement for a moment. If at the end of the statement posa indexes a < character, then that character, and whatever follows it, will be colored and printed out by the code in the preceding section. Erik inserts a space character between the adjacent HTML tags in the text string to preempt this situation and ensure that the <font size='9'>, </blink>, <u>, and </b> tags are perceived as markup and not as #PCDATA text. Alternatively, the interstitial spaces can be thrown out if we place the preceding section's code in an if (text.substring(posa, posb) != "<") { ... } clause or more simply an else { ... } clause.

More structure

Netscape 4.x may not support the innerHTML property but all modern browsers do, giving us the green light to put the to-be-colored text in a div or p element:

<div id="colorDiv">This JavaScript shows every letter of text ...</div>

The colorDiv div's innerHTML can be assigned to text and passed to the colours( ) function when the page loads:

window.onload = function ( ) { var text = document.getElementById("colorDiv").innerHTML; colours(text); }

In the colours( ) function we can build the colored/formatted string as a colorString string

var colorString = ""; ...
// For adding an HTML tag:
colorString += text.substring(posa, posb); ...
// For adding a colored #PCDATA character:
colorString += "<span style='color:#" + hexa[r] + hexa[rr] + hexa[g] + hexa[gg] + hexa[b] + hexa[bb] + "'>"
+ text.substring(posa, posb) + "</span>";


and finally assign the completed colorString string to the colorDiv div's innerHTML.

document.getElementById("colorDiv").innerHTML = colorString;

Moreover, putting the to-be-colored text in a div or p element takes care of the original script's don't use quotation marks [in the text string] limitation.

Demo

Click the button to randomly color the text above it.

This text is bolded.
This text is italicized.
This text is underlined.
This is just plain text.


Sunday, November 17, 2013
 
Coloring by Character, Part 1
Blog Entry #306

In today's post we will take up a "Multi-Colored Text" script that randomly colors the characters of a text string. The Multi-Colored Text script - get it here - was authored by Erik Schmidt in 1998 and, like the Make Me A Password script discussed in the previous post, comes from the Java Goodies: Scripts that Display Text script collection.

The Multi-Colored Text script's effect - see it here - is very similar to that of the HTML Goodies JavaScript Script Tips #81-83 script, which we deconstructed in Blog Entry #99. However, the Multi-Colored Text script differs from the Script Tips #81-83 script in two key ways:
(1) The Multi-Colored Text script applies a much greater level of color-randomness to its text-string operand than does the Script Tips #81-83 script.
(2) Unlike the Script Tips #81-83 script, the Multi-Colored Text script will recognize and act on HTML markup in its text-string operand, e.g., if the string contains a <b>this text is bold</b> element, then the this text is bold content will be bolded (and randomly colored) on the page.

Before we get started, Erik wants us to know: BTW, for you Yankees, I spell colour with a 'u' because I'm Canadian. Duly noted, mate. Wherever you are, Erik, sit back, crack open an ice-cold Brador, and enjoy the show...

The text

In 1998 the latest versions of IE and Netscape were IE 4.x and Netscape 4.x, respectively. Unlike Microsoft's JScript, classical JavaScript did not have an innerHTML property via which the content of a div or p element could be accessed, so the Multi-Colored Text script's to-be-colored text string was placed in a script element as follows:

<body bgcolor="white">
<script language="javascript">
text = "This JavaScript shows every other letter of text as a different, random colour.";
text += " You can also use any <blink> <font size='9'> HTML </font> </blink> codes that you want";
text += " as long as you don't use quotation marks and the commands have a space between them.";
text += " You can use any background colour or picture that you want, but black or white is suggested.";
text += " <b> <u>HAVE FUN!!!</u> </b>";
colours(text);
<p>
</script>


innerHTML notes

• Just to be clear, the Multi-Colored Text script colors every (not every other) letter of text with a different, random color.

• In theory it is true that the text string can contain any HTML markup, but I encourage you to stick to elements that style text, as Erik does.

• As noted in The tables[5] table section of Blog Entry #293, the blink element (a) poses an accessibility problem and (b) is supported by neither IE nor Google Chrome nor Safari: don't use it.

• Value-wise, the size attribute of the font element only goes as high as 7 (not 9). As noted in the Pre-tables[1] section of Blog Entry #291, a size="7" font element attribute maps onto a font-size:48px; style declaration.

• As the script stands, it is true that the text string cannot contain (double) quotation marks and that there must be white space between adjacent HTML tags (e.g., <b> <u>); we'll sort out these limitations in due course.

• Erik may suggest a black background color, but I don't: stick with white.

HTML 4 deprecated the font and u elements; HTML5 is reinstating the u element and giving it a broader definition.

Once the five text string segments have been strung together, text is fed to a colours( ) function held by a separate script element in the document head. The colours( ) function call is followed by an out-of-place <p> tag that must be removed for the script to work.

pre-colours( )

The colours( ) function leverages a hexa pseudo-array of hexadecimal digits to create random hex codes for coloring the text characters.

hexa = new MakeArray(16);
hexa[10] = "A";
hexa[11] = "B";
hexa[12] = "C";
hexa[13] = "D";
hexa[14] = "E";
hexa[15] = "F";


function MakeArray(n) { this.length = n; for (var i = 0; i <= n; i++) this[i] = i; return this; }

function colours(text) { … }

The hexa construct is actually an Object object*, although you wouldn't know that from reading Mozilla's Object object page. The MakeArray( ) constructor function equips hexa with 18 members:

hexa[0] = 0;
hexa[1] = 1;
...
hexa[16] = 16;
hexa.length = 16;


The hexa[10]=10;-to-hexa[15]=15; members are overwritten by the hexa[10]="A";-to-hexa[15]="F"; statements that follow the new MakeArray(16); constructor.

(*You may recall that we recently dealt with analogous Object objects in the shopcartindex.html script of the "So, You Want A Shopping Cart, Huh?" shopping cart.)

Methinks the Object object business is too clever by half in that we can formulate hexa as a bona fide Array object via a single line of code:

var hexa = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "A", "B", "C", "D", "E", "F"];

Array literals are detailed here in the Mozilla JavaScript Guide.

The colours( ) function deserves its own entry so let's deal with it next time.

Sunday, November 03, 2013
 
The Password Factory
Blog Entry #305

In today's post we will discuss a "Make Me A Password" script that generates variable-length, random-character passwords for use on the Web. The "Make Me A Password" script was authored by Bill "Ace" Frederickson in 1998 and was part of the Scripts that Display Text collection of Joe Burns' late-1990s Java Goodies JavaScript Repository project.

You can grab Ace's script here; try it out here. The script does have one little glitch: in practice it occasionally produces a password that is one or two characters shorter than it should be. As we'll see below, correcting this glitch is nothing more complicated than changing a Math.round( ) command to a corresponding Math.floor( ) command.

The script interface

The script's interface comprises three controls - in order, a Length of Password : text box, a push button, and a Random Password : text box - held by a frmPw form.

<body>
<form name="frmPw">
Length of Password : <input type="text" name="txtMax" size="5" value="8"><br>
<input type="button" value="Pick Random Password" onclick="rndPw( );")><br>
<font size="+1">Random Password : <input type="text" name="txtRandpw" size="20" value=""></font>
</form>


The form container is semantically inappropriate in the sense that we won't be submitting any data to a processing agent, but it had to be there for the browser to render the inputs back in the day; today we would wrap the inputs and labels in a div.

If you want to hold onto the form container and plan to validate your document, then you should be aware that the form element has different content models in the Strict and Transitional DTDs.
(S) In the Strict DTD, the form element's content model is (%block;|SCRIPT)+ -(FORM), which the above code violates. If you go through the form examples in the Forms chapter of the HTML 4.01 Specification, you'll notice that in each case the control content is wrapped in a p element, which seems redundant to me in that the form and p elements are both width=100% %block; elements, although I'm sure that the W3C had a good reason for doing things this way.
(T) In the Transitional DTD, the form element's content model is (%flow;)* -(FORM), which the above code conforms to.

The Length of Password : and Random Password : labels can and should be marked up as label elements.

The <font size="+1"> … </font> markup is not quite equivalent to a font-size:larger; style declaration: the former takes a 16px font size to 18px whereas the latter takes a 16px font size to 19px. (Where else but at reptile7's JavaScript blog would you learn this crucial information? ;-)) Is it really necessary to make the Random Password : label larger than the Length of Password : label? Nope, lose the font element.

Lastly and least, the ) right parenthesis character at the end of the button's input element doesn't cause any problems but shouldn't be there - take it out.

Script operation

Clicking the button calls a rndPw( ) function in the document head. The rndPw( ) function generates a random-character password and loads it into the Random Password : field; the length of the password is set by the value of the Length of Password : field.

The rndPw( ) function first defines a series of variables:

function rndPw( ) { var iStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; var n = 0; var i = 0; var s = ""; len = document.frmPw.txtMax.value; … }

• The 26 uppercase A-Z alphabetic characters and the 26 lowercase a-z alphabetic characters and the 10 0-9 digit characters are loaded into a single string, which is given an iStr identifier; as you would intuit, the password characters will be drawn from the iStr string. You could add ASCII's symbolic characters (~, !, @, etc.) to the iStr string if you wanted to but it is probably best to stick with alphanumeric characters here.

• The n and i variables will be used to index-wise source the individual characters of the password, and are initialized to 0.

• The password will be assembled/stored in an s variable, which is initialized to an empty string.

• The value of the Length of Password/txtMax field is assigned to a len variable.

Next, a len-iteration for loop creates the password:

for (x = 1; x <= len; x++) { n = Math.random( ) * 62; i = Math.round(n); s += iStr.charAt(i); }

The n = Math.random( ) * 62; line calculates a random floating-point number (running many places past the decimal point) in the range 0 (inclusive) to 62 (exclusive) and assigns it to n; read about the random( ) method of the Math object here.

The i = Math.round(n); line rounds n up or down to the nearest integer, to which i is set; read about the round( ) method of the Math object here.

The s += iStr.charAt(i); line gets the ith character in the iStr string and appends it to s's value; read about the charAt( ) method of the String object here.

(We've encountered random( ), round( ), and charAt( ) many times previously, but given that Mozilla apparently does not subscribe to Tim Berners-Lee's "Cool URLs don't change" philosophy, I thought I would give you some updated references.)

The iStr string comprises 62 characters and its character index therefore runs from 0 to 61. If i is 62 (if n61.5), then iStr.charAt(i) returns an empty string and nothing is added to s. To ensure a len-character password, replace Math.round(n) with Math.floor(n), whose maximum return will be 61; read about the floor( ) method of the Math object here.

After len random iStr characters have been loaded into s, the rndPw( ) function finally assigns s to the value of the Random Password/txtRandpw field:

document.frmPw.txtRandpw.value = s;

Demo




The default password length is 8 although the Length of Password : field's value can be legitimately set to any positive integer*; as a practical matter, however, I wouldn't go any higher than 15.
*It is left to the reader to add to the rndPw( ) function validation code that flags other input types: floating-point numbers, 0, etc.

Some password-soliciting Web sites recommend or require that user passwords contain at least one uppercase letter, at least one lowercase letter, and at least one digit; you may need to click the button a few times to get a password that meets these criteria.

N.B. I apply the Verdana typeface to the password because, unlike some other common fonts, Verdana renders distinctively the uppercase I letter, the lowercase l letter, and the 1 digit.

And there you have it - a very simple script that does something genuinely useful. Password away!


Powered by Blogger

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