Click on the image to change it.
Click on the image to change it.
We might hope that this would display a message saying which image is currently being shown. If so, we will be disappointed. The text 'Currently showing image 0' will be inserted into the HTML once and once only, namely the first time that the JavaScript is executed. (Re-loading the page doesn't change this, because it will cause the JavaScript in the header to be re-executed, setting i back to 0.) Section 12 below shows one way of achieving dynamic messages. JavaScript has the built-in ability to create 'date' objects, which make handling dates and times easier. When initially constructed, a new Date object will hold the current date and time: var now = new Date(); // Holds current date and time var dayInMonth = now.getDate(); // Day of the month, from 1 to 31 var dayInWeek = now.getDay(); // Day of the week, from 0 (Sun) to 6 (Sat) var month = now.getMonth(); // Month, from 0 (January) to 11 (December) var year = now.getFullYear(); // Year as a 4 digit number var hr = now.getHours(); // Hour, from 0 to 23 var min = now.getMinutes(); // Minute, from 0 to 59 var sec = now.getSeconds(); // Second, from 0 to 59 var timeStr = 'Time now is '+hr+':'+min+':'+sec+' on '+dayInMonth+'/'+ (month+1)+'/'+year; A web page which displays the above 'time string' using the document.write method will be found at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg7-1.html. Date objects store time internally as milliseconds since midnight, 1 January 1970. Using the getTime and setTime methods which access these values, it's possible to step backwards and forwards from a given date and time, without having to deal with the complexities of the varying number of days in a month or whether it's a leap year or not.[7] The code fragment below sets tomorrow to exactly one day from now: var now = new Date(); var tomorrow = newDate(); tomorrow.setTime(now.getTime()+24*60*60*1000); For an example of the use of date calculations, see http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg7-2.html. It is also possible to create your own objects and 'classes' of object in JavaScript; see Section 13. 8 Arrays Arrays are a kind of object. Unlike Java arrays, they are not of fixed size and are untyped. Thus the following is legal: var a = Array(); a[0] = 6; a[2] = ' is '; a[3] = true; The value of a[1] is undefined. (The expression typeof a[1] will have the string value 'undefined'.) The length of the array, as determined by a.length, is 4. Had a been declared by var a = Array(5); with the same statements following, then a[4] would also be undefined. It is not an error to attempt to access undefined values in JavaScript; they generally behave as if they had the value null (similar to Java's null). We can show all the defined values in an array via code such as: function showArray(a) { var msg = ''; for (var i=0; i
=
The box below should change colour regularly from black to red and back again.
Some notes on this example: The style attached to all elements of class box causes them to have a 2 pixel wide black border all round. In the example, this style is attached to a div with id "box1". The function init sets the value of the global variable box1 to the JavaScript object representing the div. The setInterval function is then used for animation (see the discussion below); changeColour will be called once every second. The function changeColour then sets and re-sets the border-color style specifically for the div element, which by the rules of CSS, over-rides the class-wide style. This relies on the browser dynamically changing its display whenever the CSS changes. JavaScript provides three useful 'timer' functions (methods of the window). setInterval(JavaScript_string, time_in_msec) executes the JavaScript given in the first string argument after every interval of time_in_msec milliseconds. It returns a timer identifier which should be saved if it will be necessary to stop the activity. clearInterval(timerID) stops the action created by setInterval: timer1 = setInterval('run()', 2000); . . . . . . clearInterval(timer1); setTimeout(JavaScript_string, time_in_msec) executes the JavaScript given in the first string argument after one interval of time_in_msec milliseconds. (If the action has not taken place, it can be stopped via clearTimeout(timerID).) In Section 13, we discussed creating objects and in particular rectangle objects. By combining this with the technique discussed here we can 'draw' the rectangles as they are created. We first set up the CSS box class to ensure that a div of this class will not be visible: Notice that we declare position: fixed; to ensure that the element is positioned at an absolute location relative to the window.[11] Now we write the JavaScript to create rectangle and filled rectangle objects, defining their size, position and colour via CSS styles. Note how we store a reference to the corresponding DOM object within our rectangle object so that it is easy to access the style field. function makeRect(id,left,top,width,height) { var r = new Object(); r.left = left; r.top = top; r.right = left+width; r.bottom = top+height; r.domObj = document.getElementById(id); r.domObj.style.cssText += 'left:'+left+'px; top:'+top+'px; width:'+ width+'px; height:'+height+'px; border: solid 2px black;'; return r; } function makeFilledRect(id,left,top,width,height,colour) { r = makeRect(id,left,top,width,height); r.colour = colour; r.domObj.style.cssText += ' background-color: '+colour; } The function init is used to set up three rectangles when the body of the page has loaded: function init(box1ID,box2ID,box3ID) { makeFilledRect(box1ID,15,60,50,100,'green'); makeRect(box2ID,30,100,150,75); makeFilledRect(box3ID,45,85,50,50,'red'); } Finally we set up the initially invisible div elements in the body of the page: The complete page will be found at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg14-2.html. If we want the user to interact with our objects, then it is useful to create links in both directions between our object and the corresponding DOM object. JavaScript's ability to add fields to existing objects makes this easy to do, although we must be careful not to over-ride an existing field. The makeRect function can have an additional line added: function makeRect(id,left,top,width,height) { var r = new Object(); . . . . . r.domObj = document.getElementById(id); . . . . . r.domObj.owner = r; // Relies on 'owner' being a new field! return r; } As a simple of example of how this link can be used, suppose we want to change the appearance of a rectangle object when the user clicks on it. We begin by adding a clicked field and a doClick method to makeRect: function makeRect(id,left,top,width,height) { var r = new Object(); . . . . . r.clicked = false; r.doClick = function () { if (!r.clicked) r.domObj.style.borderColor = 'yellow'; else r.domObj.style.borderColor = 'black'; r.clicked = !r.clicked; }; return r; } Finally we add an onclick event handler to the div elements. In the event handler code which is the value of an event attribute, the keyword this refers to the DOM object corresponding to the HTML element. Hence by using this and the owner field we have added to it, we can link to the corresponding rectangle object: The complete page will be found at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg14-3.html. For a further example of what it is possible to do with JavaScript and dynamic CSS, see http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg14-4.html. (Depending on your machine and browser, the animation speed may or may not be satisfactory.) 15 Manipulating the HTML DOM Consider the following XHMTL:Manipulating the JavaScript DOM is a very important technique.
Varying browser support is the main problem.
Manipulating the JavaScript DOM is a very important technique.
Varying browser support is the main problem.
Enter person's name:
The user enters a name into the text input box and then presses the "Show Place of Birth" button. The initially empty "display" div element is then used to show the result. The init function sets up the necessary objects and requests the XML document. The callback function extracts and stores an array of the objects corresponding to the person elements: var displayDiv; var nameInput; var persons; function init(displayDivID,nameInputID) { displayDiv = document.getElementById(displayDivID); nameInput = document.getElementById(nameInputID); requestXML('http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/'+ 'data.xml', setupPersons); } function setupPersons(xmlDoc) { persons = xmlDoc.getElementsByTagName('person'); } Finally when the user presses the button, the array is searched for the appropriate name and a result displayed. A minor issue is that, as noted in Section 15, text values retrieved from an XML source may contain extra white space. For this reason, xhrlib.js also contains normalize_space(str) which normalizes a string by stripping any opening and closing white space and replacing all other occurrences of white space by a single space.[16] function showBirthplace() { var name = normalize_space(nameInput.value); if (name != '') { var i = 0; var found = false; while (!found && i < persons.length) { var person = persons[i]; found = normalize_space(person.getElementsByTagName('name')[0]. firstChild.data) == name; i++; } if (!found) { displayDiv.innerHTML = 'Unknown person: '+name+'.'; } else { var birthplace = normalize_space(person. getElementsByTagName('birthplace')[0]. firstChild.data); displayDiv.innerHTML = name+' was born in '+birthplace+'.'; } } } The complete HTML page is at http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/Eg16-3.html. In spite of the fact that it only displays part of the data, Example 16-3 still downloads the entire XML file. This is clearly undesirable: The file may potentially be very large and so its loading will cause an unacceptable delay, especially with a slow connection. Since the XML file must be available by HTTP, there is no way of hiding data which the user should not be able to access -- by inspecting the source code of the JavaScript, the user can find the URL of the XML file, and then download it directly. The solution is server-side processing. For example, the URL used to access the required XML could be directed at a web page containing server-side script, written in a language such as PHP. The web server executes such script before sending the result to the client. For example, given a person's name, the server could send back some XML describing only that person. (The original data does not have to be stored as XML, since the program or script running on the server can obtain data from any source and then 'wrap' it in XML.) When http://www.cs.bham.ac.uk/~pxc/infoweb/2007/Egs/data.php?name=John Smith is accessed,[17] it returns XML equivalent to: