reptile7's JavaScript blog
Tuesday, February 20, 2007
 
Google It, Part 2
Blog Entry #67

HTML Goodies' JavaScript Script Tips #42, #43, and #44 return us to the topics of search engines and scripts that search them. Back in Blog Entry #34, we discussed HTML Goodies' JavaScript Primers #18 and its script that, when brought up to date, searches the Yahoo! search engine; inspired by the Script Tips #42-44 Script, we then modified the Primer #18 Script so that it could search both Yahoo! and Google simultaneously. In this entry, we'll take a closer look at the Script Tips #42-44 Script, which, when brought up to date, can search as many as five search engines at once.

Per the discussion at the beginning of Blog Entry #64, the Script Tips #42-44 Script is located in HTML Goodies' /legacy/beyond/javascript/stips/ subdirectory (you won't find it by following the "Here's the Code (It's big. Get it all.)" links in Script Tips #42-44); the script can be accessed at http://www.htmlgoodies.com/legacy/beyond/javascript/stips/scripttip42script.html, or you can copy it from the div below:

<script language="javascript">

function wordsplit(items) 
{
var charect = "";
for (var n = 1 ; n <= items.length ; n++) 
{
if (items.substring(n-1,n) == " ") 
{ charect += "+"; }
else 
{ charect += items.substring(n-1,n); }
} // end of for loop
return charect;
}

function search( )
{
var keywords = document.searching.query.value; 
var search1;
var search2;
var search3;
var search4;
var search5;

key = wordsplit(keywords); 

if (document.searching.yahoo.checked)
{
search1 = document.searching.yahoo.value; 
search1 += key;
wind = window.open(search1,"newwindow1","width=700,height=200,scrollbars=yes");
}

else // this keyword is unnecessary

if (document.searching.altavista.checked)
{
search2 = document.searching.altavista.value; 
search2 += key;
wind = window.open(search2,"newwindow2","width=700,height=200,scrollbars=yes");
}

if (document.searching.webcrawler.checked)
{
search3 = document.searching.webcrawler.value; 
search3 += key;
wind = window.open(search3,"newwindow3","width=700,height=200,scrollbars=yes");
}

if (document.searching.lycos.checked)
{
search4 = document.searching.lycos.value; 
search4 += key;
wind = window.open(search4,"newwindow4","width=700,height=200,scrollbars=yes");
}

if (document.searching.excite.checked)
{
search5 = document.searching.excite.value; 
search5 += key;
wind = window.open(search5,"newwindow5","width=700,height=200,scrollbars=yes");
}
}
</script>

<form name="searching">
Enter the Key word : <input type="text" name="query" size="20"><BR><BR>
<b>Select the Search Engine(s):</b><br>

<input type="checkbox" name="yahoo" value="http://search.yahoo.com/search?p="> Yahoo<br>

<input type="checkbox" name="altavista" value="http://www.altavista.digital.com/cgi-bin/query?pg=q&what=web&fmt=.&q=">Altavista<br>

<input type="checkbox" name="webcrawler" value="http://www.webcrawler.com/cgi-bin/WebQuery?searchText=">WebCrawler<br>

<input type="checkbox" name="excite" value="http://www.excite.com/search.gw?trace=a&search=">Excite<br>

<input type="checkbox" name="lycos" value="http://www.lycos.com/cgi-bin/pursuit?query=">Lycos<br>

<input type="button" value="Search" onclick="search( );">
<input type="reset" value=" Clear ">

</form>
 
Introduction In the document body, the Script Tips #42-44 Script codes a form, named searching, comprising eight controls. (0) The zeroth control is a text box, named query, in which the user enters a search term. (1-5) The next five controls are checkboxes that present a 'menu' of search engines. For each checkbox, the name attribute value is set to the lowercased name of a search engine (yahoo, altavista, etc.) and the value attribute value is set to a partial URL for a page of search results obtained by that search engine. (6-7) The sixth control is a "Search" push button for triggering the script's searching action; the seventh control is a " Clear " reset button. So, the user types one or more words into the query box and selects one or more search engines from the checkbox menu; clicking the "Search" button then calls the script element's search( ) function. The user's query input, document.searching.query.value, is first assigned to the variable keywords. Second, the variables search1, search2, search3, search4, and search5 are declared, for later use, but not initialized. I find on my computer that these declarations are unnecessary; the script runs normally (no errors are thrown) if they are commented out. The next expression calls the script element's wordsplit( ) function and passes thereto the keywords value: key = wordsplit(keywords); The wordsplit( ) function will itself send a modified value to this point in the document, and that value will be assigned to the variable key. The wordsplit( ) function The wordsplit( ) function checks the user's input for space characters and replaces them with + signs, mimicking the behavior of many search engines in a normal search. (Indeed, with respect to the search engines searched by the Script Tips #42-44 Script, Yahoo!, AltaVista, and Lycos replace spaces with + signs; also, Excite escapes a space to %2B, in which 2B is the +'s ASCII hexadecimal representation.) My intuition told me that the wordsplit( ) function was also 'excess baggage,' and sure enough, I found that I could comment it out without any problems. An analysis of wordsplit( ) is thus somewhat of an academic exercise, but is still worthwhile in terms of its instructive value, so let's get into it. Consider a test case: suppose you are using the Script Tips #42-44 Script to search for information on the C programming language. So, the search( ) function assigns C programming language to keywords, and then the key=wordsplit(keywords) expression calls the wordsplit( ) function, whereupon keywords is renamed items. Subsequently, wordsplit( ) converts C programming language to C+programming+language via the following sequence of events: (1) We literally begin 'from scratch': our starting point is an empty string, assigned to the variable charect. (2) Next, the items string is tested for spaces and rebuilt on a character-by-character basis via a for loop: for (var n = 1; n <= items.length; n++) { if (items.substring(n-1,n) == " ") charect += "+"; else charect += items.substring(n-1,n); } (3) For the for loop's first iteration (n=1): (a) items.substring(0,1) returns items's zeroth character, which is a C. (b) The if condition returns false - a C is not equal to a space - so the browser proceeds to the else statement. (c) C is then assigned to charect. (We previously discussed the substring( ) method of the String object and the += shorthand assignment operator in Blog Entry #65.) (4) For the for loop's second iteration (n=2): (a) items.substring(1,2) returns items's first character, which is a space. (b) The if condition returns true, so a + is added to the right-hand end of charect; charect is now C+. (5) For the for loop's third iteration (n=3): (a) items.substring(2,3) returns items's second character, a p. (b) The if condition returns false, and the else statement adds p to the right-hand end of charect; charect is now C+p. I trust you can take it from here. After items.length=22 iterations, the for loop stops and charect is C+programming+language, which is finally returned to the wordsplit( ) function call in the search( ) function and assigned to key. "Is it necessary for the wordsplit( ) code to be in its own separate function?" Actually, no, it isn't. If desired, you can remove the wordsplit( ) function and replace the key=wordsplit(keywords) expression with: var key = ""; for (var n = 1; n <= keywords.length; n++) { if (keywords.substring(n-1,n) == " ") key += "+"; else key += keywords.substring(n-1,n); } An alternate space-to-+ conversion Somewhat more efficiently, the following regular expression-based code will also replace keywords's space characters with + signs: var key = keywords; var space = /\s/g; if (space.test(key)) key = key.replace(space, "+"); Comments • With respect to the space regexp pattern, \s matches a single space character; the g flag will allow us to match all occurrences of \s in the key string. • We discussed the test( ) method of the core JavaScript RegExp object in Blog Entry #49. • The heavy lifting here is done by the replace( ) method of the String object, which acts on key and replaces each space-in-key match with a +. And now, back to the search( ) function With key=C+programming+language in hand, it's time to get our searching underway. The search( ) function next runs through a series of if statements, one for each checkbox, that can be written in general form as: if (document.searching.checkboxName.checked) { search# = document.searching.checkboxName.value; search# += key; wind = window.open(search#,"newwindow#","width=700,height=200,scrollbars=yes"); } (Preceding the second if statement is an unnecessary else keyword that can be removed - indeed, it doesn't appear in the Script Tips #42-44 source.) If a given checkbox is checked, then the condition of its if statement (document.searching.checkboxName.checked) returns true; subsequently: (1) the checkbox value (document.searching.checkboxName.value) is assigned to one of the search# variables; (2) key is tacked onto the right-hand end of search#, giving a full URL for a page of search results obtained by the search engine associated with that checkbox/if statement; (3) the full URL is reassigned to search#, which is then plugged into a window.open( ) command, setting up a link to search# in a new browser window. Joe gives a line-by-line discussion of the Yahoo! if statement in Script Tip #44. You've probably noticed that the new windows of all five window.open( ) commands are variabilized with the identifier wind: wind = window.open(search#,"newwindow#","width=700,height=200,scrollbars=yes"); Unless you want to manipulate the new windows from the opener document (in which case they should be referenced differently - wind1, wind2, etc.), however, new window variabilization is unnecessary. Don't leave it blank, part 4 Towards the end of Script Tip #44, Joe's readers ask, But what if no checkboxes are checked? Can we put up an alert saying to post? Joe summarizes his efforts to ensure that a user chooses at least one search engine checkbox as follows:
I played around with some code, checking all of the Ifs in one shot, and it started to get to be too much code for what it produced. I'm happy with the page just sitting still if no search engines are checked. If you can find a quick method of altering the script to produce that alert and keep the function of the script the same, let me know. I'll be glad to post it.
It is with pleasure that I offer two straightforward, related solutions to this problem. Solution #1 At the beginning of the search( ) function, declare: var r = 0; In each if statement in the search( ) function, follow the window.open( ) command with: r = 1; At the end of the search( ) function (after the fifth if statement), add: if (r != 1) window.alert("Please make a selection."); My use here of the r tracking variable is based on a similar tactic appearing in the Script Tips #13-15 Script. Solution #2 In the search( ) function, comment out the search# declarations and then replace the series of if statements with: var search42 = new Array( ); var unchecked = 0; for (i=1; i<6; i++) { if (document.searching.elements[i].checked) { search42[i] = document.searching.elements[i].value; search42[i] += key; window.open(search42[i],"newwindow"+i,"width=700,height=200,scrollbars=yes"); } if (!document.searching.elements[i].checked) unchecked++; if (unchecked == 5) window.alert("Please make a selection."); } The approach here mirrors that of the code samples in Blog Entry #47. By referencing searching's checkboxes via the elements[ ] array, we can automate with a for loop the testing of checked-vs-unchecked checkbox states. As the loop proceeds, the variable unchecked counts up the number of unchecked checkboxes; if unchecked reaches a value of 5, then an alert( ) message pops up. Note that we cannot use i<=document.searching.elements.length for the for loop condition; if we did, then the alert( ) box would also pop up if the user chooses one, two, or three checkboxes - recall that the searching form contains a total of eight, and not five, control elements. Alternatively, if you'd rather not use a for loop, you can (a) put a var unchecked = 0 declaration at the beginning of the search( ) function, (b) follow each if statement with an else unchecked++ statement, and (c) put the if (unchecked == 5) alert("Please make a selection.") statement at the end of the search( ) function.

