reptile7's JavaScript blog
Tuesday, August 10, 2010
Let's Scroll Some More
Blog Entry #187

In the previous post, we dissected the scrolling text script of HTML Goodies' "So, You Want A JavaScript Ticker Tape, Huh?" tutorial. At this point, we have the script's scroll up and running:

(As in our trial run through the move( ) function at the end of the last entry, I've given the input element a font-family:Courier; style so that the width of the scroll initially matches the size of the scroll field.)

Next issue: How would we stop the scroll, if we wanted to do that? After all, not everyone likes text scrolls; indeed, some users find them distracting and annoying...

The terminator

In the tt_start( ) function and at the end of the move( ) function itself, the main move( ) function that creates the scroll is called via the following window.setTimeout( ) command:

tt_tid = window.setTimeout("move( );", tt_speed);

The window.setTimeout( ) method returns a number* - typically a low-value integer: 0, 1, or 2 - that serves as an ID for the timeout it sets: imagine a <timeout delay="250" id="1">move</timeout> element corresponding to the above statement. (*Mozilla's window.setTimeout( ) page doesn't say anything about the timeoutID data type, although Microsoft's window.setTimeout( ) page does.) The timeout ID can be fed to a window.clearTimeout( ) command to cancel both the timeout and the code execution delayed by the timeout, and the script's main script element includes a tt_cleartid( ) function with such a command:
function tt_cleartid( ) {
	window.clearTimeout(tt_tid); }
The tt_cleartid( ) function is not called at any point in the script. But it is simple enough to add to the tickertapeform form a button that when clicked would call it:

<button type="button" onclick="tt_cleartid( );">Stop the scroll</button>

Complementarily, we could follow the button with a button that when clicked would restart the scroll by re-calling the move( ) function:

<button type="button" onclick="move( );">Restart the scroll</button>

Two more points before moving on:

(1) When delaying a function call with window.setTimeout( ), a simple functionName object reference to the function can serve as the first setTimeout( ) parameter:

tt_tid = window.setTimeout(move, tt_speed);

Mozilla recommends this syntax vs. the "move( );" stringified function call syntax.

(2) The W3C has brought the setTimeout( ) and clearTimeout( ) methods into HTML5.


Including the tt_cleartid( ) function and not counting the first ticker( ) function, the main script element contains four functions, in source order: move( ), tt_start( ), tt_cleartid( ), and ticker( ). We definitely need the move( ) function to create the scroll, but the other three functions can be thrown out, if desired.

The move( ) function is originally called by the tt_start( ) function. To get rid of the tt_start( ) function:
(1) Globally declare the tt_f identifier for the tickertapeform form.
(2) Move tt_start( )'s move( ) function call to the end of the script element.

The tt_start( ) function is called by the second ticker( ) function. To get rid of the second ticker( ) function:
(1-3) Globally set tt_message, tt_len, and tt_speed to their move( ) values.
(4-5) Write the tickertapeform form as normal HTML as described in the previous post, and then delete the tt_start( ) function call.

var tt_f = document.tickertapeform;
/* With an eye on XHTML compliance, you might prefer to remove the form's name attribute and write the above declaration as: var tt_f = document.forms[0]; */

var tt_message = "The rain in Spain falls mainly on the plain...";
var tt_len = 35;
var tt_speed = 250;
function move( ) { ... }

move( ); /* Is there a need to delay the initial move( ) call? Nah. */

The tt_cleartid( ) function is a nice extra but is unnecessary; chuck it if the ability to stop the scroll is not a priority for you.

That leaves us with just the move( ) function, which, vis-à-vis its appearance on the tickertp.txt page, can itself be slightly tightened up by combining its if (tt_c < 0) and else clauses as shown below. Moreover, move( )'s cend variable can be eliminated, as there's no real need to bound the scroll at tt_c + tt_len for relatively long tt_messages (at least I'm unaware of any limitation on a text box's value.length, which is not to say that creating a really long scroll is a good idea - it isn't); if tt_message extends beyond the right edge of the scroll field, no big deal.
function move( ) {
	if (tt_c < 0) { // If tt_c is in the 'space zone':
		cstart = 0;
		tt_f.scroll.value = tt_space.substring(0, -tt_c) + tt_message.substring(cstart, tt_message.length); }
	else { // If tt_c is in the 'text zone':
		cstart = tt_c;
		tt_f.scroll.value = tt_message.substring(cstart, tt_message.length); }
	tt_c = tt_c + 1;
	if (tt_c == tt_message.length) tt_c = -tt_len;
	tt_tid = window.setTimeout(move, tt_speed); }
The move( ) function could be shrunk significantly if we were to apply it to a concatenated tt_space + tt_message string à la the Script Tips #35-37 script, e.g.:
var scrollText = tt_space + tt_message;

function move( ) {
	scrollText = scrollText.substring(1, scrollText.length);
	tt_f.scroll.value = scrollText;
	if (scrollText.length == 1) scrollText = tt_space + tt_message;
	tt_tid = window.setTimeout(move, tt_speed); }
Format me

In the tutorial's "Go Faster You Script You!" section, Joe laments, You cannot change the scrolling text to bold or italic or make it bigger using this script. This script is a very simple scroll and you'd need a more fancy piece to play with the text; relatedly, tutorial commenters JohnS and Steeeeve ask about coloring the scroll text. The b, i, and font elements can validly have input element children by virtue of their (%inline;)* content model, but it doesn't follow therefrom that these elements will have any effect on text box values as such values do not constitute element content, and in practice they don't. (One exception: I find that Opera applies the i element to both text and textarea field values.)

I don't know when exactly the "So, You Want A JavaScript Ticker Tape, Huh?" script was written, but given that its main script element is wrapped in an xmp element, whose use the W3C was discommending as early as HTML 2.0, it clearly goes back pretty far and probably predates the first CSS and DOM specifications. Gratifyingly, modern browsers generally apply CSS's font properties and color property to text input values, and therefore an

input { color: red; font: bold italic 24px; }

style rule set is all we would need to create a red, bolded, italicized, double-sized scroll.

But as we have noted several times previously, CSS 2.1 does not define which properties apply to form controls ... or how CSS can be used to style them - what if the user's browser won't apply the above CSS to the scroll field? Once upon a time (more specifically, for pre-'level 4' browsers), a text input was pretty much the only possible 'standard output' to which a scroll could be directed. Fortunately, the DHTML innerHTML property and the DOM textContent property will now allow us to load a scroll into any can-contain-#PCDATA element, in particular a div or p element, to which the CSS font and color properties unambiguously applies.

#div0 { color: red; font: bold italic 24px; white-space: pre; }
<div id="div0"></div>
document.getElementById("div0").textContent = scrollText;

There's just one little catch in doing this: in order to prevent the collapse of the tt_space substring to a single space, be sure to add a white-space:pre; declaration to your CSS.

Commenter Steeeeve also asks about removing the scroll field's border. A border:0px; style declaration will work for a text box, but a div or p 'field' won't have a border in the first place.

A final point:
The tutorial's concluding subsection asks, "Can I Get A Second Script On The Same Page?" Joe answers No but I say yes - just be careful about your use of function and variable identifiers, and it's all good...

We'll move on to "So, You Want A Dual Image Flip, Huh?", the next Beyond HTML : JavaScript tutorial, in the following entry.


Comments: Post a Comment

<< Home

Powered by Blogger

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