Document Home


Previous Revising the Database Structure
Previous The New Event Record Structure
Previous The New Entry Interface
Previous The Bare-Bones Interface
Samples for this chapter (this file does not include the database modifications discussed in the sections leading up to this one. it is intended
solely to illustrate the javascript discussed in this chapter.)

Starting with Javascript and the Document Object Model



OK, I know I expressed some reservations about the use of javascript a few chapters ago. I still think that those reservations are pertinent, for a number of different reasons. One of the primary among those is that, in response to internet threats such as spyware and web pages that incorporate intrusive scripts, a standard security measure is to limit script execution within the browser. Although the scripts I will be employing here are innocuous, it is quite possible to run afoul of measures intended to protect against such threats.


At the same time, there are certain kinds of things that really have to be done at the client. Although I have been talking about the interface, my initial motivation here for moving into client-side scripts has less to do with the new interface per se than with the modifications I am making to the structure of the database and the number of codes that will be stored in the tables. Specifically, rather than having the user select from a list of twenty or thirty items that could be grouped together, such as the type of circumstances that result in the batter being out or the types of hits, I want the user to be able to select one of those groups first, and then refine their selection from the set of items that are in that group. I could do that without implementing any logic on the client by submitting to the server, but that would entail a slight delay and create a clunky interface, which is precisely what I am trying to avoid. Given that, the incorporation of some logic on the client is warranted, and given that javascript, or more accurately ecmascript, is ubiquitous in virtually all of the modern graphical browsers, that will be the environment in which I will implement that logic. (While there are some differences between browsers in the implementation of javascript, I will attempt to keep this as generic as possible. If I should I run into a statement which is implemented differently in the major environments, I will identify it as such.) In this sub-sub-chapter I will implement a simple validation script that will check to make sure that an event has been chosen in the at bat cell. The introduction that this will provide will serve in good stead when I implement some more interesting things in later chapters.


Before I begin to implement any code, a short introduction into the environment of a modern browser is in order. When the browser receives an html (or xml, but that is a subject for later) document, it reads the document into a set of local objects as the page is drawn. The structure into which these objects are stored is known as the document object model (DOM), and it is these objects on which client-side tools like ecmascript operate, in the absence of specialized client libraries that encapsulate and hide that level from the application logic. (For more detailed discussions of the DOM, see the references in the appropriate section of the links page.) In other words, the DOM provides both a structure through which the elements of a page can be accessed and a way to access those elements (an application programming interface, or api.)


The form of this interface is object-oriented, which from a practical perspective means that an element on the page can be accessed by specifying the series of objects in which the target object exists. This means that it is a good idea to get into the habit of naming certain components of the generated page that I have not previously bothered about naming, at least until the scripts I employ become sufficiently sophisticated as to require the more sophisticated forms of page element access that javascript offers. In the basic page that I generated in the last sub-sub-chapter, for example, I put the at_bat entry widgets within a form. Now, if I want to access the components of that form by name, I have to give the form itself a name.

$$r->print("<form action='/bb_app/league/la-store' name='at_bat' method='post'>");
Once the form is given the name "at_bat", I can access the selected value of the select box widget I named "ab_event" with the string
document.at_bat.ab_event.value
which is straightforward. Now just as perl provides the capability to access unnamed, or anonymous, structures, so does the DOM. The forms in a document are stored in an array, in the order in which they were written in the html. Therefore, in this example, the same value could be referenced as
document.forms[0].ab_event.value
Even though this capability exists, I am not at all sure that I will use it in the development of this system, largely because the scripts incorporated into these pages will be relatively straightforward. But one never knows.


As I mentioned, the simple little validation script that I have developed here simply checks to make sure that a value has been selected from the event check box in the at_bat cell. Validation of input like this is one of the primary uses javascript receives. While the syntax of javascript is different from perl, it is not so different that anyone who has followed along with these chapters could not read a short example like this and understand what is going on, especially as some of the perl modules I have used employ a similar object-oriented interface. As previously with perl, I will not here go into a detailed discussion of the javascript language beyond the manner in which specific statements perform the actions integral to the structures I am implementing. For such a discussion, I would suggest visiting the references I have included in the javascript section on the links page.


In general, scripts are made available to the browser environment by including them within <script></script> tags. Most of the various scripting languages also provide the capability to send external files that contain the script code, but for now I am simply going to embed the code in the html. This is generally done in one of two ways: printing line by line to the request object, as in

			$$r->print("<script language='javascript' type='text/javascript'>");
			$$r->print("function is_code(str)	{");
			$$r->print("var regexp =new RegExp( /[0-9]/);");
			$$r->print("return regexp.test(str);");
			$$r->print("}");
			
			$$r->print("function validentry()	{");
			$$r->print("var _event=document.at_bat.ab_event.value;");
			$$r->print("if (! is_code(_event)){");
			$$r->print("alert('Please Select An Event');");
			$$r->print("return false;}");
			$$r->print("}");
			$$r->print("</script>");
or by assigning what is known as a "here document" to a scalar and printing that back to the request object.
			my $a=<<TEST;