We're not through yet - up to this point, we haven't said anything about how the Script Tips #42-44 Script actually works in practice, and we'll get to that in the next entry.

reptile7

Labels:


Sunday, February 11, 2007
 
Breakfast, Lunch, and Dinner Links
Blog Entry #66

A couple of points to chew on before we get rolling today:

(1) Needless to say, links play an essential role (some might say the essential role) in HTML. With respect to the "hypertext" aspect of HTML, the "What is HTML?" section of HTML Goodies' "Basic HTML: Introduction" tutorial explains:
Hyper is the opposite of linear. It used to be that computer programs had to move in a linear fashion. This before this, this before this, and so on. HTML does not hold to that pattern and allows the person viewing the World Wide Web page to go anywhere, any time they want.
JavaScript significantly enhances the linking facility of HTML via the location property/object. Who needs an anchor element? Almost any document body element can be coupled in some way with a window.location or location.href statement and turned into a link.

(2) By design, the select element and its optgroup/option element descendants are capable of packing more functionality into a smaller space than just about any other HTML element.

These considerations intersect in HTML Goodies' JavaScript Script Tips #38-41, our focus in this entry. Script Tips #38 and #39 offer a simple script that codes a menu of links whose URLs are the values of option elements of a select element. This type of link menu is very common on the Web, and we'll briefly look at a 'real-world example' later in the post. The Script Tips #38-39 Script is given below:

