Client-Side Scripting
Up to now we focused on implementing application logic on the server The browser was just a simple, generalized user interface that did not play
a role in executing the application logic It is beneficial for clients to share in the execution of some of the
application logic Central focus of client-side scripting is to manipulate the content of a web
page Application logic as such is not concerned with presentation, but client-
side scripting can be used to make web pages more dynamic
Client-Side Application Logic
Field and form validation o For example, a date entry field should never accept the date Feb 30 o Without client-side validation this value would be submitted with
the form and only there identified as an incorrect value o Relying solely on server-side validation is expensive (server trips)
Automatic computation of dependent values o For example, when an item is added to a shopping cart, the new
total can be computed automatically on the client
Making Web Pages More Dynamic
New input controls o For example, a date-picker control that pops up a calendar for the
user to select a date from Rollovers and swaps
o For example, as the mouse moves over an image it is replaced by another image that gives feedback to the user that the image can be clicked
Adding HTML to the page o For example, a client-side script can insert the current date into a
web page dynamically
Document Object Model
Regardless of the scripting language, the Document Object Model (DOM) provides a platform-neutral interface to browser and content of a page
Defined by the W3C Most browsers implement it in their latest versions The name Document Object Model was chosen, because it provides an
object interface to HTML (and XML) documents (data and behavior)
Object Interface to the Browser
For example, this is the set of browser objects Netscape makes available. A good reference on DOM programming.
JavaScript
Most common scripting technology in browsers available today Name a misnomer: JavaScript was born as "LiveScript" and its name was
changed for marketing purposes However, it does share some basic syntax with Java, which makes it easy
to learn o JavaScript does not have Java's typing system o Fewer core data types o Prototype-based object model (does not support inheritance)
Predefined JavaScript Objects
The principal object to use when working with document content is the document object, a reference to which can be obtained through the window object that represents a browser window
For example, the following code initializes a text field in a form with the current day of the week
var today = new Date(); var weekdays = new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); var dayOfWeek = weekdays[today.getDay()]; window.document.forms["demo"].elements["day"].value = dayOfWeek;
The Navigator Object
The navigator object indicates which browser we are using. function navProperties() { alert("The browser is: "+navigator.appName + "\
n" + "The version number is: " + navigator.appVersion
+ "\n"); }
Browser?
Including JavaScript on a Web Page
o Use the <script> tag to define regions of JavaScript code o Generally, the <script> tag appears in the head of a web page; if it
appears elsewhere it will be executed at this point in the document
<script language="JavaScript"> function inRange(value, low, high) {
return low <= value && value <= high; }
function checkAge(field) {if (!inRange(field.value, 18, 99)) {
alert("Enter a correct age!");}
} </script>Check Age
Events
o Normal way of invoking JavaScript is in response to interface events
<input type="text" name="age" onChange="checkAge(this);">
o An event is something that triggers a script o The event handler parameter of the HTML element defines the
code (usually a call to a function) that will handle the event when it is fired
o Some of the more common events are: onClick -- User clicks a form field or link onChange -- User changes the value of a form field onMouseOver -- User moves mouse pointer over a link onMouseOut -- User moves mouse out of an image or link onSubmit -- User submits a form
Simple Temperature Calculator
o The following code converts from Fahrenheit to Celsius
function convert(form) {form.celsius.value =
Math.round((form.fahrenheit.value - 32)/1.8); }
o Include it between <script> tags in the head of your web page, and insert the following somehwere in the body
<form name="f2c">Temperature:
<input type="text" name="fahrenheit" value="32"> F to <input type="text" name="celsius"> C <input type="button" value="Convert" onClick="convert(this.form)"> </form>
Convert Temperature
How to Rollover?
o A rollover swaps one image for another as the user moves over an image
In the following code we refer to the image by its name (order)
The onMouseOver handler sets the "src" property of the image to another value
The onMouseOut handle resets the "src" property to its original value
<a href="checkout.html" onMouseOver="images.order.src='rollover-2.jpg'"onMouseOut="images.order.src='rollover-1.jpg'"><image name="order" src="rollover-1.jpg" border="0">
</a>
Rollover
Input Validation
o Restrictions on a form Some fields may only accept numbers Others may only accept dates Some fields may only accept a range of entries Some fields may be required Some combination of fields may not be permitted
o Handle restrictions by two types of checks Validate each element as data is entered Perform validation when the form is submitted
Validating Form Elements
o Checking element when data is entered most effective for validating format or range
o Perform such checks using the onChange event handler
<input type="text" name="age" onChange="checkAge(this);"
Validating Form Submissions
o Perform data validation just before form is submitted o Perform such checks using the onSubmit event handler
<form method="post" action="/cgi/register.cgi"onSubmit="return checkForm(this);">
o onSubmit handler must return true or false If it returns false, the form will not be submitted
function checkForm(form) {if (form.age.value == "") { alert("Please enter your age");
return false;}return true;
}
o Note that the following are equivalent
form.age.value form["age"].value
Some Useful Validation Idioms
o Checking for integers o Checking for ranges o Checking for phone numbers o Checking for postal codes
Checking for Integers
o Checks if a value is an integer
function isInteger(value) {return value == parseInt(value);
}
o If the value contains other characters than numbers, parseInt() will be different from value
Checking for Ranges
o Checks if a value is within a range
function inRange(value, low, high) {return low <= value && value <= high;
}
o Obvious!
Checking for Phone Numbers
o Since there are many ways phone numbers can be formatted, this is just an example
function checkPhone(field) {if (!field.value.match(/\d{3}-\d{4}/)) { alert("Incorrect phone number"); return false;}return true;
}
o This examples uses a regular expression to describe a phone number
Checking for Postal Codes
o Checks if a postal code is correctly formatted
function checkPostalCode(field) {if (!field.value.match(/([A-Z][0-9]){3}/)) { alert("Incorrect postal code"); return false;}return true;
}
o Similar to checking a phone number
Examples
o All examples
Day of Week
Add new appointment for:
Events
How old are you?
Temperature Converter
Temperature: F to C
Rollover
Input Validation
Phone:
Postal Code:
Topics
Basics Primitives, Operations and Expressions Screen Output Control Statements Object Creation Arrays, Functions
JavaScript Basics
Collection of objects supporting control of browser and user interaction. Can be used on server too, but it is different there. Not studied here Isn't typed like Java -- more like Perl. Variables are dynamically bound at run time. Similar syntax to Java ... but don't be fooled! Used instead of Applets because:
o Easier to learn, graphics are simpler o Simple event model using callbacks o Applets downloaded separately to HTML
JavaScript Objects
Objects have collections of properties (members in Java or C++).
Properties are data or method. Data either primitive or reference to object. Properties referenced by <object>.<property;> e.g. myCar.engine Javascript objects appear as Perl hashes: internally and externally Identifiers are CASE SENSITIVE: Foo and foo are different variable
names.
Using JavaScript
Using <script> tag in head and body of HTML. Can write JavaScript inline or reference files externally. Internally <script language="JavaScript"> function testValue(field) { if (field.value < 0) { alert("Negative value!); } } </script>
Externally <script language="JavaScript" src="test_value.js"></script>
JavaScript Keywords and Comments
break delete function return typeofcase do if switch varcatch else in this voidcontinue finally instanceof throw whiledefault for new try with
Comments have two forms: // and /* */ combination. Hide code from browsers without JavaScript using: <!-- ... //--> Semi-colons are optional in most cases, but use them anyway!
JavaScript Primitive Types
Number -- double precision floating point String -- use ' or " for delimeter, use \ to create escape sequences. No
difference between ' and "" forms. Boolean -- true or false Undefined -- single value undefined
Null -- single value null
JavaScript Objects and Variables
Number String Boolean Wrappers for primitive types but define methods on them. Variable declared with var keyword. var birthday = "8th March", index;
Interpreter does coercion.
JavaScript Operators and Assignment
Usual +, -, /, * Increment (++), Decrement (--) both pre- and postfix. Normal precendence rules apply. Testing type: typeof operator, returns "number", "string" or "boolean". Assignment exactly as Java e.g. var a += 4
Math and Number Objects
Math provides collection of methods to operate on Number objects e.g. o max, min, floor, sin, cos ...
Number provides several useful constants: MAX_VALUE Largest representable numberMIN_VALUE Smallest representable numberNaN Not a numberPOSITIVE_INFINITY Special value to represent infinityNEGATIVE_INFINITY Special value to represent negative infinityPI 3.14159265358979323846 approximately
NaN != NaN (Use isNaN() to test). Useful method toString() on Number, although coercion often automatic.
Strings
Concatentation: "first" + "time" -> "firsttime" Length of a string: var str = "Birthday"; var len = str.length;
charAt(N) Returns character at NindexOf(C) Position in string of character Csubstring(I,J) Substring from Ith to Jth characterstoLowerCase Converts to lower casetoUpperCase Converts to upper case
Screen Output
JavaScript interpreted as body of HTML document is interpreted. Output from JavaScript goes to same place as HTML document. Use Document object (see DOM) A good reference on DOM programming. Use write method of document object: document.write("Hello world<br/>");
Can include ANY HTML in write method -- don't use \n Window object can generate dialog boxes: alert("Warning something bad has happened."); Alert var question = confirm("Do you want to continue?"); Confirm var birthday = prompt("What is your birthday?", "8th
March"); Prompt
Dialogs are modal
Compound Statements and Relational Expressions
Compound statements: statements delimited by { }. Operation Operator
Is equal to ==Is not equal to !=Is less (or equal) than (to) <,<=Is greater (or equal) than (to) >, >=Is strictly equal to ===Is strictly not equal to !==
Also have the use AND (&&), OR (||) and NOT (!)
Selection and Control Statements
if-then and if-then-else if (birthday != "8th March) ... if (a > b) { a = b; } else { a += 1; }
switch switch (expression) { case value_1: // value_1 statements case value_2: // value_2 statements ... default: // default statements // Optional }
Should use break at the end of value statements.
Selection Example
<html> <head> <title>A switch statement</title> </head> <body> <script language="JavaScript"> var case = 3; switch (4 * case - 10) { case 1: document.write("It's case 1", "<br/>"); break; case 2: document.write("It's case 2", "<br/>"); break; case 3: document.write("It's case 3", "<br/>"); break; default: document.write("Error in switch statement,
"<br/>"); break; } </script> </body> </html> Switch
Loops and While statements
while (control expression) { statements } var index = 0;
while (index < 10) { index++; ... }
for (initial expression; control expression; increment expression) { statements }
var sum = 0, count; for (count = 0; count <= 10; count++) { sum += count; }
do { statements } while ( control expression) do { count++; sum = sum + (sum * count); } while (count <= 50);
Object Creation and Modification
Use new expression for creation of objects var my_new_object = new Object();
my_new_object has no properties initially. Can create properties by assigning them. Object is a hash ... just like Perl var my_car = new Object(); my_car.make = "Ford"; my_car.model = "Focus"; my_car.year = 2002; my_car.engine = new Object(); my_car.engine.size = "2.0L"; my_car.engine.hp = 124;
Can also access my_car.make by my_car["make"]. Delete properties by: delete my_car.model;
Can also use constructors to generate "types". Can iterate on properties (just like Perl's foreach): for (identifier in object) { statements } for (var prop in my_car) { document.write("Name: " + prop + "; Value: " + my_car[prop] + "<br/>"); }
Arrays
Have dynamic length
Creation: var my_array = new Array(1, 2, "three", "four"); var my_other_array = new Array(100); var my_third_array = [1, 2, "three", "four"];
Array bounds start at zero. my_array.length; // gives me the current length of my_array my_array.length = 100; // makes the current length of my_array 100 my_array.join(" : ") would yield "1 : 2 : three : four" my_array.reverse() would yield ["four", "three", 2 1] Also have sort() var names = ["Bill", "Ben", "Alice", "Tony"]; var sorted_names = names.sorted(); sorted_names == ["Alice", "Ben", "Bill", "Tony"];
Can pass (2 argument) function to sorted(sort_fn) // Sort descending function sort_fn(a, b) {b - a}; sorted_names = names.sort(sort_fn); sorted_names == ["Tony", "Bill", "Ben", "Alice"];
And slice()? var slice_of_names = names.slice(1,3); slice_of_names == ["Ben", "Alice", "Tony"]; slice_of_names = names.slice(2); slice_of_names == ["Alice", "Tony"];
Array Operations
push() and pop() var popped_name = names.pop(); popped_name == "Tony"; // Removed Tony from the list names.push("Tony"); names == ["Bill", "Ben", "Alice", "Tony"]; // Added Tony to
end of list
shift() and unshift() var shifted_name = names.shift(); shifted_name == "Bill"; // Removed Bill from the list names.unshift("Bill"); names == ["Bill", "Ben", "Alice", "Tony"]; // Added Bill to
front of list
Multidimensional Arrays
Implemented as array of arrays
var nested_array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
Functions
Using "function" keyword Can have references to functions too. function foo(arg1, arg2) { var function_name = "foo"; current_function = function_name; document.write("This is the " + function_name + "
function. <br/>";); } var reference2foo = foo; // Can call foo via reference now reference2foo();
Have to define function before refering to it. Functions go in <head> section of document.
Functions
Functions can have local variables; e.g. function_name NOTE: Implicitly declared variables are GLOBAL; e.g. current_function Local variables of same name take precedence over global declarations. Parameter passing is by value, but objects are references! Parameters communicated via arguments array -- actual as well as formal. arguments array is similiar to @_ in Perl. foo(1, 2, 3); // Formal are 1 and 2, arguments array is [1, 2, 3] foo(1); // Formal is 1, arguments array is [1]
Constructors
You can use "new Object()" and assign properties, but it's awkward. Constructors are special functions for creating and initializing objects. function car(new_make, new_model, new_year) { this.make = new_make; this.model = new_model; this.year = new_year;
} // Constructing a car var my_car = new car("Saturn", "SL1", "2002");
Can have method as well as data properties. function display_car() { document.write("Car make: ", this.make, "<br/>"); document.write("Car model: ", this.model, "<br/>"); document.write("Car year: ", this.year, "<br/>"); } // Now constructor is: function car(new_make, new_model, new_year) { // Data properties this.make = new_make; this.model = new_model; this.year = new_year; // Method properties this.display = display_car; // <-- Method to display
myself } // Display myself var my_car = new car("Saturn", "SL1", "2002"); // Display the car on the current page my_car.display();
Pattern Matching
Applies to String objects. Similiar principles to Perl. search method var str = "Saturn"; var position = str.search(/ur/); // Would return 3
replace method var str = "Fred, Freddie, and Frederica were siblings"; str.replace(/Fre/g, "Boy"); // str == "Boyd, Boyddie, and Boyderica were siblings"; // $1, $2, and $3 variables are set to "Fre"
match method var str = "I can have 1 2 3 or 4 chances to win." var matches = str.match(/\d/g); // matches == [1, 2, 3, 4]
split method var str = "pears:grapes:apples"; var fruit = str.split(/:/); // fruit == [pears, grapes, apples]
Regular expressions same as perl; e.g.
\s for space \d for [0,1,2,3,4,5,6,7,8,9] etc
Topics
Document Object Model (review) Events and event handling Events, attributes and tags Load and unloading documents Button events Event propagation
Document Object Model (DOM)
DOM standardized by W3C. Defines object hierarchy to allow scripts to interact with HTML
documents. DOM is just an interface between HTML and application programs. DOM is tree-like, but it's an abstract interface. Most browsers versions beyond 5 (IE, Netscape) support DOM. The document object represents displayed HTML document. The window object is container for document object. Important objects within document:
forms Forms defined within the HTML documentforms.elements Objects within the form; e.g. buttons and menus
DOM Structure example
<table><tr> <td>a</td> <td>b</td></tr><tr> <td>c</td> <td>d</td></tr></table>
Events
JavaScript implements an event-driven programming model. Events are notifications of something noteworthy happening:
o Document loading or unloading o Clicking a button o Changing focus from one element to another
Events are processed by event handlers. Similiar to, but simpler than, Java model. Events are objects, so names are case-sensitive. Don't use the document.write() method in event handlers!
Event Tag Attribute Explanation
abort onAbort Image loading aborted
blur onBlur1. A document or frame loses input focus
2. Text or selection element loses focus
change onChange1. Text field or area changes and loses focus
2. Selection element changes and loses focus
click onClick
1. Click on link 2. Submit, Reset or other Button is pressed 3. Radio button is pressed
4. Checkbox is clicked
error onError 1. Image loading error
2. Document loading error
3. Frame loading error
focus onFocus
1. Document or frame receives focus 2. Text field or area receives focus
3. Select element receives focus
load onLoad1. Image has been loaded
2. Document or frame has been loaded
mouseout onMouseOut1. Mouse moved from over link
2. Mouse moved out of image map
mouseover onMouseOver1. Mouse moved over link
2. Mouse moved into image map
reset onReset Reset button pressed
resize onResize Window size is changed
select onSelect1. Mouse cursor moved over text field
2. Text area is selected within a text area
submit onSubmit Submit button is pressed
unload onUnload1. User exits the document
2. User exits a frameset
Element Identification and Event Callbacks
Give every element and id attribute. Use getElementById method of document to obtain element. ... <form id = "testExample"> <input type="text" id = "testInput"> ... </form> ... document.getElementById("testInput").style is address of
input element
Callbacks specified in 2 ways: Assume form with name "example" defined, containing
"textField"
As attribute of HTML tag: <input type="text" name="textField" value="2002"
onChange="validate()"> Or dynamically, through property of element: document.forms["example"].elements["textField"].onChange =
validate;
Using event attribute (e.g. onChange) adds flexibility. Cannot pass arguments through -- not even "this".
Selection and Focus
Error handling frequently requires change of focus and selection. Invoke function through address of DOM element document.forms["example"].elements["textField"].focus(); /
/ Sets focus document.forms["example"].elements["textField"].select(); /
/ Highlight text
Remember: if form to remain active return false after check.
Event Propagation
Can handle events on one element by another Document can handle ALL onchange events (for example) Table could handle ALL onchange events for its cells load, unload, focus and blur events do not propagate
Dynamic Content
DHTML examples Can modify DOM tree dynamically. Addition, deletion and editing possible e.g. Adding TEXT function appendTEXT(tag,index,text){ var oj = document.createTextNode(text) ;
document.getElementsByTagName(tag).item(index).appendChild(oj);
}
<FORM> <INPUT TYPE="button" VALUE=" to DIV0"
onClick="if(document.getElementById)appendTEXT('DIV',0,' (^^)/DIV0 ')">
<INPUT TYPE="button" VALUE=" to DIV1"
onClick="if(document.getElementById)appendTEXT('DIV',1,' (^^)/DIV1 ')">
<INPUT TYPE="button" VALUE=" to DIV2"
onClick="if(document.getElementById)appendTEXT('DIV',2,' (^^)/DIV2 ')">
<INPUT TYPE="button" VALUE=" to SPAN0"
onClick="if(document.getElementById)appendTEXT('SPAN',0,' (^^)/SPAN0 ')">
<INPUT TYPE="button" VALUE=" to SPAN1"
onClick="if(document.getElementById)appendTEXT('SPAN',1,' (^^)/SPAN1 ')">
</FORM> <DIV>div0 : <SPAN>span0 : </SPAN></DIV> <SPAN>span1 : </SPAN> <DIV>div1 : </DIV> <DIV>div2 : </DIV> </form>
div0 : span0 :
span1 :
div1 :
div2 :
Adding an Image function addImage(imageURL) { var imgEl = document.createElement("IMG"); imgEl.src = imageURL; imgEl.id = imageURL; document.body.appendChild(imgEl); }
<a href="javascript:addImage('rollover.jpg'); void 0">Adding an Image</a>
Adding an Image
Edit the image function editImage(id, src) { var imgEl = document.getElementById(id); imgEl.src = src; // Should re-do the size of the image -- exercise to
student } <a href="javascript:editImage('rollover.jpg', 'dom.jpg');
void 0">Editing an Image</a>
Editing an Image
Removing the image function removeImage(id) { var imgEl = document.getElementById(id); document.body.removeChild(imgEl); } <a href="javascript:removeImage('rollover.jpg'); void
0">Removing an Image</a>
Remove an Image
Dynamic Positioning and Visibility
visible and hidden attributes values used to change display. Attibute visibility can be accessed document.getElementById("id").visibility = "visible" |
"hidden"; <form id = "dynamicForm"> <span id="dynamicText">Text field: </span> <input type="text" id = "dynamicInput" value="8th March"> </form>
Text field:
Hide form <a href="javascript:document.getElementById('dynamicForm').style.visibility='hidden'; void 0">Hide form</a> Show form
<a href="javascript:document.getElementById('dynamicForm').style.visibility='visible'; void 0">Show form</a>
Positioning: top and left attributes function moveIt(id, newTop, newLeft) { var elt = document.getElementById(id); elt.top = newTop; elt.left = newLeft; }
Cookies
Can be created on the client side too. DOM exposes cookie through document.cookie Set a cookie by assigning property, retrieve one by reading its current
value. The following statement, for example, sets a new cookie with a minimum number of attributes:
document.cookie = "cookieName=cookieValue"; Set Cookie Display the property's value: alert(document.cookie);
Value of document.cookie is string containing a list of all cookies associated with web page. Consists of name=value pairs for each cookie that matches the current domain, path, and date.
cookieName1=cookieValue1; cookieName2=cookieValue2
Cookie Manipulation Functions
// name - name of the cookie// value - value of the cookie// [expires] - expiration date of the cookie (defaults to end of current session)// [path] - path for which the cookie is valid (defaults to path of calling document)// [domain] - domain for which the cookie is valid (defaults to domain of calling document)// [secure] - Boolean value indicating if the cookie transmission requires a secure transmission// * an argument defaults when it is assigned null as a placeholder// * a null placeholder is not required for trailing omitted arguments
// E.G. document.cookie = "cookieName=cookieValue; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/directory/thisFile.html; domain=scs.carleton.ca; secure function setCookie(name, value, expires, path, domain, secure) { var curCookie = name + "=" + escape(value) + ((expires) ? "; expires=" + expires.toGMTString() : "") + ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + ((secure) ? "; secure" : ""); document.cookie = curCookie;}
// name - name of the desired cookie// * return string containing value of specified cookie or null if cookie does not existfunction getCookie(name) { var dc = document.cookie; var prefix = name + "="; var begin = dc.indexOf("; " + prefix); if (begin == -1) { begin = dc.indexOf(prefix); if (begin != 0) return null; } else begin += 2; var end = document.cookie.indexOf(";", begin); if (end == -1) end = dc.length; return unescape(dc.substring(begin + prefix.length, end));}
// name - name of the cookie// [path] - path of the cookie (must be same as path used to create cookie)// [domain] - domain of the cookie (must be same as domain used to create cookie)// * path and donavigator.mimeTypesdoublemain default if assigned null or omitted if no explicit argument proceeds
// Sets the expiry date so that the cookie will disappear immediately.
function deleteCookie(name, path, domain) { if (getCookie(name)) { document.cookie = name + "=" + ((path) ? "; path=" + path : "") + ((domain) ? "; domain=" + domain : "") + "; expires=Thu, 01-Jan-70 00:00:01 GMT"; }}
Cookie Manipulation Example -- personalized counter
// date - any instance of the Date object// * hand all instances of the Date object to this function for "repairs"function fixDate(date) { var base = new Date(0); var skew = base.getTime(); if (skew > 0) date.setTime(date.getTime() - skew);}
// create an instance of the Date objectvar now = new Date();// fix the bug in Navigator 2.0, MacintoshfixDate(now);// cookie expires in one year (actually, 365 days)// 365 days in a year// 24 hours in a day// 60 minutes in an hour// 60 seconds in a minute// 1000 milliseconds in a secondnow.setTime(now.getTime() + 365 * 24 * 60 * 60 * 1000);var visits = getCookie("counter");// if the cookie wasn't found, this is your first visitif (!visits) { visits = 1; // the value for the new cookie document.write("<span style=color:red>By the way, this is your first time here.</span>");} else { // increment the counter visits = parseInt(visits) + 1; document.write("<span style=\"color:red\">By the way, you have been here <i>" + visits + "</i> times.</span>");}// set the new cookiesetCookie("counter", visits, now);
By the way, this is your first time here.
Breaking out of Frames
<!-- frame buster - code by Gordon McComb --><script language="JavaScript" type="text/javascript"> <!-- Hide script from older browsers setTimeout ("changePage()", 3000);
function changePage() {if (self.parent.frames.length != 0)
self.parent.location=document.location;
}
// end hiding contents --></script>
Showing modification dates
<script language="JavaScript" type="text/javascript"><!--
document.write("Last Modified " + document.lastModified)
// --></script>
Has it changed?
Useful to know if a page has changed since last visit. <script language="JavaScript" type="text/javascript"> <!-- var lastModified = getCookie("lastModified"); if (lastModified != document.lastModified) { if (lastModified) { document.write("Document changed since last
visit"); } // create an instance of the Date object var now = new Date(); // fix the bug in Navigator 2.0, Macintosh fixDate(now); // cookie expires in one year (actually, 365
days) // 365 days in a year // 24 hours in a day // 60 minutes in an hour // 60 seconds in a minute // 1000 milliseconds in a second now.setTime(now.getTime() + 365 * 24 * 60 * 60 *
1000); setCookie("lastModified", document.lastModified,
now); } // --> >/script>
Document changed since last visit
Bookmarklets
URLs with JavaScript code that have been saved as bookmarks o http://www.bookmarklets.com
How you turn an URL into a bookmark is browser-specific, for example o Right-click and choose to save link as bookmark o Left-drag to personal toolbar
Your first bookmarklet
javascript:void(window.open(''))
Open window
<a href="javascript:void(window.open(''))">Open window</a>
Using void() ensures that the original page is unchanged
Example - Integrating an Online Dictionary
Create your own bookmarklet that looks up a word you have selected on your page on the Merriam-Webster web site
javascript:q=document.selection.createRange().text;location.href='http://www.m-w.com/cgi-bin/dictionary?book=Dictionary&va='+escape(q); void(0)
How did we know this? Look at the form on the web site
<FORM name="dict" method="post" action="/cgi-bin/dictionary"><TD valign="middle" width="165"><INPUT type="hidden" name="book" value="Dictionary"><FONT color="#ffffff" size="2" face="Arial,
Helvetica"><B>Collegiate<SUP>Æ</SUP> Dictionary</B></FONT></TD><TD valign="middle" width="140"><INPUT name="va" size="15"></TD><TD valign="middle" width="95"><INPUT type="submit" value="Look it up"></TD>
</FORM>
Lookup in Webster
<a href="javascript:q=document.selection.createRange().text;location.href='http://www.m-w.com/cgi-bin/dictionary?book=Dictionary&va='+escape(q);void(0)">Lookup in Webster</a>
Example - Integrating an Online Search
Create your own bookmarklet that looks up a word you have selected on your page using Google
Google Search
<a href="javascript:q=document.selection.createRange().text;location.href='http://www.google.ca/search?q='+escape(q)+'&ie=UTF-8&oe=UTF-8&hl=en&meta=';void(0)">Google Search≪/a>
Bookmarklets and CGI
Recap o Bookmarklets are JavaScripts saved as bookmarks o Execute in the browser's frontmost window o Can interact with object or data in this window
Example o Create and store comments on web pages o Retrieve them later when you visit the pages again
Example - CGI
Accepts an URL and a comment and records them Retrieves a comment when given an URL Declarations
#!/usr/bin/perl
use CGI; use CGI::Carp( fatalsToBrowser );
my $scriptUrl = "http://localhost/~mrw/cgi-bin/245/comment.cgi";
my $q = new CGI; my $url = $q->param("url"); my $comment;
Example - CGI
Branch off to the appropriate handler
if ($q->param("save")) {$comment = $q->param("comment") || "";saveComment($url, $comment);
} else {$comment = getComment($url);
}
Example - CGI
Generate a comment form
print $q->header("text/html"),$q->start_html(-title => $url, -bgcolor => "yellow"),$q->start_form({ action => $scriptUrl }),$q->hidden("url"), # inherits value$q->textarea(-name => "comment", -cols => 30,
-rows => 8, -value => $comment, -wrap),$q->p(
$q->submit(-name => "save", -value => "Save Comment")),$q->end_form,$q->end_html;
Example -CGI
Retrieve a comment from the database
sub getComment {my $url = shift;my %db;
dbmopen(%db, "comment_db", 0666) ||die "unable to open comment database";
requestLock("comment_db"),my $comment = $db{$url};releaseLock("comment_db"),dbmclose(%db);
return $comment;
}
Example - CGI
Save a comment to the database
sub saveComment {my ($url, $comment) = @_;my %db;
dbmopen(%db, "comment_db", 0666) || die "unable to open comment database";requestLock("comment_db"),$db{$url} = $comment;releaseLock("comment_db"),dbmclose(%db);
}
Example - JavaScript
JavaScript that invokes this CGI script
url = document.location.href; open('http://localhost/~me/205/bookmarklets/comments.cgi?url=' + escape(url),'commentlet', 'width=400,height=250');
void(0);
Commentlet
<a href="javascript:url = document.location.href; open('http://localhost/~mrw/cgi-bin/245/comment.cgi?url=' + escape(url), 'commentlet', 'width=400,height=250'); void(0);">Commentlet</a>
Example - Usage
Visit a web site and select the bookmarklet Browser displays another window
Enter a comment and save it On returning to the page, the window will contain your original comment Comments can be shared with other users!
Example - Source Code
Here is the full source code of the CGI script comment.cgi
#!/usr/bin/perl
use CGI; use CGI::Carp( fatalsToBrowser );
my $scriptUrl = "http://localhost/~mrw/cgi-bin/245/comment.cgi";
my $q = new CGI; my $url = $q->param("url"); my $comment;
if ($q->param("save")) {$comment = $q->param("comment") || "";saveComment($url, $comment);
} else {$comment = getComment($url);
}
print $q->header("text/html"),$q->start_html(-title => $url, -bgcolor => "yellow"),$q->start_form({ action => $scriptUrl }),
$q->hidden("url"), # inherits value$q->textarea(-name => "comment", -cols => 60,
-rows => 14, -value => $comment, -wrap),$q->p(
$q->submit(-name => "save", -value => "Save Comment")),$q->end_form,$q->end_html;
sub getComment {
my $url = shift;my %db;
dbmopen(%db, "comment_db", 0666) ||die "unable to open comment database";
requestLock("comment_db"),my $comment = $db{$url};releaseLock("comment_db"),dbmclose(%db);
return $comment; }
sub saveComment {my ($url, $comment) = @_;my %db;
dbmopen(%db, "comment_db", 0666) || die "unable to open comment database";
requestLock("comment_db"),$db{$url} = $comment;releaseLock("comment_db"),dbmclose(%db);
}
# one of many ways to do this ...
sub requestLock { my $alias = shift; my $n = 0; my $lock = $alias . ".lock"; while (mkdir($lock, 0555) == 0) { $! == $EEXIST ||
die "can't make $lock: $!"; $n++ < 30 ||
die "timed out waiting for $lock"; sleep(1); } }
sub releaseLock { my $alias = shift; my $lock = $alias . ".lock"; rmdir($lock); }