Web Database Applications With Php And Mysql (2nd Edition) [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Web Database Applications With Php And Mysql (2nd Edition) [Electronic resources] - نسخه متنی

David Lane, Hugh E. Williams

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید










9.3 JavaScript and Client-Side Validation






In this section, we introduce
the JavaScript scripting language as a client-side method for
validation and other simple tasks.

JavaScript
isn''t a full-fledged programming language like PHP:
it can''t connect to databases, it offers only
limited interaction with certain system resources, and it
can''t do most tasks a web database application
requires. However, JavaScript is good for interacting with a form and
for controlling the display of data to the user.




Client-side
validation with JavaScript is optional but has benefits, including
faster response to the user than server-side validation, a reduction
in web server load, and a reduction in network traffic. Also, unlike
server-side validation, it can be implemented as interactive
validation where errors are checked as they occur and field-by-field
reporting where error messages are shown individually. However,
validation in the client tier is unreliable: the user can bypass the
validation through design, error, or misconfiguration of their web
browser. For that reason, client-side validation should be used only
to improve speed, reduce load, and add features, and never to replace
server-side validation.




The client-side scripting language we use here is best known as

JavaScript. However, in June 1998, the
European Computer Manufacturers Association (ECMA) agreed to be
responsible for the standard implementations of the scripting
language by Microsoft, Netscape, and Sun. Accordingly, the real name
of the language is now


ECMA-Script,
based on the standard ECMA-262. The most recent version of ECMA-262
is the third edition, dated December 1999. Netscape still use the
name JavaScript, and JavaScript 1.5 is fully compatible with ECMA-262
Version 3.


The standard is available from http://www.ecma-international.org/publications/standards/ECMA-262



Besides validation, there are many other common uses of

JavaScript in web
database applications including:



Simple interaction with form data. For example, JavaScript is often
used to calculate values and display these in an input widget.



Enhancing user interactions by adding dynamic elements to a web page.
Common features include pull-down menus, mouseover changes to the
presentation (rollovers), and dialog boxes.



Customizing the browser and using information from the browser to
enhance presentation.




Most of these techniques are oriented around

events. An
event is an action that can be trapped through
JavaScript code, such as a mouse passing over an object, a window
opening, or a user clicking on a button.


The next section introduces JavaScript through a simple example.
After that, we show you the basics of JavaScript by contrasting and
comparing it with PHP, and then we show you several more examples
including a case study. However, this section isn''t
comprehensive and isn''t aimed as a replacement for
many of the excellent resources that are available; selected
resources are listed in Appendix G.



9.3.1 Introducing JavaScript




Consider the short

JavaScript validation example in Example 9-5.


Example 9-5. A simple JavaScript example to check if a form field is empty



<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Simple JavaScript Example</title>
<script type="text/javascript">
<!-- Hide the script from old browsers
function containsblanks(s)
{
for(var i = 0; i < s.value.length; i++)
{
var c = s.value.charAt(i);
if ((c == '' '') || (c == ''\n'') || (c == ''\t''))
{
alert(''The field must not contain whitespace'');
return false;
}
}
return true;
}
// end hiding -->
</script>
</head>
<body>
<h1>Username Form</h1>
<form onSubmit="return(containsblanks(document.userform.username));"
method="POST" name="userform" action="test.php">
<input type="text" name="username" size=10>
<input type="submit">
</form>
</body>
</html>


This example is designed to check if an optional
username field contains whitespace and, if so, to
show a dialog box containing an error message to the user. The dialog
box is shown in Figure 9-1. The example contains a
mixture of HTML and JavaScript, and almost all the JavaScript is
encapsulated between the <script> and
</script> tags in the
<head> tag of the document.





Figure 9-1. The dialog box produced when whitespace is entered in the username field


The JavaScript function containsBlanks( ) is
called when the user submits the form. The function call is part of
the form element:


<form onSubmit="return(containsblanks(document.userform.username));"
method="post" name="userform" action="test.php">


When the submission event occurs (when the user presses the Submit
button or presses the Enter key while the cursor is in the text
widget) the onSubmit event is triggered. In this
case, the result is that the function containsblanks(
)
is called with one parameter,
document.userform.username. The object
document refers to the document loaded in the
browser window, the userform is the name of the
form itself, and username is the name of the input
widget within the form. The function call itself is wrapped in a
return( ) expression. The overall result of
executing containsblanks( ) is that if the
function returns false, the form
isn''t submitted to the server; if the function
returns true, the HTTP request proceeds as usual.


The function containsblanks( ) works as follows:



A for loop iterates through the characters entered
by the user. The expression s.value.length refers
to the length of the string value entered by the user into the
username widget. The length
property is one of the predefined properties of the
value attribute of the
<input> widget.



Each character in the string entered by the user is assigned to a
character variable c using the expression
s.value.charAt(i) to return the characters in the
value entered by the user. The value attribute of
the widget has an associated method charAt( )
that returns the value of the character at the position
passed as a parameter. For example, if the user enters
test in the widget,
s.value.charAt(0) returns t,
and s.value.charAt(1) returns
e.



The if statement checks whether the current
character is a space, a tab character, or a carriage return. If so,
the alert( ) method is called with an error
string as a parameter. The alert( ) method
presents a dialog box in the browser that shows the error message and
has an OK button, as shown in Figure 9-1. When the
user clicks OK, the function returns false, and
the submission process stops.



If the string doesn''t contain any whitespace, the
function containsblanks( ) returns
true, and the form submits as usual.





HTML comment tags are included inside the
<script> tags and surround the JavaScript
script. This is good practice, because if JavaScript is disabled or
the user has an old browser that knows nothing about scripts, the
comments hide the script from a potentially confused browser. An old
browser happily displays the HTML page as usual. In addition, an old
browser or one that has JavaScript turned off will ignore the
onSubmit event handler in the form
element.



9.3.2 JavaScript and PHP






The syntax of JavaScript is
similar to PHP and to other languages such as C and Java. Table 9-2 compares some of the basic features of PHP and
JavaScript that we used in Example 9-5 and others
that are used later in this chapter. The key differences are that
JavaScript variables aren''t prefixed with a dollar
sign, local variables must be declared in JavaScript, different open
and close script tags are used, and string concatenation in
JavaScript uses a plus sign and PHP uses a period. Other than that,
the languages are very similar when used for basic
tasks.




Table 9-2. The language basics in PHP and JavaScript


Language component




PHP




JavaScript




Open and close script tags



<?php ?>



<script type="text/javascript">
</script> or <% %>




Block statement



{ }



{ }




Multi-line comment



/* hello */



/* hello */




Single-line comment



// hello



// hello




Constant declaration



define("z", 1);



const a = 1;




Variable declaration




Not required




Required for local variables, var a = 0;




Variable assignment



$a = 0;



a = 0;




Assignment shortcut style



$a += 5;



a += 5;




Variable typing




At runtime




At runtime




Statement terminator



;




; or the end-of-line




Equality value testing




Double-equals, ==




Double-equals, ==




Equality type and value testing




Triple-equals, ===




Triple equals, ===




Inequality testing



!=



!=




Strings



"string" ''string''



"string" ''string''




String constants



\n and \t



\n and \t




String concatenation



$a = $b . $c;



$a = $b + $c;




Boolean values



true false



true false




Logical AND



&&



&&




Logical OR



||



||




Logical NOT



!



!



9.3.2.1 Generating output




In PHP, output to the browser is generated using the
print or printf statements, or
by using a template and template methods as discussed in Chapter 7. In JavaScript, there are several different
ways output can be produced including writing output to the browser
window as a document is created, creating dialog boxes, updating
values in form widgets, and creating new windows.


To write output to a window, the writeln( )

method can be used:


<script type="text/javascript">
document.writeln("Hello, world.");
</script>


The document object refers to the document that is
displayed in the browser window, and writeln( )
is a method associated with that document. You can write to a
document only as it''s created, you
can''t use this method to write text to the document
after it''s been rendered in the browser. The basic
objects and methods are discussed later in this section.


In Example 9-5, a dialog box with an OK button is
created with the alert(
)

method. For example, you can pop
up a dialog box when the user clicks on a button:


<form action="test.php">
<input type="button" value="Pop a box" onclick="alert(''Pop!'');">
</form>


The onclick attribute causes the box to appear
when the user clicks on the button.


It''s also possible to create dialog boxes using the
confirm( )
method that displays both an OK
and Cancel button:


<script type="text/javascript">
if (confirm("Are you sure?"))
alert("Great!");
else
alert("What a pity!");
</script>


The confirm( ) method returns
true when the user clicks Ok and
false otherwise.


Another approach to producing output is to write to the browser
window status line. However, this isn''t a very
effective mechanism: the status bar may be hidden or disabled, and
it''s easy to overlook messages displayed at the base
of the window. Yet another approach is to create a new fully-featured
non-dialog browser window, which we discuss later in this chapter.
The final approach is to update values in input widgets, an approach
we use later in our examples.


9.3.2.2 Loops and conditionals






Loops and conditionals are
almost the same in both languages. As discussed in Chapter 2, PHP has the for,
while, foreach, and
do...while loops, and the if
and switch conditionals. JavaScript has the
for, while,
do...while, and for...in loops,
and the if and switch
statements. The continue and
break statements are available in both languages.


The for, while, and
do...while loops are the same in PHP and
JavaScript, with the exception that in JavaScript
it''s possible to declare a variable in a
for loop with the var
statement; an example is shown in Example 9-5.
JavaScript also has the for...in statement which
allows you to iterate through properties of objects, while PHP has
the foreach statement for iterating through
elements in arrays. An example with the for...in
statement is presented later in this section.


9.3.2.3 Functions






Functions
are similar in PHP and JavaScript. Consider the following JavaScript
example:


function bold(string)
{
document.writeln("<b>" + string + "</b>\n");
}


When called with the function call
bold("this is
bold")
, the function prints the string
<b>this is bold</b> as part of the
document. Similarly to PHP, functions are declared with the statement
function, parameters are listed in brackets and
separated by commas, and the function body is surrounded by curly
braces. Functions can optionally return values using the
return statement, which behaves identically in PHP
and JavaScript.


Variables that are declared within a function are local to that
function. Local variables must be declared using the
var statement as in the following example:


function count( )
{
var x=1;
while (x<6)
{
document.writeln(x + " ");
x++;
}
}


Variables that are used or declared outside functions are global
variables. Declaring globals with var is optional:
as in PHP, they can be declared implicitly by assigning values to
them. However, unlike PHP, global variables in JavaScript are
accessible everywhere in the current document; global variables are
not declared in functions using the global
keyword.


9.3.2.4 Debugging JavaScript






JavaScript
has two types of errors that report messages:
load-time

and
run-time errors. Load-time errors are sometimes
reported by the user agent before it runs the JavaScript, and
you''ll be shown a warning box that details the
error, its line number, and the code fragment itself. Run-time errors
occur when a code fragment is running and, again, a warning box is
sometimes displayed with the line number of the code that caused the
error.


The inconsistent nature of error reporting can be annoying: often,
you''ll get no messages at all but the script
won''t run. However, in many browsers (including
Mozilla and Netscape), you can get more detailed error information by
typing javascript: in the Location box and
pressing Enter. The JavaScript console that pops up lists all errors
that have occurred since the browser began running. You can remove
old messages by clicking on the Clear button that''s
shown at the top of the console window; periodically doing this is a
good way to avoid confusion about which errors are applicable to
what.


Errors can also be annoying because they are often platform- or
browser-dependent and change from one release to the next. Complex
JavaScript adds a thicker client to a web database application, and
this may reveal differences between browser applications, browser
versions, and different platforms.


If complex JavaScript is required or desired, make sure
it''s tested on all the popular platforms with the
popular browser products and versions. However, we recommend that
JavaScript be kept simple: complex tasks should be left to PHP
scripts, and you should ensure that user interfaces function
correctly even if JavaScript is faulty or disabled.


9.3.2.5 Objects






Objects
associated with the browser, windows, and the document are accessible
in JavaScript. For example, in Example 9-5, the form
object and its child (an input text widget) are accessed and used.
Historically, the definition of these objects (and the events,
properties, and methods described in the next sections) was part of
the JavaScript standard and they were loosely known as the
Navigator objects
. This has now changed, and
the objects are defined as part of the





Document Object Model
(DOM).


In this section, we informally describe the objects and properties
that are accessible from within JavaScript, and avoid the details of
DOM. However, the complete specification is accessible at http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/.


The window object is the top of the DOM hierarchy,
and it contains the toolbars and menus of the browser, as well as the
document and its sub-components. The hierarchy of the objects that
descend from window is shown in Figure 9-2.





Figure 9-2. The hierarchy of window objects in the DOM


In JavaScript code, the document object can be
referenced using the same notation as in PHP''s
object-oriented model using window.document, or
just document for short (because there is only one
window when you''re not using frames, which we
don''t in this book).


Each of the objects in the hierarchy has
properties and methods, and
creates events. Properties are characteristics
that describe the appearance of the object, while the methods are its
behaviors. Events are actions that the object can act on such as
mouse clicks or key presses. Events are discussed in the next
section, and methods and properties in the following section.
However, selected events, methods, and properties are used in
examples here.


Consider a document that contains a form that has a text input widget
and a submit button:


<form name="custform" method="GET" action="cust.php">
Surname: <input type="text" name="surname">
<br><input type="submit" name="submit">
</form>


The text widget is accessible using the names associated with the
objects in the hierarchy. In this example, the form widget has the
attribute name="custform", and the input widget
has the attribute name="surname". You can
therefore reference the text widget''s value as
document.custform.surname.value. The
value is a property of the text input widget and
it contains the data the user has entered, or it can be assigned a
value to modify the data that''s shown in the widget.


The value could be output when an onchange event
is triggered in the widget itself:


<input type="text" name="surname" 
onchange="alert(''You entered '' + document.custform.surname.value);">


The browser automatically generates an onchange
event when the text in the widget changes; we explain events more
later.


Alternatively, you could output the value when the submission process
itself occurs:


<form name="custform" method="GET" action="cust.php" 
onsubmit="alert(''You entered '' + document.custform.surname.value);">


Another way to access the properties of an object is to access the
DOM element array. For example, the value of the text input widget in
the custform can be referenced as:


document.forms[0].elements[0].value


The notation forms[0] means the first form in the
document, and elements[0] means the first element
of that form. You can iterate through all properties in an object
using the for...in statement that we introduced
previously. For example, to show the names of all elements in the
form, use:


for (o in document.custform) 
string += o + '' '';
alert("Here are the elements: " + string);


The loop assigns each element in document.custform
in turn to the variable o, and then
o is appended to string. If you include this
fragment in a document containing the custform,
you may be surprised that it outputs not just the surname widget and
the submit button, but more than 50 properties. Some of these are
discussed in the next section.


Some browsers are fussier than others. For example,
Microsoft''s Internet Explorer complains when you
reference an object before it''s defined. This means
that you can''t reference a form earlier in your HTML
source than where the form is actually declared.
You''ll find that these kinds of issues make
developing complex or portable code difficult. As
we''ve already discussed, we recommend you use
JavaScript for simple tasks and leave the complex ones to PHP on the
server side.


In JavaScript, there are also several other pre-defined objects.
These include core objects such as Array,
RegExp, Date, and
Math that are discussed in detail in the
Core JavaScript Guide available from http://devedge.netscape.com/library/manuals/.



9.3.2.6 Events







Events
are triggered by both the user agent (usually a web browser), and the
user working with the document and browser. These events are useful
triggers for JavaScript actions. For example, a function might be
called as a page loads, when the user presses the submit button, when
a form field changes, or when the mouse passes over a document
element. Examples using many of these events are included in later
examples in this chapter.


The key events that can be trapped and handled by JavaScript are as
follows:




onblur





When a user removes focus from form elements or a window. This occurs
when the user presses the Tab key to move to the next widget, clicks
on another widget or window, or carries out some other action that
takes the focus away from the current window or widget.





onchange





When a select, text, or textarea input loses focus and has been
modified since it gained focus.





onclick





When a pointing device (usually a left mouse button) clicks on an
area, button, checkbox, hypertext link, radio button, reset, or
submit.





onfocus





When a user brings focus to form elements or a window, normally by
clicking in it.





onload





When a user agent finishes loading a window (or all frames in a
frameset).





onmouseout





When the pointing device moves out from an element, area, or
hypertext link.





onmouseover





When the pointing device moves over an element, area, or hypertext
link.





onreset





When a form is reset.





onsubmit





When a form is submitted.





onunload





When the user exits a page, that is, when the user agent unloads the
document from the window. For example, this happens when a new page
is loaded, a browser window or tab is closed, or the browser program
ends.





We have omitted other events related to key presses and text
selection, as well as other types of mouse clicks and movements.
These are detailed in the HTML 4.01 documentation at http://www.w3.org/TR/html4/interact/scriptsl.
and in the DOM documentation listed in the previous section.


9.3.2.7 Methods and properties






The window, document, form, and
input element objects have properties and methods that are commonly
accessed and used in validation tasks. This section lists selected
methods and properties, and examples later in this chapter show many
of these used in scripts. Images, tables, the document body, document
styles, and frames also have their own methods and properties, but we
don''t discuss these here. The complete list of
objects, methods, and properties can be found at http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/ecma-script-bindingl.


The


navigator object
is outside of the window hierarchy we showed in Figure 9-2 and the standards. However, it is useful
because it describes the browser environment. Its properties include:




platform





The operating system.





userAgent





The same information as sent in the HTTP request that includes the
user agent name and version.





The window object properties and methods include:




location.href





The URL in the location box.





name





The window''s name. Can be used to retrieve or set
the window name. For example, window.name =
"Hello!
" sets the title to Hello!.





locationbar.visible





Determines whether the location bar is visible. It can be set to
true or false, making the
location bar visible or hidden respectively.





menubar.visible





Determines whether the menu bar is visible. It can be set to
true or false, making the menu
bar visible or hidden respectively.





personalbar.visible





Determines whether the personal or directories bar is visible. It can
be set to true or false, making
the personal bar visible or hidden respectively.





scrollbars.visible





Determines whether the horizontal and vertical scroll bars are
visible. It can be set to true or
false, making the scroll bars visible or hidden
respectively.





statusbar.visible





Determines whether the status bar is visible. It can be set to
true or false, making the
status bar visible or hidden respectively.





toolbar.visible





Determines whether the toolbar is visible. It can be set to
true or false, making the
toolbar visible or hidden respectively. It can be set or unset only
before the window is opened.





status





The text displayed in the status bar at the base of window. This can
be set to display a message to the user.





alert( )





Shows a dialog box with an OK button, and takes text as a parameter.





back( )





Causes the user agent to return to the previous resource in its
history list. This has the same effect as pressing the Back button in
the web browser.





close( )





Closes the current window.





confirm( )





Shows a dialog box with OK and Cancel buttons, and takes text as a
parameter. Returns true when the user presses OK
and false otherwise.





forward( )





Causes the user agent to go forward to the next resource in its
history list. This has the same effect as pressing the Forward button
in the web browser.





open( )





Opens a new window, taking a URL, name, and features as parameters.





print( )





Sends the contents of the window to a printer.





prompt( )





Shows a dialog box with an input widget and OK and Cancel buttons.
Takes a text question to display, and optional default text to
display in the input widget. Returns true when the
user presses OK and false otherwise.





The document object properties and methods include:




lastModified





The date the resource was last modified.





title





The text contained in the <title> tag of the
document.





URL





The URL of the current document.





write( ) and writeln( )





Writes text to the current document during its creation. The latter
adds a carriage return character to the string.





The form objects in a document include the following properties and
methods:




name





The value of the name attribute.





action





The value of the action attribute.





method





The value of the method attribute
(GET or POST).





submit( )





Sends the form to the server.





reset( )





Clears all user-entered input from the form. If the form was shown
with pre-filled values, it is reset to those values. If the form was
initially empty, it is reset to empty.





The form elements select, textarea, input, and button have common
methods and properties that include:







type





The type of input as defined by the type attribute in the form
element.





value





The value contained or selected in the form element.





value.length





The length of the value contained or selected in the form element.





name





The value of the name attribute in the form element.





focus( )





Brings the focus to the form element (not used with button elements).





blur( )





Removes the focus from the form element (not used with button
elements).





select( )





Selects (usually by highlighting) the text in an input or textarea
element (not used with select or button elements).





value.charAt( )





Returns the character in the value at the position of the integer
parameter. For example, value.charAt(0) returns
the first character in the value.






9.3.3 JavaScript Examples






The
short examples in this section implement simple, common, and useful
JavaScript web database application features that use the techniques
we have discussed so far. These include:



Checking if two passwords are the same



Mouse rollovers, where an image is changed to highlight an option as
the mouse cursor passes over it



Calculating and updating form fields based on user changes to data



Interacting with the web browser and windows to trigger events and
manipulate presentation



Detecting the browser application and version



Drop-down menus that load a new URL into the current window



9.3.3.1 A password form validation function




Example 9-6

is an example of JavaScript
validation that checks whether a password is the same when the user
enters it twice. The validation is interactive: an
onchange event is trapped for the two password
widgets, formPassword1 and
formPassword2, and the function thesame(
)
is called whenever the user changes the data in a widget
and then leaves it. The error reporting is field-by-field.


Example 9-6. Using JavaScript for interactive validation of password fields



<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.0 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Password Validation</title>
<script type="text/javascript">
<!-- Hide the script
function thesame(value1, value2)
{
if (((value1 != null) || (value1 != "))
&& value2 != " && value1 != value2)
{
alert("The passwords must be identical.");
return (false);
}
return (true);
}
// end hiding -->
</script>
</head>
<body>
<h1>Username Form</h1>
<form method="post" action="test.php" name="userForm">
<br>Username: <input type="text" name="userName" size=10>
<br>Password:
<input type="password" name="formPassword1" size=10
onchange="thesame(document.userForm.formPassword1.value,
document.userForm.formPassword2.value);">
<br>Re-enter password:
<input type="password" name="formPassword2" size=10
onchange="thesame(document.userForm.formPassword2.value,
document.userForm.formPassword1.value);">
<br><input type="submit" value="SUBMIT">
</form>
</body>
</html>


The function thesame( ) checks if the current
widget contains data. If it does, and the other password widget also
contains data, the data in the two widgets is compared. If the data
in the widgets is different, an error message is shown to the user.
It''s necessary to test whether both widgets actually
contain data in interactive validation; without this check, the
function annoyingly displays an error before the user has the
opportunity to enter data into both widgets.


9.3.3.2 Rollover presentation with mouseover events




Example 9-7

shows a basic implementation of the
common rollover feature used in many web applications.


Example 9-7. mouseover example with JavaScript



<!DOCTYPE HTML PUBLIC 
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>MouseOver Example</title>
</head>
<body bgcolor="#ffffff">
<a href=" onmouseout="cart.src=''/image/library/english/10164_/
image/library/english/10164_/image/library/english/10164_/image/
library/english/10164_cart_off.jpg''"
onmouseover="cart.src=''/image/library/english/10164_/image/
library/english/10164_cart_on.jpg''">
<img src="/image/library/english/10164_/image/library/english/
10164_/image/library/english/10164_/image/library/english/
10164_cart_off.jpg" border=0 name="cart" ></a>
</body>
</html>


When the page is first loaded, an un-highlighted image of a shopping
cart is shown; the image is used in the front page of the winestore
in Chapter 16. The image is loaded with the HTML
fragment:


<img src="/image/library/english/10164_/image/library/english/10164_/
image/library/english/10164_/image/library/english/10164_cart_off.jpg"
border=0 name="cart">


The only difference to the usual approach of loading images is that
the <img> tag has the attribute
name="cart".


If the mouse passes over the cart image, an
onmouseover event is triggered, and the JavaScript
action carried out is:


onmouseover="cart.src=''/image/library/english/10164_/
image/library/english/10164_cart_on.jpg''"


The event handler changes the value of the src
attribute of the <img> tag with the
name="cart". The result is that a new highlighted
image is loaded to replace the un-highlighted image. In the case of
our winestore, a shopping cart with a blue foreground is shown.


When the mouse leaves the image region, the
onmouseout event is generated and handled with the
following JavaScript fragment:


onmouseout="cart.src=''/image/library/english/10164_/
image/library/english/10164_/image/library/english/10164_/
image/library/english/10164_cart_off.jpg''"


This restores the original image. The impression to the user is that
the cart element is highlighted as the user focuses on the element.


Rollovers are straightforward to develop and the approach
we''ve shown you works in all graphical browsers. You
can even use the same technique to highlight menu options, and to
produce pop-up and pull-down menus.


9.3.3.3 Prefilling form data with JavaScript calculations





Another common use
of JavaScript is to pre-fill a form with data from a calculation.
Example 9-8 shows how data can be managed and
updated in a shopping cart.


When the user changes the quantity of a wine he intends to purchase,
an onchange event is generated. This change event
is handled by the update(
)

function, which modifies the
value attribute of the total
widget, showing the new total cost to the user. The new value shown
to the user is calculated by multiplying together the
quantity.value and the
unit.value. Of course, as in all web database
applications, the values and mathematics should be rechecked at the
server when the form is submitted to the server.


Example 9-8. Using JavaScript to dynamically update values of form widgets



<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Dynamic Form Update Example</title>
</head>
<body>
<h1>Your Shopping Cart</h1>
<form method="get" action="test.php">
<table border="0" width="100%" cellpadding="0" cellspacing="5">
<tr>
<td>Quantity </td>
<td>Wine</td>
<td>Unit Price</td>
<td>Total</td>
</tr>
<tr>
<td><input type="text" name="quantity" value="1" size=3
onchange="total.value = unit.value * quantity.value;">
<td>1997 Anderson and Sons Wines Belcombe Grenache</td>
<td>$<input type="text" value="17.29" name="unit" readonly></td>
<td>$<input type="text" value="17.29" name="total"
align="right" readonly></td>
</tr>
</table>
<input type="submit" value="Purchase Wines">
</form>
</body>
</html>


9.3.3.4 Interacting with the web browser




Example 9-9

shows four examples of handlers for
buttons that use the methods defined for the
window object. The method window.close(
)
closes the focused window, window.print(
)
shows the print dialog window, window.back(
)
goes back one page, and window.open(
)
opens a new browser window.


Example 9-9. Closing and opening windows with JavaScript, printing the current page, and adding a Back button to a form



<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Playing with the Browser and Windows</title>
</head>
<body>
<h1>Playing with the Browser and Windows</h1>
<form action="example.9-6.php">
<input type="button" value="Close Window" onClick="window.close( );">
<br><input type="button" value="Print Window" onClick="window.print( );">
<br><input type="button" value="Go Back" onclick="window.back( );">
<br><input type="button" value="Visit the book site"
onClick="window.open(''http://www.webdatabasebook.com/'',''BookSite'',
''toolbar=yes,location=yes,menubar=yes,directories=yes,scrollbars=yes,
resizable=yes'');">
</form>
</body>
</html>


Only window.open( ) is complex. The first
parameter is the URL to request in the new window, the second is a
title, and the third is a set of properties of the new window.
Without the list of properties that are included, the default new
window has no Location box, no toolbars, no scrollbars, and
can''t be resized.


9.3.3.5 Which browser is the user using?





As discussed previously, even
simple JavaScript sometimes highlights annoying differences in the
way browsers support standard features. Indeed, even different
versions of the same browsers support different JavaScript features
from the same version of the standard.


Example 9-10 shows how the browser application name
and version can be detected with both JavaScript and PHP. If a
JavaScript script requires customization for a particular product,
if statements can carry out actions in different
ways. Another common approach in JavaScript-intensive web database
applications is to write two sites: one that uses Internet Explorer
JavaScript (known as Jscript), and another that uses Netscape
Navigator or Mozilla JavaScript. However, as we recommended earlier,
complex JavaScript is often best avoided in favor of server-side
scripts.


Example 9-10. Which browser is the user using?



<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<title>Playing with the Browser and Windows</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body>
<script type="text/javascript">
<!-- Hide the script from old browsers
alert("You are using " + navigator.userAgent);
// end the hiding -->
</script>
This page should pop up a box if you have a JavaScript-capable and enabled
browser.
<br>But, using PHP, we can tell you that you''re using the
<?php print $_SERVER["HTTP_USER_AGENT"]; ?> browser.
</body>
</html>


9.3.3.6 Drop-down menus





A common use of JavaScript is to
automatically load a new page when a user selects a menu option from
a drop-down list. Example 9-11 shows how to do this
using a select widget and its properties. The JavaScript in the body
of the document is straightforward: when the user changes their
selection of menu item, an onchange event is
triggered, and the loadNewPage( ) function is
called.


Example 9-11. Drop-down menus that load a new URL



<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Menu Example</title>
<script type="text/javascript">
<!--
function loadNewPage( )
{
var listItem = document.menuForm.newPage.selectedIndex;
var newPage = document.menuForm.newPage.options[listItem].value;
location.href = do you want to go now?
<br><form method="GET" action="menusl" name="menuForm">
<select name="newPage" onchange="loadNewPage( );">
<option value="menusl">This page
<option value="http://www.webdatabasebook.com/">The book web site
<option value="http://www.oreilly.com/">O''Reilly and Associates
<option value="http://www.hughwilliams.com/">Hugh''s homepage
<option value="http://www.mds.rmit.edu.au/~dave/">Dave''s homepage
</select>
</form>
</body>
</html>


The form in Example 9-11 has a
name attribute of menuForm and
the select list has a name attribute of
newPage. Therefore, the list is referenced as
document.menuForm.newPage. The
loadNewPage( ) function references the list to
load the new page in three steps:



The local variable listItem is assigned the
ordinal number of the selected value from the list. To discover which
item is selected, the selectedIndex property of
the newPage <select> is
inspected. For example, if the first item is selected then the value
is 0.



The value of the selected item (which contains the
new URL) is determined by accessing the options
array property of the list and retrieving the value of the element
listItem. This value is stored in the local
variable newPage. For example, if the first item
in the list is selected listItem is
0, the value is the URL
http://www.webdatabasebook.com/,
and newPage is set to that value.



To load the new URL in the current window, the
location.href property is set to
newPage. This causes the new document to
load.




9.3.4 Case Study: A Generic JavaScript Validation Function






The example in this
section shows how JavaScript can be used as a validation tool across
multiple HTML pages or templates. An example of errors produced by
applying the techniques described in this section to customer
validation is shown in Figure 9-3. We show you the
JavaScript code, the PEAR IT template, and the PHP code in this
section.





Figure 9-3. A dialog box showing an error produced by the JavaScript validation function


9.3.4.1 The JavaScript validation script




The general-purpose verify( ) function for
post-validation and field-by-field error reporting is shown in Example 9-12. The code is stored in the file
/image/library/english/10164_/image/library/english/10164_example.9-12.js and is designed to be added to a
template, such as the phonebook template developed in Chapter 8. Later in this section, we show you how to
add it to a customer details template that has diverse validation
needs.


By storing JavaScript code in its own file, it can be reused across
multiple HTML pages or templates. To do this, instead of including
code between the <script> and
</script> tags, you add a
src attribute to the
<script> element that specifies the file
that contains the JavaScript code. For example, to load the code in
Example 9-12 into a document or template, you use:


<script type="text/javascript" src="/image/library/english/10164_/
image/library/english/10164_example.9-12.js">
</script>


This approach saves cutting and pasting the code into more than one
file, and avoids the need to update several pages when the script
changes. It also has the additional advantage of reducing network
traffic if the user has a web browser cache, because a copy of the
script can be reused in multiple HTML pages without retrieving it
again from the web server.


Example 9-12. A general-purpose JavaScript form validation function



// A utility function that returns true if a string contains only
// whitespace characters.
function isblank(e)
{
if (e.value == null || e.value == ")
return true;
for(var i = 0; i < e.value.length; i++)
{
var c = e.value.charAt(i);
if ((c != '' '') &&
(c != ''\n'') &&
(c != ''\t''))
return false;
}
return true;
}
// Checks if an optional field is blank
function checkblank(e)
{
if (isblank(e))
{
alert("The field " + e.description + " must be filled in.");
return false;
}
return true;
}
// Checks if a field is numeric.
// If the optional min property is set, it checks it is greater than
// its value
// If the optional max property is set, it checks it is less than
// its value
function checknumber(e)
{
var v = parseFloat(e.value);
if (isNaN(v))
{
alert("The field " + e.description + " must be a number");
return false;
}
if ((e.minNumber != null) && (v < e.minNumber))
{
alert("The field " + e.description +
" must be greater than or equal to " + e.minNumber);
return false;
}
if (e.maxNumber != null && v > e.maxNumber)
{
alert("The field " + e.description +
" must be less than or equal to " + e.maxNumber);
return false;
}
return true;
}
// Checks if a field looks like a date in the 99/99/9999 format
function checkdate(e)
{
var slashCount = 0;
if (e.value.length != 10)
{
alert(" The field " + e.description +
" must have the format 99/99/9999" +
" and be 10 characters in length");
return false;
}
for(var j = 0; j < e.value.length; j++)
{
var c = e.value.charAt(j);
if ((c == ''/''))
slashCount++;
if (c != ''/'' && (c < ''0'' || c > ''9''))
{
alert(" The field " + e.description +
" can contain only numbers and forward-slashes");
return false;
}
}
if (slashCount != 2)
{
alert(" The field " + e.description +
" must have the format 99/99/9999");
return false;
}
return true;
}
// Checks if a field contains any whitespace
function checkwhitespace(e)
{
var seenAt = false;
for(var j = 0; j < e.value.length; j++)
{
var c = e.value.charAt(j);
if ((c == '' '') || (c == ''\n'') || (c == ''\t''))
{
alert("The field " + e.description +
" must not contain whitespace");
return false;
}
}
return true;
}
// Now check for fields that are supposed to be emails.
// Only checks that there''s one @ symbol and no whitespace
function checkemail(e)
{
var seenAt = false;
for(var j = 0; j < e.value.length; j++)
{
var c = e.value.charAt(j);
if ((c == '' '') || (c == ''\n'') || (c == ''\t''))
{
alert("The field " + e.description +
" must not contain whitespace");
return false;
}
if ((c == ''@'') && (seenAt == true))
{
alert("The field " + e.description + " must contain only one @");
return false;
}
if ((c == ''@''))
seenAt = true;
}
if (seenAt == false)
{
alert("The field " + e.description + " must contain one @");
return false;
}
return true;
}
// This is the function that performs <form> validation.
// It is invoked from the onSubmit( ) event handler.
// The handler should return whatever value this function
// returns.
function verify(f)
{
// Loop through the elements of the form, looking for all
// text and textarea elements. Report errors using a post validation,
// field-by-field approach
for(var i = 0; i < f.length; i++)
{
var e = f.elements[i];
if (((e.type == "text") || (e.type == "textarea")))
{
// first check if the field is empty and shouldn''t be
if (!e.isOptional && !checkblank(e))
return false;
// Now check for fields that are supposed to be numeric.
if (!isblank(e) && e.isNumeric && !checknumber(e))
return false;
// Now check for fields that are supposed to be dates
if (!isblank(e) && e.isDate && !checkdate(e))
return false;
// Now check for fields that are supposed to be emails
if (!isblank(e) && e.isEmail && !checkemail(e))
return false;
// Now check for fields that are supposed
// not to have whitespace
if (!isblank(e) && e.hasNospaces && !checkwhitespace(e))
return false;
} // if (type is text or textarea)
} // for each character in field
// There were no errors if we got this far
return true;
}


Example 9-12 contains several functions and the main
function is the last one in the file, verify( ).
The verify( ) function is called when a form is
submitted, and it expects the form object to be passed to it as a
parameter. The function iterates through the elements in the form and
carries out validation checks on each field, depending on what
properties you set for that field. If any check fails, the function
returns false. If all checks succeed, the function
returns true. We show you how to call the function
and set the element properties later.


The first fragment of the verify( ) function is
as follows:


function verify(f)
{
// Loop through the elements of the form, looking for all
// text and textarea elements. Report errors using a post validation,
// field-by-field approach
for(var i = 0; i < f.length; i++)
{
var e = f.elements[i];


A form object f is expected as a parameter. The
for loop iterates through each element object in
f. The first element is numbered 0 and the total
elements in the form is stored in the property
f.length. As discussed previously, the element
objects are stored in the elements array and so,
for example, f.elements[0] is the object
representation of the first element in f. For
compactness in the code, with each iteration of the loop, we assign
the current element object to the local variable
e.


The next fragment in verify( ) checks whether
the current input element is of type text or textarea:


if (((e.type == "text") || (e.type == "textarea")))
{


We''ve only written validation functions for these
types of element, and we leave it to you to extend this further to
meet your needs.


The remainder of the verify( ) function tests
different properties of the current element and calls functions to
validate it. For example, the following fragment tests if the element
contains a value (that is, it''s not blank), if the
isNumeric property is set, and if the value is not
a number:


// Now check for fields that are supposed to be numeric.
if (!isblank(e) && e.isNumeric && !checknumber(e))
return false;


The result of this check is that if the element
isn''t blank and is supposed to be numeric and
isn''t a number, the function returns
false. In the same way as PHP''s
short-circuit evaluation discussed in Chapter 2, the second and subsequent tests in the
if expression are only carried out if all
preceding tests are true. The isblank( ) and
checknumber( ) functions are validation
functions in Example 9-12, and the
isNumeric property is a user defined property that
we discuss later.


There are several functions in Example 9-12 that each
begin with the prefix check. In addition to
testing if a mandatory field is blank and if a field is numeric,
these check whether mandatory fields have data in them, dates are in
a reasonable format, email addresses look plausible, and whether
there''s whitespace within a value. As an example, we
discuss the checkdate( ) function next; we
don''t discuss the others in detail but they use the
same ideas and validation steps.


The checkdate( ) functions perform very simple
date format checking: it tests if a date has the format
99/99/9999 where 9 is a digit.
More explicitly, it checks that the value is exactly 10 characters in
length, contains only forward slashes and digits, and has only two
forward slashes. It doesn''t check the ordering of
the characters, nor the validity of the date by the calendar.
It''s therefore a simple first step in validation: if
the check succeeds, there''s more chance
it''ll pass the more detailed server-side validation
that occurs after the form is submitted. The checkdate(
)
function returns true if validation
succeeds and false otherwise.


The checkdate( ) function begins as follows:


// Checks if a field looks like a date in the 99/99/9999 format
function checkdate(e)
{
var slashCount = 0;
if (e.value.length != 10)
{
alert(" The field " + e.description +
" must have the format 99/99/9999" +
" and be 10 characters in length");
return false;
}


It expects a form element e as a parameter. The
local variable slashCount is used later to count
the number of forward slashes. The first test checks if the value is
ten characters in length and, if not, it shows an error dialog and
the function returns false. The
description property of the element is set before
the verify( ) function is called and we show you
this later.


The next fragment is as follows:


  for(var j = 0; j < e.value.length; j++)
{
var c = e.value.charAt(j);


The for loop iterates through each character of
the value in the element; the first element is 0 and the last is
determined from the property e.value.length. For
compactness in the later code, we store the current character in the
local variable c by retrieving is using the
built-in charAt( ) method discussed previously.


The body of the loop has two straightforward steps. First, if the
current character is a forward slash, we increment the counter:


if ((c == ''/''))
slashCount++;


Second, if the current character isn''t a forward
slash and isn''t a digit we pop up an error dialog
and the function returns false:


  if (c != ''/'' && (c < ''0'' || c > ''9''))
{
alert(" The field " + e.description +
" can contain only numbers and forward-slashes");
return false;
}
}


If the execution of the function makes it to the next fragment only
digits and forward slashes have been encountered in the value. Now,
we check whether there were two forward slashes:


  if (slashCount != 2)
{
alert(" The field " + e.description +
" must have the format 99/99/9999");
return false;
}
return true;
}


If the check fails, we pop up an error dialog and return
false. If all checks have succeeded the value
looks like a date and the function returns true.


9.3.4.2 Using the JavaScript validation function




To use the verify( ) function, you call it from
the onsubmit handler of a form. For example,
suppose you have authored the customer details input form
that''s shown in Figure 9-4.





Figure 9-4. A customer form with JavaScript validation


The form requires users to provide a first name, surname, address,
email address, date of birth, and salary. For this form, the
onsubmit handler that''s used is
as follows:


<form action="test.php" method="post" name="custform"
onsubmit="document.custform.firstname.hasNospaces = true;
document.custform.firstname.description = ''First Name'';
document.custform.surname.description = ''Surname'';
document.custform.address.description = ''Address'';
document.custform.email.description = ''Email'';
document.custform.email.isEmail = true;
document.custform.dob.isDate = true;
document.custform.dob.description = ''Date of Birth (99/99/9999)'';
document.custform.salary.description = ''Salary'';
document.custform.salary.isNumeric = true;
document.custform.salary.minNumber = 1;
document.custform.salary.maxNumber = 1000000;
document.custform.salary.hasNospaces = true;
return verify(document.custform);">


This code fragment creates and sets properties for each form element.
These are properties that we''ve created (and not
part of JavaScript itself), and each is used by some part of our
verify( ) function. For example, when validation
fails, the validation functions show error messages that inform the
user which field contains the error. To pass this string to the
validation function, we create a description
property for all elements that are validated. For instance, the
fragment:


document.custform.email.description = ''Email'';


sets the description property of the email input
element to ''Email''. As shown in the previous
section, this description is displayed in a dialog box when an error
occurs.


To control validation, you set a property that triggers a validation
function in the verify( ) function. For example,
if you want an element to be validated using the checkdate(
)
function we described previously, you set the
isDate property to be true:


document.custform.dob.isDate = true;


The verify( ) function inspects this property
and, because it''s true, it calls
the checkdate( ) function to validate the
dob field.


The other properties we''ve set up can be used to
trigger other types of validation. You can set are
isEmail (for an email address),
hasNoSpaces (if an element should not contain
whitespace), isNumeric (for integers),
minNumber (a minimum value for an
isNumeric element), maxNumber
(a maximum value for an isNumeric element), and
isOptional (for an element that can be left
blank).


9.3.4.3 The PHP and template components




To complete our JavaScript validation case study, Example 9-13 and
Example 9-14 show the PHP script and
template respectively that create the customer details form.


Example 8-7 (which displays the phonebook form) with three
differences. The first is that it displays several more elements than
the phonebook script. The second is that it sets a new
SUBMITACTION placeholder in the template to the
JavaScript code fragment discussed in the previous section. The final
difference is that it also sets the name of the form into a new
placeholder, FORMNAME.


Example 9-13. The PHP script to produce the customer details form



<?php
require ''db.inc'';
require_once "HTML/Template/ITX.php";
$template = new HTML_Template_ITX("./templates");
$template->loadTemplatefile("example.9-11.tpl", true, true);
$template->setVariable("MESSAGE",
"Please fill in the details below to join");
$template->setVariable("SUBMITVALUE", "Join Now!");
$template->setVariable("FORMNAME", "custform");
$template->setVariable("SUBMITACTION", "
document.custform.firstname.hasNospaces = true;
document.custform.firstname.description = ''First Name'';
document.custform.surname.description = ''Surname'';
document.custform.address.description = ''Address'';
document.custform.email.description = ''Email'';
document.custform.email.isEmail = true;
document.custform.dob.isDate = true;
document.custform.dob.description = ''Date of Birth (99/99/9999)'';
document.custform.salary.description = ''Salary'';
document.custform.salary.isNumeric = true;
document.custform.salary.minNumber = 1;
document.custform.salary.maxNumber = 1000000;
document.custform.salary.hasNospaces = true;
return verify(document.custform);");
$template->setCurrentBlock("mandatoryinput");
$template->setVariable("MINPUTTEXT", "First name");
$template->setVariable("MINPUTNAME", "firstname");
$template->setVariable("MINPUTVALUE", ");
$template->setVariable("MINPUTSIZE", 50);
$template->parseCurrentBlock("mandatoryinput");
$template->setCurrentBlock("mandatoryinput");
$template->setVariable("MINPUTTEXT", "Surname");
$template->setVariable("MINPUTNAME", "surname");
$template->setVariable("MINPUTVALUE", ");
$template->setVariable("MINPUTSIZE", 50);
$template->parseCurrentBlock("mandatoryinput");
$template->setCurrentBlock("mandatoryinput");
$template->setVariable("MINPUTTEXT", "Address");
$template->setVariable("MINPUTNAME", "address");
$template->setVariable("MINPUTVALUE", ");
$template->setVariable("MINPUTSIZE", 50);
$template->parseCurrentBlock("mandatoryinput");
$template->setCurrentBlock("mandatoryinput");
$template->setVariable("MINPUTTEXT", "Date of Birth (dd/mm/yyyy)");
$template->setVariable("MINPUTNAME", "dob");
$template->setVariable("MINPUTVALUE", ");
$template->setVariable("MINPUTSIZE", 50);
$template->parseCurrentBlock("mandatoryinput");
$template->setCurrentBlock("mandatoryinput");
$template->setVariable("MINPUTTEXT", "Email");
$template->setVariable("MINPUTNAME", "email");
$template->setVariable("MINPUTVALUE", ");
$template->setVariable("MINPUTSIZE", 30);
$template->parseCurrentBlock("mandatoryinput");
$template->setCurrentBlock("mandatoryinput");
$template->setVariable("MINPUTTEXT", "Annual salary (whole dollars)");
$template->setVariable("MINPUTNAME", "salary");
$template->setVariable("MINPUTVALUE", ");
$template->setVariable("MINPUTSIZE", 6);
$template->parseCurrentBlock("mandatoryinput");
$template->parseCurrentBlock( );
$template->show( );
?>


Example 9-14 is almost identical to the template in
Example 8-8.


Example 9-14. The template used to produce the customer form






<!DOCTYPE HTML PUBLIC
"-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html401/loose.dtd">
<html>
<head>
<script type="text/javascript" src="/image/library/english/10164_/
image/library/english/10164_example.9-12.js">
</script>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Customer Details</title>
</head>
<body bgcolor="white">
<form name="{FORMNAME}" method="post" action="test.php"
onsubmit="{SUBMITACTION}">
<h1>Customer Details</h1>
<h2>{MESSAGE}.
Fields shown in <font color="red">red</font> are mandatory.</h2>
<table>
<!-- BEGIN mandatoryinput -->
<tr>
<td><font color="red">{MINPUTTEXT}:</font></td>
<td>
<input type="text" name="{MINPUTNAME}" value="{MINPUTVALUE}"
size={MINPUTSIZE}>
</td>
</tr>
<!-- END mandatoryinput -->
<tr>
<td><input type="submit" value="{SUBMITVALUE}"></td>
</tr>
</table>
</form>
</body>
</html>


The differences are that the JavaScript code from Example 9-12 is included using the src
attribute (as discussed at the beginning of this case study), and
that the FORMNAME and
SUBMITACTION placeholders have been added to the
form element. The FORMNAME is the name of the
form, and the SUBMITACTION supports the
onsubmit function call.



/ 176