<script language="javascript">

function LinkUp( )
{
var number = document.DropDown.DDlinks.selectedIndex;
location.href = document.DropDown.DDlinks.options[number].value;
}
</script>

<form name="DropDown">
<select name="DDlinks">
<option selected>--> Choose a Link <--
<option value="scripttip1.html"> Page One
<option value="scripttip2.html"> Page Two
<option value="scripttip3.html"> Page Three
</select>

<input type="button" value="Click to Go!" onclick="LinkUp( );">
</form>

Overview of the Script Tips #38-39 Script

Joe goes over the DropDown form and its controls in Script Tip #38. I have a few comments to add to the mix:

• We won't be sending the DropDown form to a processing agent, so if preferred, you can
(a) remove the form element start-tag and end-tag,
(b) replace the select element's name="DDlinks" attribute with an id="DDlinks" attribute, and then
(c) reference the select element with document.getElementById("DDlinks")
à la recent entries.

The first [in source order] 'option' is the one that will display so we will not give that a VALUE. Even if we don't specify a value attribute for the zeroth option element, however, it would still seem to have a value; according to the W3C, If [the value] attribute [of an option element] is not set, the initial value is set to the contents of the OPTION element. In practice, I find on my iMac that document.DropDown.DDlinks.options[0].value returns an empty string and not --> Choose a Link <--.

• In HTML, the option element end-tag is optional; if you want the script to be XHTML-compliant, then </option> tags must be added.

• The XHTML purists in the audience should also formulate the selected Boolean attribute of the zeroth option element as selected="selected", granted that this may pose problems for older browsers.

