F. The example scriptsIn order to gain a real understanding of the preparation phase, let's discuss the purpose and user interaction of my example scripts, and distill high-level decisions from them. Below you'll find descriptions of the preparations I made for each of the example scripts. I start by defining the purpose, user actions, and the feedback on those actions. Then we'll take a quick look at script knowledge (what data does the script require in order to function) and maintenance considerations.
Textarea Maxlength
HTML structureHere, as in a few other scripts, the script knowledge and maintenance requirements can be combined. Every textarea that has a maximum length should get a custom attribute maxlength. The presence of this hook alerts the script to the fact that it should check this textarea, and its value is the upper limit of user input. In addition, this attribute is easy to change even for newbie Webmasters. Example: <textarea maxlength="300"></textarea> Script structureWhen the page is initialized, the script goes through all textareas and sees whether they have a maximum length. If they do, it sets an event handler. When the event takes place, the script checks whether the user's text exceeds the limit. If it does, the script changes the style of the element that shows the current length of the text. In order to do this, the textarea must somehow be related to this element: After it finds out which textarea is currently being edited, the script should be able to find the element that shows the current length. We already discussed the technical nuts and bolts in 4C. Usable Forms
HTML structureAs with the previous script, the script knowledge and maintenance requirements call for clear definitions in the HTML itself. Eventually the form would be modified by the bank's internal Web developers, and their JavaScript knowledge was insufficient to add complicated script structures every time new form fields were added. I created a simple, intuitive system to define which form fields should be shown in which circumstances. I decided to give a rel attribute with the same value to each element that triggers a certain form change, and to each tag that contains form fields that should appear. Example: <tr> <td>[label]</td> <td><input type="checkbox" name="country_other" rel="othercountry"> Other than The Netherlands</td> </tr> <tr rel="othercountry"> <td>[label]</td> <td><input name="other_country" /></td> </tr> This allows Webmasters to easily add or change relations, and allows the script to find related elements. Besides, the existence of the rel attribute serves as a hook. Script structureWhen the script is initialized, it removes all container elements that have a rel attribute. If the user clicks on form elements with a rel attribute, it returns the containers with the same rel value to their original position in the document, or removes them again. We'll study Usable Forms's associative arrays in 8K. Form Validation
HTML structureForm Validation needs an HTML attribute that serves as a hook, contains validation information, and can be updated by a newbie Webmaster: <input name="phone" validation="required numeric" /> As we discussed in 4B, I could also have used class as a hook for this specific script. Script structureSince I wanted Webmasters with JavaScript knowledge to be able to add new validation definitions, the script structure should make it easy to add new bits of script. Therefore I decided to treat the values of the validation attributes as keys to an associative array (we'll discuss those in 5K). If the script finds the value "required", it looks up the function it should execute to handle this bit of validation, and then it does the same with the value "numeric": [Form Validation, lines 9, 12, 15-32 (condensed), and 47-49 (condensed)] validationFunctions["required"] = isRequired; validationFunctions["numeric"] = isnumeric; function isRequired(obj) { // check } function isnumeric(obj) { // check } If the Webmaster wants to add a validation function, he can write the function, and add its name to the validationFunctions associative array and to the validation attribute of the relevant form fields: <input name="phone" validation="required numeric mustBeMobile" /> validationFunctions["mustBeMobile"] = checkMobile; function checkMobile() { // check if phone number is a mobile number } If a form field is discovered to contain an error, the script automatically creates an error message next to it. I used the same naming system as with the validation functions: [Form Validation, lines 2-3] validationErrorMessage['required'] = 'This field is required'; validationErrorMessage['numeric'] = 'This field requires a number'; In addition, I decided that any validation function could return one of three values:
This allows Webmasters to define special error messages for special cases. Dropdown Menu
HTML structureThe script must understand which sub-navigation to show when the user selects a main navigation item. Obviously, the best way of doing that is to use nested lists. If the user selects an item that contains a list, that list should become visible. In addition, the root <ul> should get a class name that indicates "I'm a dropdown menu" and simultaneously serves as a JavaScript hook. <ul > <li><a href="#">News</a> <ul> <li><a href="#">Press Releases</a> <ul> <li><a href="#">Release 1</a></li> <li><a href="#">Release 2</a></li> <li><a href="#">Release 3</a></li> </ul> </li> etc. Script structureIn principle, the script structure is simple. If the user selects an item, make that item's nested list (if any) visible; if the user unselects the item, or selects another item, the nested list should become invisible again. I didn't want to perform all kinds of complicated calculations in JavaScript, so I decided that the script would change only the className of the nested list. The CSS definitions for this new class name would take care of the actual visibility/invisibility. We'll get back to Dropdown Menus in Chapter 7, especially in 7H. Edit Style Sheet
HTML structureThis script works with a form that contains fields that allow the Webmaster to change the styles. Since the script runs on an administration page, we have greater control than usual over its exact content. Therefore the script does not use a hook, but instead is hard-coded to use the second form in the page. In order to keep everything simple, I decided to store the names and values of the CSS properties in the form fields: <select name="textAlign" > <option value="">not specified</option> <option value="left">Left</option> <option value="center">Center</option> <option value="right">Right</option> </select> This select box is meant for setting the alignment of the text. Therefore, its name is textAlign (the JavaScript version of CSS text-align), and the values of the options are the CSS values: left, right, or center. The script thus only has to read out the name and value of the form field the user changed in order to know which style it should change to which value. We'll discuss this further in 5K and 9D. Script structureThe script first has to access the individual rules of the correct style sheet (colors.css in the example). Then it waits for the user to pick a rule, and to change a style of that rule. As we saw, the style change itself is easy: Just take the name/value pair of the form field the user has changed, and use it as a CSS property/value pair. Sandwich Picker
HTML structureEach sandwich can be moved through the document. Since the list with all sandwiches and their descriptions is clearly a case of tabular data, it made most sense to give each sandwich its own <tr> and move these <tr>s through the document. In addition, I put the price information in the table headers. Any sandwich below a certain header has that price. The element with initially contains all sandwich <tr>s, and therefore this id serves as the script's hook. Script structureThe script's main job is to find out which <tr>s should be moved to which position, and then to do it. This is trickier than it seems; we'll discuss this problem fully in 8I. The script should have easy access to the sandwich name and price, since they are needed for the search action and the total price calculation. Therefore I added these two bits of data as properties of the object that represents the <tr> (see 5J). XMLHTTP Speed Meter
HTML structureIn all scripts we've discussed so far, I decided to store a significant amount of data in the HTML. This is not necessary with XMLHTTP Speed Meter; here, the data is pulled from the server by an XMLHttpRequest. Therefore the only important point in the HTML structure was the animation. I decided to always show a grey background image, and to overlay it with an element that had a green background image. The animation would consist of changing the width of this element. The script uses a few ids as hooks, and I assign a submit event to the only form in the page. Script structureThis script has two distinct modules:
I developed each independently; their only point of connection is that the XMLHTTP module passes the data (the download speed) to the animation module. We'll discuss the animation module in 9G and the XMLHttpRequest module in Chapter 10. Site Survey
HTML structureThis script should be able to work on any page in any site. Therefore, I didn't prepare an HTML structure, except for defining an optional element with . If this element is present in the page the script is added to, the script creates a little help text that announces the popup that's going to open. The popup contains a bit of text and a form. The script adds as many hidden fields to this form as necessary. This script uses no hooks, since I can't predict how the pages it will work on will be structured. Besides, the script hardly changes anything in the document tree, so it doesn't really need hooks. Script structureThe main challenge was keeping the communication between the popup and the main window open. The script reads out the necessary data (mainly the page URLs) and stores quite a bit of information in cookies for safekeeping. We'll discuss these features in detail in 6B. Detail decisionsThese explanations focus on the high-level decisions I made while I was working out the scripts. These decisions allowed me to start writing the script, although during the writing I discovered many special cases and little extras that also needed to be addressed. For instance:
These are typical functionalities you add later on. Although they're important for the overall user experience of the scripts, you shouldn't worry about them much while making core decisions. Making sure that the basic functionality works is your first priority; once that's done you can start working on the extras. Besides, usually you'll discover the need for such extras only while you're writing the script. |