<script language='javascript' type='text/javascript'>
//this function checks to make sure that the entered value includes integers (code) 
function is_code(str)	{
var regexp =new RegExp( /[0-9]/);
return regexp.test(str);
}

// this javascript function checks to make sure that a non-whitespace event has been selected
function validentry()	{
var _event=document.at_bat.ab_event.value;
if (! is_code(_event)){
alert('Please Select An Event');
return false;}
}

</script>
TEST

			$$r->print($a);			


Perl inherited the idea of here documents from unix shell scripting, and as in that environment they provide a way to define a block of statements relevant to an external environment and feed those statements to that environment without having to go through the entire block, escaping the characters that have meaning to the operative interpreter. To "escape" a character means to tell the interpreter to treat that character as only a character, and not to use it in the manner the interpreter normally would. In the javascript above, for example, perl would interpret the curly braces ("{}") as enclosing a block of code. Placing that code in a here document tells perl to ignore all that, and is in that sense a quoting construct.


Each of these methods is subject to its own quirks. The line-by-line method requires careful attention to the fact that the lines being printed are in fact commands in another environment. In the process of printing those lines back to the browser it is very easy to leave something out that will be required at the other end, creating bugs that are difficult to diagnose. On the other hand, definition of a here document in perl requires careful attnetion to the formatting of the included text. Note that the here document in the sample above is flush with the left-hand side of the page. It is that way in the subroutine as well. This error

Can't find string terminator "TEST" anywhere before EOF at BB_APP_INTERFACE.pm line 1714.
was produced because the terminator for the here document (the next to the last line in this snippet, in which the string "TEST" defines the end of the document) was indented. There must also be no spaces between the angle braces ("<<") that define the beginning of the here document and the string that names it.


Now that I have gotten the script back to the browser I can talk about what it does. In short, it just checks to make sure that the string contains an integer, which means that it must be a non-whitespace string. The verification is triggered by the addition of an onclick argument to the definition of the form's submit button.

$$r->print("<center><input type='submit' name='submit' value='Submit_Event' onclick='return validentry()'></center>");
With this addition, submission of the form will be stopped if the argument following the return statement evaluates to "false". Thus the form submission will fail if the validentry() function returns the value "false". In the validentry() function itself
// this javascript function checks to make sure that a non-whitespace event has been selected
function validentry()	{
var _event=document.at_bat.ab_event.value;
if (! is_code(_event)){
alert('Please Select An Event');
return false;}
}
the selected value is stored in the variable _event, and if the returned value from the execution of the is_code() function is not true, pops an alert window prompting for the entry of a valid code and returns the value "false", leading to abortion of the form submission. The is_code() function
function is_code(str)	{
var regexp =new RegExp( /[0-9]/);
return regexp.test(str);
}
takes as string as an argument, defines a regular expression object that looks for integers, and then applies the javascript regular expression test method to that string. Note again that this is a very simple regular expression, just checking for an integer anywhere in the submitted string. In the current context that is sufficient, but I think it is appropriate to point out that limitation. If I wanted to make sure that all three characters in the string were integers, starting with the beginning of the string, I would use the term /^[0-9]{3}/. I will get into such more complex statements as the need arises. Note also that the regular expression object itself is stored as a variable. This is similar to the perl mechanism of storing statement handles to scalars. The syntax and implementation differ, but that is just one of the things with which one has to familiarize oneself.


With this script in place, an attempt to submit a form for which no event has been selected will result in a dialogue that looks like this:




Returning briefly to the issue I raised during my discussion of frames regarding appropriately generated html that for some reason does not display properly, when I first developed this script I had trouble getting the onclick action to fire. I saved the generated source and copied it into my html editor, arachnophilia, to play with it as a static page and started stripping out parts of the page to determine the source of the problem. When that did not reveal anything I manually typed the contents of a very bare-bones page with the script and was moderately surprised when it worked! Investigating further, I was able to track the source of the problem to the two lines displayed in this illustration.



As the illustration indicates, the two snippets are identical. (While the onclick action was inappropriately specified at that point, that error did not affect the triggering of the action. It just meant that a returned value of "false" would not stop the form submission: the alert window should still have been displayed.) At this point, I could copy the non-functional snippet into the working prototype and it would stop working, but once I replaced it with the working version it would start working again. I copied the working version over the corresponding part of the subroutine in BB_APP_INTERFACE, and after restarting the server the action fired appropriately.


So go figure. All I can think is that some part of one of the problem lines had something in it that did not display in either of the editors that I use. I had overwritten the non-working versions by the time I thought of using a hex editor to look at the file contents at a lower level, but that series of events remains a valuable experience. This is obviously a low probablility event, I have been generating html throughout the chapters of this document without anything analogous happening. Obviously, however, the fact that it did happen means that it can happen. The series of events also illustrates the point that one should not assume that problems that emerge as one is implementing something new are necessarily attributable to the new stuff. Clearly, that should be the first thing checked, but one should keep a perspective open on the wider environment.


In the next sub-sub-chapter, I will build on what I have done here to flesh out the data entry interface.