I have three items to choose from. You can have fifty, or more, if you want. Here we see the advantage of the select element as noted at the outset of the post. Layoutwise, a selection list of 50 options occupies less than a line in a document; a corresponding link menu of, say, radio buttons would take up 50 lines (I suppose you could scrunch it into fewer lines, but it wouldn't look very nice).

DropDown's last control, a push button, triggers when clicked the LinkUp( ) function, which effects the script's linking action and is discussed in Script Tip #39.

So, the user makes a selection from the menu and then clicks the "Click to Go!" button. The value of the user's chosen option is a relative URL, scripttip#.html, that LinkUp( ) will assign to the href property of the location object, creating a link. LinkUp( ) determines that value via the method outlined in the "Determining user input: selection lists" section of Blog Entry #17:

var number = document.DropDown.DDlinks.selectedIndex;
location.href = document.DropDown.DDlinks.options[number].value;

(If the user doesn't make a selection and clicks the button, then assignment of the empty string (vide supra) value to location.href causes the page to reload.)

This is the simplest, but not the only, way to ascertain a user's select element input, as we'll see below in our discussion of Script Tip #41.

Some up-to-date reference links: in the DOM Level 2 HTML Specification,
(a) the HTMLSelectElement Interface is here,
(b) the HTMLOptionsCollection Interface is here, and
(c) the HTMLOptionElement Interface is here.

BTW, the square bracket characters in the location.href statement are (sigh) once again escaped to &#91; and &#93; in the Script Tips #38-39 source - moreover, my attempts to access scripttip1.html, scripttip2.html, and scripttip3.html pages in HTML Goodies' /beyond/javascript/stips/article.php/ subdirectory did not lead to Script Tips #1-3 (blank pages came up) - so you won't observe a script effect if you "Choose a Link" and then "Click to Go!" in Script Tips #38-39. However, a functioning Script Tips #38-39 Script demo can be found here.

One more minor comment before moving on: contra Script Tip #39, neither of LinkUp( )'s statements must be "on one written line":

function LinkUp( ) {
var number =
document.DropDown.DDlinks.selectedIndex;
location.href =
document.DropDown.DDlinks.options[number].value; }

executes just fine, for example.

Script Tip #40

Script Tip #40 slightly modifies the Script Tips #38-39 Script so that when the user chooses a DDlinks option, then the script automatically links to the destination document; towards this end, Script Tip #40 ditches the "Click to Go!" push button and instead triggers LinkUp( ) with an onchange select element attribute:

<select name="DDlinks" onchange="LinkUp(this.form);">

The interesting thing here is the LinkUp( ) function call's this.form argument, which references the DropDown form. (The this.form expression does not return [t]he output of the form, the index number of the user's choice - this.form.DDlinks.selectedIndex would do that.) Is the this.form parameter necessary? It ain't necessary - LinkUp( ) holds what it needs and doesn't need to be 'fed' anything. Nevertheless, a reformulated, parameterized LinkUp( ) that meaningfully accepts this.form is certainly possible, e.g.:

<script type="text/javascript">
function LinkUp(myForm) {
var number = myForm.DDlinks.selectedIndex;
location.href = myForm.DDlinks.options[number].value; }
</script>
<form name="DropDown">
<select name="DDlinks" onchange="LinkUp(this.form);"> <!--etc.-->

A functioning Script Tip #40 Script demo can be found here.

Script Tip #41

Script Tip #41 adapts the Script Tips #38-39 Script to a top-and-bottom two-frame page:

<frameset rows="30%,*">
<frame src="menuframes.html" />
<frame src="lookhere.html" />
</frameset>

Frames references
(1) HTML Goodies' "So, You Want Some Frames, Huh?" tutorial provides a gentle introduction to frames for those who might be new to this topic.
(2) The W3C discusses frames in Chapter 16 of the HTML 4.01 Specification.

The following code is loaded into the menuframes.html (top) frame document:

<script language="javascript">
function acrossFrames( ) {
if statement #1
if (document.FrameForm.DDFrameForm.options[0].selected)
parent.frames[0].location = 'menuframes.html';
if statement #2
if (document.FrameForm.DDFrameForm.options[1].selected)
parent.frames[1].location = 'scripttip1.html';
if statement #3
if (document.FrameForm.DDFrameForm.options[2].selected)
parent.frames[1].location = 'scripttip2.html';
if statement #4
if (document.FrameForm.DDFrameForm.options[3].selected)
parent.frames[1].location = 'scripttip3.html'; }
</script>
<form name="FrameForm">
<select name="DDFrameForm">
<option selected> --> Pick One <--
<option>Script Tip One
<option>Script Tip Two
<option>Script Tip Three
</select>
<input type="button" value="go there" onclick="acrossFrames( );">
</form>

The form element, the select element, and the linking function have all been renamed; much more importantly, note that the value attributes of options[1], options[2], and options[3] have been stripped out. The acrossFrames( ) function replaces LinkUp( )'s location=selectObject.options[selectObject.selectedIndex].value code with a series of four if statements, one for each DDFrameForm option. Let's look at if statement #2:

if (document.FrameForm.DDFrameForm.options[1].selected)
parent.frames[1].location = 'scripttip1.html';

(At last, an appropriate use of the parent property of the window object! Also, the frames[ ] array, as a property of the window object, is discussed here.)

This if statement says, "If it's true that the first [second in source order] option of the DDFrameForm selection list of the FrameForm form of the document is selected, then assign [the file] scripttip1.html to the value of the location property of the first [second in source order] frame of the parent frameset window," or in plain English, selecting the "Script Tip One" option will load scripttip1.html into the bottom frame (i.e., after clicking the "go there" button). Analogously, if statements #3 and #4 load scripttip2.html and scripttip3.html into the bottom frame if the "Script Tip Two" and "Script Tip Three" options are chosen, respectively.

If preferred, if statements #2-4 can be condensed via a for loop:

for (i=1; i<document.FrameForm.DDFrameForm.options.length; i++) {
if (document.FrameForm.DDFrameForm.options[i].selected)
parent.frames[1].location = "scripttip" + i + ".html"; }

For that matter, if we put the value="scripttip#.html" attributes back in the <option> tags, then we can, à la the LinkUp( ) function, replace if statements #2-4 with:

var number = document.FrameForm.DDFrameForm.selectedIndex;
parent.frames[1].location = document.FrameForm.DDFrameForm.options[number].value;

Script Tip #41's "See It In Action" link leads to a mostly functioning demo. The "Script Tip One", "Script Tip Two", and "Script Tip Three" selections respectively load Script Tips #1, #2, and #3 into the bottom frame successfully, but if you click "go there" without making a selection, then a "404 - File not found" page loads into the top frame. Checking the demo page's source, we see that the frame files have a .htm, and not a .html, extension; reloading the menuframes.htm page into the top frame, then, is a simple matter of replacing if statement #1's 'menuframes.html' with 'menuframes.htm'.

A real-world example

We wrap up this entry with a visit to CNN.com. Scrolling to the bottom of the page, we encounter a link menu, whose coding is:

<form>
<select title="CNN.com is available in different languages" name="languages" size="1" onchange="if (this.options[selectedIndex].value != '') location.href=this.options[selectedIndex].value;" class="cnnFormSelectSm">
<option value="" disabled selected>Languages</option>
<option value="" disabled>---------</option>
<option value="http://arabic.cnn.com/">Arabic</option>
<option value="http://www.CNN.co.jp/">Japanese</option>
<option value="http://www.joins.com/cnn/">Korean</option>
<option value="http://cnnturk.com/">Turkish</option>
</select>
</form>

Like Script Tip #40's code, this menu's select element start-tag contains an onchange event handler that creates a link by assigning the value of the user's selected option to location.href; no function is involved, or needed. Via the if conditional, no linking occurs if the selected option value is an empty string, as is the case for the zeroth and first options. Noteworthily, the onchange attribute is able to use selectedIndex, as opposed to this.selectedIndex, as an options[ ] index number.

The title attribute, used here with the select element and which is usable with most HTML elements, is discussed here in the HTML 4.01 Specification.

The select element's size="1" attribute and the disabling of the first two options (disabled is another Boolean attribute, and is defined by the W3C here) seem redundant to me, but perhaps there are user agents for which they are necessary. Moreover, no use is made of the select element's name="languages" attribute, but it doesn't hurt to have it there.

The select element's .cnnFormSelectSm CSS style block, detailed on this page, is:

.cnnFormSelectSm {
font-family: arial, verdana, sans-serif;
font-size: 10px;
color: #000; }

The multiple search engine script of Script Tips #42-44 also maps form controls onto URLs and we'll take it on in the next post.

reptile7

Labels:


Friday, February 02, 2007
 
When We Two Ticker-Taped
Blog Entry #65

Today we examine a script with a distinctly cool effect (or at least I think so):


HTML Goodies offers three scrolling text scripts.
(1) The simplest (and best, IMO) of these scripts is the focus of Script Tips #35, #36, and #37.
In addition, the Beyond HTML : JavaScript section of HTML Goodies sports
(2) a "So, You Want A Scrolling JavaScript, Huh?" tutorial and
(3) a "So, You Want A JavaScript Ticker Tape, Huh?" tutorial
that provide such scripts.

We'll go over the Script Tips #35-37 Script in this entry. We may well return to the other two scripts at some point in the future, as they 'scream out for simplification,' if you get my drift.

The Script Tips #35-36 Script

Script Tips #35 and #36 give a script that writes a scrolling text message to the browser window's status bar. Script Tip #37 slightly modifies the Script Tips #35-36 Script so that the text scroll runs in an <input type="text"> box. The Script Tips #35-36 Script is reproduced below:

<script language="javascript">

var space = "                  "; // 18 spaces
var ScrollText = space + "Hey hey! Look at me scrollin'...";

function SBScroll( ) {

temp = ScrollText.substring(0,1);
ScrollText += temp;
ScrollText = ScrollText.substring(1,ScrollText.length);
window.status = ScrollText.substring(0,ScrollText.length);

setTimeout("SBScroll( );",100); }

</script>

Well, you're going to need something to scroll, so let's make it, Joe says in Script Tip #35. Glancing at the script, and without any deconstruction, you can probably figure out that the script's scrolling message is represented by the variable ScrollText. ScrollText comprises two parts:
(1) a "buffer" of 18 spaces is stringified and assigned to the variable space;
(2) space is then prepended to the scrolling message, in this case "Hey hey! Look at me scrollin'...".
(FYI: for its display in Script Tips #35-37, the space declaration appears in the source as:
var space = " &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;".
For executing the script, however, 18 normal spaces via the space bar are good enough for space.)

Next we have the SBScroll( ) function, which creates the scroll and puts it in the status bar. How do we trigger it? In Script Tips #35-36 (and also for Script Tip #37's modified script), Joe uses a push button and an onclick event handler:

<input type="button" value="Click me For the Scroll" onclick="SBScroll( );" />

Perhaps more conventionally and per Joe's recommendation, my demo above calls SBScroll( ) with an onload="SBScroll( );" body element attribute, as we'll see later.

The SBScroll( ) function

To more easily see what's going on, I'm going to replace space's space characters with hyphens. Going into the SBScroll( ) function, then, we have:
ScrollText = ------------------Hey hey! Look at me scrollin'...

Joe's attempted deconstruction in Script Tip #36 is hobbled by his misunderstanding of the substring( ) method of the core JavaScript String object. He correctly begins, The method substring( ) allows you to take only a portion of a text string - so far, so good - but then he confusingly adds, The way a substring( ) method works is taking the higher of two variables...the substring( ) method returns the greater of two items - this description approximately applies to the max( ) method of the JavaScript Math object, but not to the substring( ) method. The substring( ) method definition in the HTML Goodies JavaScript methods keyword reference is better but still leaves room for improvement.

The syntax of the substring( ) method is:

[var stringSubset =] stringObject.substring(indexA, indexB);

Some necessary background from Netscape's String object documentation:
You can think of a string as an array of characters. In this way, you can access the individual characters in the string by indexing that array...Characters in a string are indexed from left to right. The index of the first character is 0, and the index of the last character in a string called stringName is stringName.length - 1.

With respect to the stringObject on which it acts, the substring( ) method returns the subset of stringObject beginning at the indexA character and running to the indexB - 1 character, i.e., up to but not including the indexB character; for example:

"Hello, World!".substring(3,8);
// returns lo, W; recall that the H is the zeroth character of the string

Now that we have this sorted out, let's turn to the SBScroll( ) function and go through it line by line.

(1) temp = ScrollText.substring(0,1);
This statement assigns the zeroth character of ScrollText, - (a hyphen), to the variable temp.

(2) ScrollText += temp;
Something new! This is the first time we've used a shorthand assignment operator; the statement above is a shorthand version of:

ScrollText = ScrollText + temp;

Note the order of addition operands: x += y is equivalent to x = x + y and not x = y + x; although unimportant for arithmetic addition, the operand order is definitely important for string concatenation, our present concern. The ScrollText += temp command thus adds temp's - to the right-hand end of ScrollText, and the resulting one-character-longer string, still beginning with 18 hyphens, is reassigned to ScrollText:
ScrollText = ------------------Hey hey! Look at me scrollin'...-.

(3) ScrollText = ScrollText.substring(1,ScrollText.length);
This command effectively chops off the zeroth character of ScrollText, and the resulting string, now beginning with 17 hyphens, is reassigned to ScrollText:
ScrollText = -----------------Hey hey! Look at me scrollin'...-.
(Note that a ScrollText.substring(1,ScrollText.length-1) command would also chop off ScrollText's last character.)

(4) window.status = ScrollText.substring(0,ScrollText.length);
This statement then writes ScrollText to the browser window's status bar in a normal manner. Of course,

window.status = ScrollText;

would work just as well here.

(5) setTimeout("SBScroll( );",100);
This expression re-calls the SBScroll( ) function after a 100-millisecond time delay. In the course of ten such recursive function calls, here's what we see in the status bar:

-----------------Hey hey! Look at me scrollin'...-
----------------Hey hey! Look at me scrollin'...--
---------------Hey hey! Look at me scrollin'...---
--------------Hey hey! Look at me scrollin'...----
-------------Hey hey! Look at me scrollin'...-----
------------Hey hey! Look at me scrollin'...------
-----------Hey hey! Look at me scrollin'...-------
----------Hey hey! Look at me scrollin'...--------
---------Hey hey! Look at me scrollin'...---------
--------Hey hey! Look at me scrollin'...----------
-------Hey hey! Look at me scrollin'...-----------

In an animation-like effect, the Hey hey! Look at me scrollin'... message appears to travel from right to left, running off the left end of the status bar and reappearing to the right thereof; what we're actually seeing is a cyclical, repeating display of a string of unchanging length but changing composition - in successive displays, we pick up the 0th character, tack it onto the end of the string, and then all of the string's characters shift one position, indexwise, to the left. Do it over and over again and you've got a scroll.

A formatted scroll

(The code appearing in this and the next sections pertains to the post's original textscroll.html and leftscroll.html demos, which are now in self-contained divs.)

As noted above, Script Tip #37 provides code for putting the scroll in a text box; a benefit thereof: you can then format the scroll via some style declarations, if desired. (Maybe your computer will allow you to format status bar text - mine won't.) Here's the style block I used for my demo at the outset of this post:

input {
border-width: 0px;
color: teal;
font-family: sans-serif;
font-size: 16px;
font-weight: bold; }

Here's the demo document body HTML:

<body onload="SBScroll( );">
<input size="50" id="scrollBox" />
</body>

In the script element, the scroll is written to the text box with:

document.getElementById("scrollBox").value = ScrollText;

The demo document is itself loaded into an iframe:

<iframe width="100%" height="40" src="http://home.earthlink.net/~reptile7jr/textscroll.html" frameborder="0" scrolling="no">Your browser does not support iframes. Please see Script Tip #37 for a related demo.</iframe>

West to east

A scroll that runs from right to left is appropriate for a message in a left-to-right language; recall from high school physics that if the eyes are set at the origin of an inertial frame of reference, then during the normal reading of left-to-right text, the words move to the left (i.e., in the -x direction) as they are being read. If you prefer a scroll that runs from left to right - for a message in a right-to-left language, or simply because you are, like myself, a bit of a contrarian - then this can be easily done by 'reversing' the operations of the Script Tips #35-37 Script.


Here's the script I used; its deconstruction is left to you:

<script type="text/javascript">

var ScrollText = "Here, kitty kitty kitty...                  ";

function SBScroll2( ) {

temp = ScrollText.substring(ScrollText.length-1,ScrollText.length);
ScrollText = temp + ScrollText;
ScrollText = ScrollText.substring(0,ScrollText.length-1);
document.getElementById("scrollBox2").value = ScrollText;

window.setTimeout("SBScroll2( );",100); }

</script>

<body onload="SBScroll2( );"><input id="scrollBox2" /></body>

And here's my CSS:

input {
border-width: 0px;
color: maroon;
display: block;
font-family: sans-serif;
font-size: 16px;
font-weight: bold;
margin-left: auto;
margin-right: 0px;
width: 250px; }

In our next episode, we'll tuck into the Script Tips #38-41 Script, which codes a selection-list-based menu of links.

reptile7

Labels:



Powered by Blogger

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