Вы находитесь на странице: 1из 265

JavaScript tutorial - Important guidelines

First let's learn some important stuff. There are lots of browsers out there that cannot support JavaScript. Although browsers generally support more and more with each release the language itself !eeps evolving and there is already a vast amount of the JavaScript language available for browsers to support. "o browser will ever support all of it and you cannot e#pect them to. There are many reasons why people cannot or will not 'upgrade' to your chosen browser. A few are$

They are at wor! and they can only use the system default browser. They want to view pages more %uic!ly so they use a te#t only browser. They are blind or have poor eyesight so they need a te#t only browser&reader&'raille reader. They realise that the more e#tra features li!e JavaScript or ('Script you use the more you They don't li!e the way some sites insist on ta!ing over their control of the browser opening

leave yourself open to becoming a target for viruses or vulnerability e#ploits. popup windows brea!ing the operation of the bac! button preventing the conte#t menu from wor!ing or insisting on ma!ing things appear and disappear in a way that causes usability problems. )hatever their reasons you should not stop them from using your site. If your site uses JavaScript for navigation or content then that navigation and content should be there without JavaScript enabled. *our JavaScript can e#tract content from the page and do whatever it wants with that but you should ma!e sure that content is available without the script. If you want to use a script in way that you cannot simply e#tract the information from the static page use <noscript> to provide an alternative for people that cannot run your script. There are also many browsers out there that you do not realise e#ist. I !now of well over a hundred different browsers that support JavaScript to varying degrees. If your script uses something that browsers may not support you should detect if the browser is capable of using it and then fall bac! to an accessible alternative if it doesn't. There is no magic formula for this but the basic rules are that you should not detect a browser ma!e or version. *ou will get it wrong and you will mista!enly detect one browser and thin! it is another ending up with you using the wrong code. *ou will ma!e incorrect assumptions about current and future browsers and you will cause problems for your users. This tutorial should help you learn how to correctly detect capabilities and wherever needed it will show you how to wor! out when a browser cannot do what you need so you can halt your script or provide an alternative. )hen there are different ways to do the same thing and some browsers only then you should

support one while others support another it will show you how to correctly wor! out which one to use.
Introduction to JavaScript

JavaScript is a programming language that can be included on web pages to ma!e them more interactive. *ou can use it to chec! or modify the contents of forms change images open new windows and write dynamic page content. *ou can even use it with +SS to ma!e ,-T./ 0,ynamic -yperTe#t .ar!up /anguage1. This allows you to ma!e parts of your web pages appear or disappear or move around on the page. JavaScripts only e#ecute on the page0s1 that are on your browser window at any set time. )hen the user stops viewing that page any scripts that were running on it are immediately stopped. The only e#ception is a coo!ie which can be used by many pages to pass information between them even after the pages have been closed. 'efore we go any further let me say2 JavaScript has nothing to do with Java. If we are honest JavaScript originally nic!named /ive)ire and then /iveScript when it was created by "etscape should in fact be called 3+.Ascript as it was renamed when "etscape passed it to the 3+.A for standardisation. JavaScript is a client side interpreted ob4ect oriented high level scripting language while Java is a client side compiled ob4ect oriented high level language. "ow after that mouthful here's what it means. +lient side 5rograms are passed to the computer that the browser is on and that computer runs them. The alternative is server side where the program is run on the server and only the results are passed to the computer that the browser is on. 3#amples of this would be 5-5 5erl AS5 JS5 etc. Interpreted The program is passed as source code with all the programming language visible. It is then converted into machine code as it is being used. +ompiled languages are converted into machine code first then passed around so you never get to see the original programming language. Java is actually dual half compiled meaning it is half compiled 0to 'byte code'1 before it is passed then e#ecuted in a virtual machine which converts it to fully compiled code 4ust before use in order to e#ecute it on the computer's processor. Interpreted languages are generally less fussy about synta# and if you have made mista!es in a part they never use the mista!e usually will not cause you any problems.

Scripting This is a little harder to define. Scripting languages are often used for performing repetitive tas!s. Although they may be complete programming languages they do not usually go into the depths of comple# programs such as thread and memory management. They may use another program to do the wor! and simply tell it what to do. They often do not create their own user interfaces and instead will rely on the other programs to create an interface for them. This is %uite accurate for JavaScript. )e do not have to tell the browser e#actly what to put on the screen for every pi#el we 4ust tell it that we want it to change the document and it does it. The browser will also ta!e care of the memory management and thread management leaving JavaScript free to get on with the things it wants to do. -igh level )ritten in words that are as close to english as possible. The contrast would be with assembly code where each command can be directly translated into machine code. 6b4ect oriented See the section on 'ob4ect oriented programming' for details.

How is JavaScript constructed

The basic part of a script is a variable literal or ob4ect. A variable is a word that represents a piece of te#t a number a boolean true or false value or an ob4ect. A literal is the actual number or piece of te#t or boolean value that the variable represents. An ob4ect is a collection of variables held together by a parent variable or a document component. The ne#t most important part of a script is an operator. 6perators assign literal values to variables or say what type of tests to perform. The ne#t most important part of a script is a control structure. +ontrol structures say what scripts should be run if a test is satisfied. Functions collect control structures actions and assignments together and can be told to run those pieces of script as and when necessary. The most obvious parts of a script are the actions it performs. Some of these are done with operators but most are done using methods. .ethods are a special !ind of function and may do things li!e submitting forms writing pages or displaying messages.

3vents can be used to detect actions usually created by the user such as moving or clic!ing the mouse pressing a !ey or resetting a form. )hen triggered events can be used to run functions. /astly and not %uite so obvious is referencing. This is about wor!ing out what to write to access the contents of ob4ects or even the ob4ects themselves. As an e#ample thin! of the following situation. A person clic!s a submit button on a form. )hen they clic! the button we want to chec! if they have filled out their name in a te#t bo# and if they have we want to submit the form. So we tell the form to detect the submit event. )hen the event is triggered we tell it to run the function that holds together the tests and actions. The function contains a control structure that uses a comparison operator to test the te#t bo# to see that it is not empty. 6f course we have to wor! out how to reference the te#t bo# first. The te#t bo# is an ob4ect. 6ne of the variables it holds is the te#t that is written in the te#t bo#. The te#t written in it is a literal. If the te#t bo# is not empty a method is used that submits the form.
Examples

All e#amples on this page and elsewhere in my JavaScript tutorial are provided free of charge. 5lease see theterms and conditions page for terms of use. These e#amples are all useful in their own right but when used together can produce spectacular results. I will leave that to your own creativity. "ote that the synta# highlighted source of all the header files I use in these e#amples as well as several others is available on my JavaScript libraries page. The header files can also be downloaded from there. The header file scripts are meant to be real scripts for real use not tutorials. I have included them on this page as they can be viewed as e#amples of real programming not lessons on how to program. I agree that they are not always easy to read but that is mainly because they are optimised for real use. *ou may choose to see this as a bad programming method but I do not as I can always see what I was intending for the script to do and it helps to cut down on the transmitted file si7e something which modem users are always happy for. To give you an e#ample of a more 'friendly' format which is easier to use as a learning aid one of my readers has !indly produced a reformatted version of my generic re-writable elements script which is included in the email they sent me.

Non DHTML

The most popular use of JavaScript; changing images when the mouse hangs over a link

5reloading images for use in mouseovers and pre-caching.

The next most popular use of JavaScript; opening new browser win ows

6pening a window with customisable settings.

The next most popular use of JavaScript; writing !namic content

+hanging what is written depending on conditions.

The next most popular use of JavaScript; checking forms

Form chec!ing ensuring a form is filled in correctly.

Slightl! less use but "ust as useful# retaining variables from one page for use on another page

+omplicated string manipulation ta!ing variables from the location bar. +reating reading and modifying coo!ies.

Some specialist scripts


Form manipulation offering the correct countries for a continent. .ore form manipulation e#pandable tree structure.

The most irresponsible script

'rowser sniffing - to be used only to help avoid browser specific bugs not to determine

capability.

DHTML

$ppearing % isappearing content


5opup .enus. 5opup .enus with delay - see 8ec!o engine bug. Auto-generation 5opup .enus with delay - 8ec!o engine bugs removed. Tooltips.

Movable content

Tooltips. Static logo. Falling ob4ects 0snow1. Flying stars 0changes apparent si7e of div elements1. Firewor!s 0demonstrates changing colour1. Analogue cloc!.
o o

Mouse trails

Single trail with bouncing animation. .ultiple trail with several possibilities.

&ewritable ocument content


8eneric re-writable elements. 0Simple1 message scroller.

'() D*M

Importing 9./ data files - a very advanced scripting topic. Solitaire game - a very advanced script.

These scripts any many more are included on my JavaScript libraries page. The page also contains several utility scripts which you may find useful for your )eb development. 5lease see the terms and conditions page for terms of use.

+ames 6! so they are far too complicated to be e#amples but all of the principles are the same as I have described in these tutorials. These games re%uire various different technologies li!e -T./ +SS ,-T./ etc. "ot all browsers will be able to use all of the games in particular the :, games because they are (3;* demanding on resources. The simpler games may even wor! in browsers li!e "etscape :. These games are all on my games site.
Adding JavaScript to a page

*ou can add a script anywhere inside the head or body sections of your document. -owever to !eep your document well structured there are some basic guidelines$

.ost scripts can go inside the document head. This !eeps them out of the way of the main If your script needs to run at a certain stage during page layout 0for e#ample if it uses

document content. document.write to create content1 it should be put at the correct stage of the document almost always somewhere inside the document body. If the script is very small then put it all where it will be used. If it is larger then put it inside the head inside a function and you can then call that function when you need it.

If your script is used on more than one page or if it is of any significant si7e then put it in its

own file and load it in the document head. "ot only will this help to !eep the clutter of the document but it will also help avoid potential synta# problems 0I will cover these later1. As an e#tra benefit these can be used by multiple pages allowing browsers to use their cache and saving bandwidth for you and your visitors.

ing a script to the page

To insert JavaScript into a web page use the <script> tag. *ou should use the type attribute to specify the type of script being used which in the case of JavaScript is text/javascript. It is also possible to the language attribute to say what JavaScript version you are using. In practice this number means very little to browsers. They may claim to support a specific version but will have vastly different capabilities. All JavaScript supporting browsers currently in use will support a level of JavaScript e%uivalent to JavaScript <.= 0represented as >4avascript<.=>1 or higher so this is what I will teach you in this tutorial.

'rowsers will generally choose an arbitrary version number that they will claim to support and will run any script that has either no language version number or a version e%ual to or lower than the one they claim to support. Since the language is so unreliable you should generally omit this attribute although it is common to see scripts using it. *our script can then detect if the browser is capable of running your script and it can do this a lot more accurately than the version number can. This is an e#ample of a script tag used to include a script in your page$
<script type="text/javascript"> //JavaScript goes here </script>

If your script is incapable of providing its own fallbac! but it is needed to access the page you should include support for non-JavaScript browsers by using$
<noscript> <p>This will not be displayed if JavaScript is enabled</p> </noscript>

,sing comments +omments allow you to leave notes to yourself and other people in your script and are useful as a reminder of what the script is doing and why. The double slash indicates a single line comment. 3verything after it on the same line will be ignored by the script engine. The slash-asteris! indicates a bloc! comment. 3verything after it will be ignored by the script engine until an asteris!-slash is encountered.
<script type="text/javascript">

//This is a single line comment

This is a

bloc! comment

</script>

,sing external script files *ou can also use a separate header file to contain the JavaScript 0usually ?.4s1 ma!ing it easy to share across pages$
<script src="whatever"js" type="text/javascript"></script>

)hen

using

header

files

if

you

put

any

script

code

in

between

the <script """> and </script> tags it will only be e#ecuted if the browser does not support header files 0assuming it does support the version of JavaScript shown in the language attribute if you used one1. In reality this is only for very old browsers that are not used at all any more so there is no need for anything to be put there. Scripts in header files are e#ecuted as if they were in the main page. If the script referances any e#ternal files such as images the addresses it uses are relative to the main page not the script @;I.

)ommenting out !our scripts This is not needed any more. All current browsers are aware of script tags and how to treat their contents since they have been part of -T./ since -T./ :. 'rowsers that do not understand -T./ : or scripts 0these are virtually never used now1 will display the script as if it was the content of the page. *ou can hide the script from them by commenting out your script with standard -T./ comments. 'rowsers that understand script will simply ignore these comments and will 4ust interpret the script within them. The opening comment is ignored as if it were a normal single line JavaScript comment. The closing comment will not so it needs to have a JavaScript comment put before it$
<script type="text/javascript"> <#$$

//JavaScript goes here

//$$> </script>

These -T./ comments should not be used if you are using an e#ternal script file and are not to be used anywhere else in your scripts.

Dealing with -HTML "ote that when I tal! about 9-T./ I am tal!ing about pages that are served using a content type ofapplication/xhtml%xml - the ma4ority of pages that use 9-T./ mar!up are actually served as text/htmland as a result are correctly treated as -T./ not 9-T./. The rules in 9-T./ are different. Script tags are not treated as being special. Their contents are treated as any other part of 9-T./ so various operators can be misinterpreted as part of the mar!up. To avoid this it is best to put all scripts in e#ternal script files so that they do not interfere with the page itself. If you feel the need to put something directly on the page you can declare it as +,ATA 0the default for script contents in normal -T./1$
<script type="text/javascript"> <#&'()T)&

//JavaScript goes here

**> </script>

If you feel the compulsion to comment out your script in 9-T./ you must use a more ugly structure to contain your scripts. Again this really is not needed since browsers that do not understand script

also do not understand 9-T./ but in case you want to use it 0maybe you are serving it as 9-T./ to some browsers and -T./ to others1 this is what to use$
<script type="text/javascript"> <#$$//$$><#&'()T)&//><#$$

//JavaScript goes here

//$$><#**> </script>

)ontrolling when the script is activate 'y default any script you write will be processed as the document loads. For e#ample$
<script type="text/javascript"> var my+ariable = ,-ello,. window"alert/my+ariable0. //as the doc1ment loads2 a message box saying ,-ello, will be displayed </script>

Sometimes this may be undesirable and it may be better to write functions 0see the section on )riting functions1 and activate them later. To activate JavaScript you can use -T./ events. .odern browsers can detect a vast number of events on most elements. 6lder browsers are more limited and can only detect the standard set of events on specific elements. The ones that will wor! in all browsers I have tested are$ input te#tarea select onclic! on!eydown on!eyup on!eypress onchange onfocus onblur etc. form

onsubmit onreset a onclic! onmouseover onmouseout onfocus onblur body onload onunload +hec! with the -T./ specifications on the ):+ site for more details. 'a' elements can also detect onmousemove in all current browsers but not some of the older browsers that are not used any more. For some of these older browsers such as "etscape A it is possible to compensate using a combination of onmouseover onmouseout and then document.capture3vents and onmousemove on the body 0see the section on 3vent information1. The 3vent information and more advanced ,6. events chapters of this tutorial show how to listen for more event types and obtain information from them. These are some e#amples of using events 0shown here using traditional inline event handlers - later on in this tutorial I will show you alternative ways to attach events to elements that will not re%uire you to alter your -T./1$
<a onmo1seover="name3of3f1nction/params0" href="somepage"html"> <inp1t on!eypress="my+ariable = 4.startTest/0."> <select onchange="self"location"href = this"options&this"selected5ndex*"val1e."> <body on1nload="window"alert/,bye,0">

Another

way

of

ma!ing

-T./

activate

JavaScript

is

to

use<a

href="javascript6name3of3f1nction/params0"> but in general it is best to use events so the lin!

can provide an accessible alternative if JavaScript is not available 0the event handler can prevent the browser from using the lin! normally if scripting is available1. In all these cases the script is contained within -T./ attributes and is sub4ect to the normal rules of -T./ entities. If you need to put %uotes in the script in between the %uotes in the html use the -T./ entity B%uot2 or BC:A2 for > style %uotes or if your %uotes in the -T./ are done using the ' %uotes 0which is unusual ...1 you can use BC:D2 to represent these in the script. If you need to include E or F operators you should use the Blt2 and Bgt2 entities.

Object oriented programming

*b"ects An ob4ect is a 'thing'. For e#ample a number is an ob4ect. An array is an ob4ect. *our browser window is an ob4ect. A form in your document is an ob4ect. There are hundreds more and in some cases you can create your own. 6b4ects can have ob4ects in them. For e#ample your document can have a form in it. This form is a 'child ob4ect' of the document. Therefore the document is the 'parent ob4ect' of the form. To reference the child ob4ect we have to go through the parent ob4ect eg. doc1ment"my7orm An array can have numbers in its cells. As we have already discussed the array is an ob4ect and so would be a cell within it and so is the content of the cell. )e cannot refer to the cell itself but we can refer to its contents$ my)rray&,cell name or n1mber,* for e#ample.

)lasses .or t!pes/ A class is a group of ob4ects that are similar in some way. For e#ample a number and a piece of te#t can both be stored as a variable 0in a way li!e the variables you would use in mathematical algebra1. In essence we can say that pieces of te#t and numbers are e#amples of class 'variable'. "umbers can be sub divided into two groups integers and floats 0or doubles1. Integers are whole numbers$ < = : A G -< -= etc. Floats have decimal points$ <.< -H.I G.H etc. In this case we can say that : is an instance of class variable 0sub1class number 0sub1class integer. In fact a variable is a type of ob4ect. All instances of class 'ob4ect' have a certain two methods$ toString/0and val1e8f/0. Therefore as : is an it instance will of class inherit ob4ect 0sub1class variable 0sub1class number 0sub1class integer the toString/0 and val1e8f/0 methods provided by the class 'ob4ect'. +lasses are not so important in JavaScript as they are in many other ob4ect oriented programming languages. +lasses can be created when you define your own classes of ob4ects but it is not usual to create your own 'sub'-classes.

)ollections If you need to !now what arrays are see the section on (ariables.

There are many arrays that are inbuilt into each document. The document itself is an array in certain uses. The most obvious of these collections is the images collection. To refer to images in the document
doc1ment"images&,name

we
of

use
image,*

This is a special !ind of array !nown as a collection.

0roperties Ta!e for e#ample an image. )hen we define images in -T./ we write$
<img src="frog"gif" name="my5mage" height="9:" width="9:" alt=") frog">

The properties of the image would be src name height width alt and if we also used Style Sheets we might have included several more 0li!e bac!ground-color for e#ample1. All properties are a type of ob4ect so to refer to the src of my image I would write doc1ment"images&,my5mage,*"src

Metho s There are always actions that are associated with ob4ects. For e#ample a form may be submitted or reset. The actions are methods. To submit a form in non-ob4ect-oriented programs we might writes1bmit/,name of form,0 That would simply be a function. In ob4ect oriented programming li!e JavaScript we would usedoc1ment"name8f7orm"s1bmit/0 The reason this is a method and not 4ust a function is that each form will have its own s1bmit/0 function built in which is referred to using the ob4ect oriented synta# shown above. *ou will never have to write methods in yourself unless you create your own ob4ects the browser does that for you. *ou can thin! of it li!e this$

)ith the non-ob4ect-oriented way we would tell a function to submit the form. )ith the ob4ect oriented way we would tell the form to submit itself.

If wanted you can run several methods in turn on the same ob4ect by using$

referenceToThe8bject"method9/0"method4/0"method;/0"method9again/0

In this case method< must return a class of ob4ect that has the method 'method=' etc.
Operators

The most common operators are mathematical operators2 J - & ? 0add subtract divide multiply1 for e#ample. 6perators can be split into two groups comparison operators and assignment or 'action' operators. +omparison operators test to see if two variables relate to each other in the specified way for e#ample one variable is a higher number than the other. 6ther operators perform an action on a variable such as increasing it by one. The following table gives those that are most commonly used. There are many JavaScript <.: operators such as the identity operator === and others li!e it. These are supported by all current browsers but are rarely used. 'rowsers that do not understand them will 4ust produce errors. JavaScript operators Opera tor

Uses

adds two numbers or appends two strings - if more than one type of variable is
+

appended, including a string appended to a number or vice-versa, the result will be a string

/ * % =

subtracts the second number from the first divides the first number by the second multiplies two numbers divide the first number by the second and return the remainder assigns the value on the right to the object on the left the object on the left = the object on the left + the value on the right - this also works when appending strings the object on the left = the object on the left - the value on the right number on the left must be greater than the number on the right - this also

+=

-= >

JavaScript operators Opera tor

Uses

works with strings and values number on the left must be less than the number on the right - this also works with strings and values number on the left must be greater than or equal to the number on the right this also works with strings and values number on the left must be less than or equal to the number on the right - this also works with strings and values increment the number decrement the number the numbers or objects or values must be equal the numbers or objects or values must not be equal bitwise leftshift bitwise rightshift bitwise !"

<

>=

<=

++ -== != << >> & | ^ ~ ! && ||

bitwise #$ bitwise %#$ bitwise !#& logical !#& 'the statement must not be true( logical !" 'both statements must be true(

logical #$ 'either statement must be true(

JavaScript operators Opera tor

Uses

in

object or array on the right must have the property or cell on the left

"ote if you do not set the lang1age="javascript9"4" attribute in the EscriptF tag : == false ==
,, and1ndefined == n1ll.

If you do set the language attribute to ,javascript9"4,

.o7illa&Firefo# and other 8ec!o browsers 0but none of the other ma4or browsers1 will change this so that none of these will e%uate to each other. Since the attribute is deprecated anyway and the JavaScript versions were never standardised you should not rely on this behaviour. There are also a few operators that can also be used li!e functions$ void
void statement or void/statement0 0see the section on writing functions1

typeof
typeof variable or typeof/variable0 returns the type 0or class1 of a variable.

eval
eval/string0 interprets a string as JavaScript code.

There are also the 'var' 'new' and 'delete' operators. See the section on variables for e#amples of their uses. Also see the section on the .ath ob4ect operators below. "ote that JavaScript has no logical 96; operator. If you need that functionality see my separate 96; article.

*perator prece ence If you as! JavaScript to perform a calculation using multiple operators those operators will be evaluated in a specific order. For e#ample ; % <
= is calculated as / < = 0 % ; because the ? / > % $ % 0where the

is calculated before the J. The order in which these are evaluated is$

second J is appending strings1. To change the order in which they are calculated use parenthesis 0 1

as the contents of parenthesis are calculated before the contents outside the parenthesis. For e#ample ; % <
= = ?@ but/ ; % < 0 = = <;

The Math ob"ect metho s In reality these are methods of the .ath ob4ect but they are used in place of operators. )ath object methods Operator
Math.abs(n) Math.acos(n) Math.asin(n) Math.atan(n)

What it does $eturns the absolute value of n $eturns 'in radians( cos-* of n $eturns 'in radians( sin-* of n $eturns 'in radians( tan-* of n $eturns the angle 'rads( from cartesian coordinates +,+ to n,k $eturns n rounded up to the nearest whole number $eturns cos n 'where n is in radians( $eturns en $eturns n rounded down to the nearest whole number $eturns ln'n(

Math.atan2(n,k)

Math.ceil(n)

Math.cos(n) Math.e !(n)

Math."loo#(n)

Math.lo$(n)

!ote, to find log*+'n(, use )ath,log'n( )ath,log'*+(

Math.%a (a,b,c,...) $eturns the largest number Math.%in(a,b,c,...) $eturns the smallest number

)ath object methods Operator


Math.!o&(n,k) Math.#an'o%()

What it does $eturns nk $eturns a random number between + and * $eturns n rounded up or down to the nearest whole number $eturns sin n 'where n is in radians( $eturns the square root of n $eturns tan n 'where n is in radians(

Math.#o(n'(n)

Math.sin(n) Math.s)#t(n) Math.tan(n)


Variables

(ariable types are not important in JavaScript. They may be interchanged as necessary. This means that if a variable is a string one minute it can be an integer the ne#t. The basic variable types are$ character 'a' or 'K' or '!' etc. string 'hdttgs L -AMhs 01 8et the idea' integer G or < or = or : or A etc. or -< or -= or -: or -A etc. float 0or double1 =:.HAM or -<G.AM boolean true or false function

A function2 see the section on Functions ob4ect An ob4ect2 see the section on 6b4ect oriented programming array A type of ob4ect that can store variables in cells 0see below1 undefined A variable that has not been given a value yet null A variable that has been defined but has been assigned the value of null Integer and float are grouped together as 'number'. +haracter and string are grouped together as 'string'. @se the typeof operator to find out which variable type your variable is. "ote typeof will return 'ob4ect' for arrays and null.

Defining variables See the section on ';eferencing' subsection 'Avoiding referencing conflicts' to see how to choose names for your variables.

Normal variables It is good practice to pre-define all variables using the var !eyword. It is possible to define the variable leaving its value undefined or assigning a value immediately or even to define multiple variables in a single command$
var variablename. var variablename = val1e. var vari9 = val1e2 vari4 = another+al1e2 vari;.

JavaScript is fairly lenient and will create a global variable if you forget to use the 'var' !eyword but you assign a value to an undeclared variable 0if you attempt to read the value of an undeclared variable it will throw an error as discussed below1. -owever this can lead to problems if you end up accidentally overwriting variables from another scope 0this will be covered in the chapter on Functions1. 6nce a variable is defined do not use ,var variablename, again unless you wish to completely overwrite the variable. It ma!es no sense to redeclare a variable with the var !eyword within the same scope but browsers will not complain if you do it. These are some e#amples of how to define variables in this case a string a number and a regular e#pression$
var my7ish = ,) fish swam in the river,. var myA1mber8fBoats = 4;. var myCattern = /<&D>* E&D<* >/gi.

"ote that variables can be defined at any point in your script including inside a control structure that causes that statement never to be e#ecuted. -owever no matter where you choose to define your variable the JavaScript engine will create the variable at the start of the current scope. It will hold the value 1ndefineduntil a statement is e#ecuted that gives it a value.

*b"ects

)ebT( =.M- does not support the NO synta# for creating ob4ects.

If you want to create variables that you want to be able to give child properties to you must define the variable as an ob4ect. To define a variable as an ob4ect use either the new
8bject/0 or FG synta#$ var variableAame = new 8bject/0. var variableAame = Fmy7irstCroperty692myAextCroperty6,hi,2etcG.

*ou can then assign child ob4ects or properties to that ob4ect as you want$
variableAame"aCropertyAame5HadeIp = ,hello,. variableAame"a'hild8bjectAame5HadeIp = new 8bject/0.

"ote that if you want to run a method on an ob4ect that you 4ust created for true JavaScript <.= compliance you must surround the ob4ect declaration with brac!ets 0early "etscape A will have problems otherwise1. This e#ample will not wor! in early "etscape A and other browsers made at the same time$
new (ate/0"getTime/0

This e#ample will wor! in all JavaScript supporting browsers$


/ new (ate/0 0"getTime/0

This applies to all ob4ect types li!e Array Image 6ption 6b4ect ,ate and ones you create yourself.

$rra!s

)ebT( =.M- does not support the PQ synta# for creating arrays.

Arrays are similar to the 6b4ect we have 4ust defined but with some small differences. I li!e to thin! of arrays as bo#es. Inside the bo# there are several compartments or cells. )e can vary the number of compartments. To refer to the contents of a compartment we write the name of the bo# then we write s%uare brac!ets inside which we put the name or number of the compartment. To create an array use either the new )rray/0 or &* synta#$
var name8f)rray = new )rray/0. var name8f)rray = new )rray/,content3of3first3cell,2,and3the3second,2J2,blah,2,etc,0. var name8f)rray = &,content3of3first3cell,2,and3the3second,2J2,blah,2,etc,*.

*ou can also use a number as a parameter when creating the array ob4ect. If the number is a positive integer an array will be created with that many cells all of which will be empty$ new
)rray/@0. "ote that if you set the language version to 4avascript<.= some browsers 0but not all1 will

create an array with a single cell containing the number H. To refer to the contents of its cells use the synta# name8f)rray&name3or3n1mber3of3entry* 0if using names instead of numbers the name should be in %uotes1. "umeric arrays start at G not < so the first cell is number G.

In JavaScript arrays and ob4ects are almost e%uivalent and accessing a named cell of an array is the same as accessing a property of an ob4ect. If a cell of an array is called 'mycell' you could use either of these to access its contents$
name8f)rray&,mycell,* name8f)rray"mycell

There are some important differences between arrays and ob4ects. 'y default arrays have far more methods attached to them for stepping through the array or splitting it into pieces. In addition if numbers are used for entries you can find out how many entries 0or variables1 the array is holding using name8f)rray"length It is possible to create multi-dimensional arrays by creating aditional arrays as the contents of the cell of another array$
var name8f)rray = new )rray/new )rray/9242;2?02,hello,2&,a,2,b,2,c,*0.

*ou can refer to the cells of that array using the s%uare brac!et notation twice 0or multiple times depending on how many dimensions your array has1$
name8f)rray&name3or3n1mber3of3entry*&name3or3n1mber3of3inner3entry*

*ther t!pes of ob"ects 'rowsers will have many built in types of ob4ects. All JavaScript capable browsers will provide the following aditional ob4ect types$ ,ate +reates a date ob4ect which can perform calculations based on the date for e#ample$
var mydate = new (ate/0. window"alert/ ,The year is, % mydate"get71llKear/0 0.

Image

+reates an image that is not visible but is stored in cache. Setting the src attribute of the image causes the image to be loaded and stored in the browser's cache$
var myimage = new 5mage/0. myimage"src = ,thing"gif,.

"ow

each

time

want

to

change

an

image

on

the

page

can

saydoc1ment&,imagename,*"src = myimage"src. and the image will change without having to wait for the new image to load. 6ption +reates an option that can be added into a select input for e#ample$
var myoption = new 8ption/,text,2,val1e,0. select5np1t"options&select5np1t"options"length* = myoption.

See the section on '+reating ob4ects' for how to create your own ob4ects that are not one of the predefined ob4ect types. ,6. compliant browsers will provide far more ob4ect types - these will be covered in later chapters of this tutorial.

Deleting properties 6n several occasions here I have created properties for ob4ects. 3ven if these are set to undefined or null they still e#ist holding that new value and will be found using the for-in control structure. *ou can delete them completely by using the 'delete' !eyword$
delete my8bject"itsCroperty.

6f course unless you have serious computer memory considerations or security ris!s it is usually not necessary to do this at all since JavaScript engines clean up after themselves once the variable is no longer referenced.

$voi ing errors with variables If at any time you refer to a variable that does not e#ist you will cause an error. -owever JavaScript allows you to refer to one level of undefined child properties of an ob4ect. This is a very important rule to learn as it forms the basis of ob4ect and capability detection and is fundamental to ma!ing cross browser scripts. The following series of e#amples will demonstrate what will throw errors$
var my8bject = new 8bject/02 non8bject = ,,2 non8bject4.

This sets everything up for the following e#amples. So far everything is fine but in the code below b is undefined. This will cause an error$
var a = b % @.

In the ne#t e#ample the parent ob4ect has been defined but its property has not. Since this is only one level of undefined properties this is allowed and will not cause an error$
var b = my8bject"my'hild.

In the ne#t e#ample the parent ob4ect has been defined but its property has not. Trying to refer to a child of the non e#istent property means there are now two levels of undefined properties. This will cause an error$
b = my8bject"my'hild"its'hild.

In the ne#t e#ample the parent ob4ect has been defined but it is a type of variable that cannot accept child properties. Trying to create a child property will not throw an error since it is only one level of undefined properties. -owever it will not do anything since the new property will be re4ected$
non8bject"its'hild = =. window"alert/non8bject"its'hild0. //This will alert ,1ndefined,

In the ne#t e#ample the parent ob4ect has been declared but it was not given a value. As a result it holds the value undefined. Trying to refer to a child property means there are now two levels of undefined properties and will throw an error$
non8bject4"its'hild = =.

&eferencing a variable or "ust its value If you assign one variable to another there are cases where this merely copies the value in one variable and 'pastes' it into the other but there are also cases where instead of copying the variable it 4ust provides you with a new way to reference that variable. The following is an e#ample of where this might occur$
var myAew+ariable = my8ld+ariable.

If my8ld+ariable was already defined as a string number boolean null or undefined it would simply have copied my8ld+ariable and 'pasted' it into myAew+ariable. If the new variable were changed 0for e#ample using myAew+ariable = ,some new val1e,.1 my8ld+ariable retains its old value. If on the other hand my8ld+ariable was already defined as a function array ob4ect or

option myAew+ariable would have been created as a pointer to my8ld+ariable. The children of my6ld(ariable would now also be the children of my"ew(ariable. If the new variable were changed 0for e#ample usingmyAew+ariable
= ,some new val1e,.1

it would only alter the value

of myAew+ariable so that it no longer references the same contents as my8ld+ariable. -owever changing the child properties ofmyAew+ariable will change the properties of the ob4ect it references and as a result my8ld+ariable would also see the change$
var my8ld+ariable = new 8bject/0. var myAew+ariable = my8ld+ariable. myAew+ariable"new'hild = ,-ello,. alert/my8ld+ariable"new'hild0. //This will alert ,-ello,

More about numbers JavaScript understands numbers in several formats allowing you to specify numbers in he# decimal and octal. If a G precedes a number and there is no number higher than I the number is considered to be in octal 0base L1 and if the number is preceded by G# then it is considered to be in he# 0base <M1 and can also contain characters A ' + , 3 F. "either may contain decimal points. )ith decimal numbers 94e%? may be used to replace <=#<GA and 94e$? may be used to replace <=#<G-A etc. There are a few numbers that are held by the .ath ob4ect and can be used as variables with the e#ception that you cannot assign values to them. These are !nown as constants. There are some constants available that give the document area of the window that is available for writing to. These re%uire specific referencing to obtain and so have been included in the section on referencing items ob4ects and elements subsection ')indow si7e'. The available .ath ob4ect constants are$ )ath object constants Math object property
Math.* Math.+,2 Math.+,-. Math.+/02* Math.+/0-.* Math.12

Value (approx) .,/*0 +,123 .,3+3 *,44. +,434 3,*4.

Mathematical equivalent e ln'.( ln'*+( log.'e( log*+'e( 5i 'sqrt'.((-* or sqrt'*-. ( sqrt'.(

Math.3456-72

+,/+/

Math.34562

*,4*4

Special string characters There are a few string characters that can be escaped with a bac!slash and can be used to replace untypeable characters. These are$ Rn A newline character. @se this if you want to insert a line brea! into te#t. Rf A form feed. Try not to use this ever. @se Rn instead. Rr A carriage return. Try not to use this ever. @se Rn instead. Rt A tab character. RR A R character R& A & character 0most web developers Pmyself included on occasionQ forget this one - generally browsers will have no trouble with you forgetting the bac!slash but it is important for representing closing tags and in theory you should always use the bac!slash escape when writing a forward slash - see the section on )riting with script for details of where it is needed1 If you need to recognise a )indows linebrea! you need to loo! for RrRn. If you are trying to add a linebrea! 0for e#ample when modifying the value of a te#tarea input1 you should insert a Rn character. This will wor! cross browser. "ote that browsers on )indows may convert this Rn character into a RrRn automatically depending on where you use it. 6ld .ac 6perating Systems 06S D and below1 used Rr for linebrea!s but as far as my tests showed they are converted to Rn by JavaScript. -owever 4ust be aware that you may encounter some of these especially in te#t inputs 0.ac 6S D is still popular among .ac users - probably a little less than HGS of the .ac mar!et1. @ni# based 6perating Systems 0including .ac 6S 91 use Rn for linebrea!s.

If you are writing a string that contains double %uotes the easiest way to deal with it is to surround it with single %uotes. *ou should also use double %uotes if your string contains single %uotes$
var mystring = ,)nd he said "help" twice,. var mystring = "-elp )ndy,s cat".

*ou may notice a problem. )hat if you have both single and double %uotes in your stringT The solution is to use the escape character 'R' to e#cape the %uotes 0in fact you can always escape %uotes even if the string is delimited by the other type of %uotes1. For e#ample both of the following are valid$
var mystring = ,)nd he said "help )ndyL,s cat" twice,. var mystring = ")nd he said L"help )ndy,s catL" twice".

If your string becomes too long to fit on one line 0this really doesn't matter - you can ma!e the te#t as long as you want1 and you want to split it onto several lines simply end the string follow it with the concatenation operator J and start a new string on the ne#t line$
var mystring = ,first line of the string , % ,still on the first line of the string $ itL,s li!e we never bro!e the line,.

"ote in theory you can use R to brea! the string$


var mystring = ,li!e L this,.

'ut this has significant problems2 the R will not always cope with trailing whitespace may or may not correctly treat the leading whitespace before the new line and does not wor! correctly in all JavaScript implementations$

"etscape A 0inventors of JavaScript1 3scape 6pera I.M- and I+3browser include the Internet 3#plorer .o7illa&FireFo# 6pera LJ Safari&Uon%ueror i+ab and 6mni)eb ignore

linebrea!s in the string. the linebrea! characters.

I+3browser sometimes ignores the whole string

I mention this only for completeness. ,o not use it. It is easier and better to use the concatenation operator as shown above.

&egular expressions

6pera A-M has a ma4or bug in its regular e#pression handling and will fail on even the simplest regular 5oc!et Internet 3#plorer Internet 3#plorer for )indows +3 and i+ab =- do not support regular e#pressions

e#pressions. properly.

+ertain methods li!e the string8bject"replace/0 and string8bject"match/0 methods can recognise patterns in te#t. To do this they use regular e#pressions. These are well documented elsewhere so I will not describe the synta# here. 'asically what you can do is use special characters to recognise te#t patterns 0li!e Rw for characters a-7 A-V G-D and W1. To define a collection of characters as a regular e#pression you use the & character 0sometimes with a g or i after it1. For e#ample the regular e#pression /L/L &LwLM* L L//matches bloc! comments. Some rare browsers do not support regular e#pressions. In theory you should be able to detect regular e#pression support using this$
if/ window"NegOxp 0 F var myNeg1larOxpression = new NegOxp/"pattern"0. G

This should not produce errors in 5oc!et Internet 3#plorer and Internet 3#plorer for )indows +3 0as they do not understand the &pattern&options synta# or support the ;eg3#p ob4ect1. -owever as 6pera M- and i+ab =- support the ;eg3#p ob4ect but fail to use it correctly your scripts will still fail though hopefully without errors. Than!fully current releases of 6pera and i+ab do support regular e#pressions correctly.
ontrol structures

The 1if1 statement


if/ my+ariable == 4 0 F my+ariable = 9.

G else F my+ariable = :. G

If my(ariable had been = it would now be <. If it had been anything other than = it would now be G. 'If' statements can also test for the occurence of a child ob4ect of an ob4ect that may not e#ist. For e#ample some browsers provide doc1ment"body"style while some older browsers do not even providedoc1ment"body. In these browsers writing 'if/ doc1ment"body"style 0' would 4ust produce an error 0see the section on '(ariables' subsection 'Avoiding errors with variables'1. In order to solve this problem we could write this$
if/ doc1ment"body 0 F if/ doc1ment"body"style 0 F etc" G G

-owever the PP operator has a useful feature that we can use here to combine the two 'if' statements into one$
if/ doc1ment"body PP doc1ment"body"style 0 F etc" G

The first test would be false so the browser would not proceed to the second. This is !nown as a short-circuit. The QQ operator has a similar feature but it will only evaluate the second test if the first one fails. JavaScript understands that if the 'N' and 'O' 0curly brace1 characters are left out then only the ne#t command belongs to that statement$
if/ x < @ 0 x%%. window"alert/x0.

-ere the alert will always happen reguardless of # but # will only be incremented if # is less than H. This may seem convenient as it allows you to ma!e your code a tiny bit shorter but I recommend

avoiding this synta#. It ma!es your code harder to read especially if you start nesting your control structures. It also ma!es it easy to forget to put them in when you needed them and also ma!es debugging code much harder since you will need to go bac! through your code to add them so that you can add e#tra debugging tests. It is best to always use the curly braces even if they are optional. As always there is an e#ception. "ested 'if' statements li!e this can start to get difficult to manage$
if/ my+ariable == 4 0 F my+ariable = 9. G else F if/ my+ariable == @ 0 F my+ariable = ;. G else F my+ariable = ?. G G

'y strategically removing curly braces that can usefully be reduced to this construct 0which you may recognise from other programming languages1 - note that 'else if' is not written as 'elseif'$
if/ my+ariable == 4 0 F my+ariable = 9. G else if/ my+ariable == @ 0 F my+ariable = ;. G else F my+ariable = ?. G

The 1for1 loop This is one of the most common constructs in use. Typically it is used to cycle through the contents of an array or to create a specific number of new ob4ects but it can do many more useful things if needed. The synta# of the 'for' loop is as follows$
for/ starting3initialise. contin1e3as3long3as3condition. do3this3each3time 0

startingWinitialise This is where you define new variables that you will use in the loop typically for use with incremental counting. As with all variables you must declare them 0if you have not done so already1. *ou can define multiple variables if needed using$
var my+ariable9 = val1e2 my+ariable4 = another3val1e.

These variables are not restricted to being inside the 'for' loop and will be available to all code after the loop 0in the same scope as the loop1. continueWasWlongWasWcondition This is where you define the conditons under which the loop should continue to e#ecute. The synta# is e#actly the same as for the 'if' statement so you can apply more than one continue condition by using the BB or XX operators$
my+ariable9 <= @ PP my+ariable4 >= =:.

If the condition is not satisfied when the for loop begins then it will never loop through it. doWthisWeachWtime 6nce the end of the loop is reached it will do whatever you tell it to here. Typically this is used to increment or decrement a stepping variable and it is possible to perform actions on more than one variable by separating them with a comma$
my+ariable9%%2 my+ariable4 $= ?

The following is a full e#ample.

for/ var my+ariable = 9. my+ariable <= @. my+ariable%% 0 F my)rray&my+ariable* = 9. G

my)rray&9* to my)rray&@* are now <.

The 1for 2 in1 loop The 'for - in' loop is used to cycle through all e#posed properties of an ob4ect 0or array1. 3very time you create properties or methods on an ob4ect these will be added to the list of properties that will be e#posed. .ost internal properties 0the ones that JavaScript creates1 will also be e#posed but JavaScript engines are allowed to hide internal properties and methods if they want to. *ou should not rely on any specific behaviour here but note that some browsers will give the internal properties and methods of intrinsic ob4ects and some will not. Again you should declare the variable names that you use if you have not done so already. The synta# of the 'for - in' loop is as follows$
for/ var my+ariable in an8bject8r)rray 0 F

This will run through the loop once for each e#posed property in an8bject8r)rray. 3ach time it loops it assigns the ne#t property name as a string value to my+ariable. *ou can then use array notation to access the value of that property. The following e#ample writes all the e#posed properties of the document ob4ect$
for/ var my+ariable in doc1ment 0 F doc1ment"write/ my+ariable % , = , % doc1ment&my+ariable* % ,<br>, 0. G

"ote that if you use this loop on an array it will list the numbered and named !eys including the internal 'length' property. It is very easy to ma!e mista!es here so be careful not to mista!e these property types for each other.

The 1while1 loop The 'while' loop is identical in behaviour to the 'for' loop only without the initial setup and loop-end actions. It will continue to run as long as the condition is satisfied$
var my+ariable = 9.

while/ my+ariable <= @ 0 F my)rray&my+ariable* = 9. my+ariable%%. G

my)rray&9* to my)rray&@* are now <.

@sing a feature of the increment 0and decrement1 operator here it is possible to shorten the code inside the loop to be 4ust 'my)rray&my+ariable%%* = 9.' and it would have e#actly the same effect. Firstly it would use the value of my(ariable to inde# the array cell then it would increment my(ariable. This also wor!s in reverse2 'my)rray&%%my+ariable* = 9.'. Firstly it would increment the value of my(ariable then it would use the new value to inde# the array cell. If I had done this my)rray&4* to my)rray&<* would now be <. These features also wor! outside loops but this is where you will most commonly see them so I have included them here.

The 1 o 2 while1 loop This is similar to the while loop but with an important difference. The condition is evaluated at the end of the loop meaning that even if the condition is never satisfied it will still run through the loop at least once.
var my+ariable = 9.

do F my)rray&my+ariable* = 9. my+ariable%%. G while/ my+ariable <= @ 0.

myArrayP<Q to myArrayPHQ are now <.

The 1switch1 statement The 'switch' statement is li!e repeated 'if' statements testing a single value to see if it matches one of a set of values$
switch/my+ar0 F case 96 //if my+ar is 9 this is exec1ted case ,sample,6 //if my+ar is ,sample, /or 92 see the next paragraph0 //this is exec1ted case false6 //if my+ar is false /or 9 or ,sample,2 see the next paragraph0 //this is exec1ted defa1lt6 //if my+ar does not satisfy any case2 /or if it is //9 or ,sample, or false2 see the next paragraph0 //this is exec1ted G

If a case is satisfied the code beyond that case will also be e#ecuted unless the brea! statement is used. In the above e#ample if my(ar is < the code for case 'sample' case false and default will all be e#ecuted as well. The solution is to use brea!2 as follows 0The use of the brea! statement is described below1.
switch/my+ar0 F case 96 //if my+ar is 9 this is exec1ted brea!. case ,sample,6 //if my+ar is ,sample, this is exec1ted brea!. case false6 //if my+ar is false this is exec1ted brea!. defa1lt6 //if my+ar does not satisfy any case2 this is exec1ted //brea!. is 1nnecessary here as there are no cases following this G

The 1with1 statement Ta!e for e#ample the following e#ample$


x = Hath"ro1nd/ Hath"RA4 % Hath"O % Hath"pow/ y2 ? 0 0.

@sing the 'with' statement this can be replaced with$


with/ Hath 0 F

x = ro1nd/ RA4 % O % pow/ y2 ? 0 0. G

"ote that the 'with' statement brings e#tra variable names into the current scope. In the e#ample above if I already had a variable called pow before the 'with' statement this variable would be unavailable inside the with statement as it would have been replaced by the method of the Hath ob4ect 0as would any other variables that matched property or method names1. 6nce the 'with' statement is complete the old variables would become available again.

The 3uick 1if1 statement This is !nown as the conditional or ternary operator and is an easy way to assign different values to a variable depending on a condition.
var my+ariable = doc1ment"getOlementSy5d T 9 6 :.

This is identical to$


if/ doc1ment"getOlementSy5d 0 F var my+ariable = 9. G else F var my+ariable = :. G

The tr! 2 catch 2 finall! statement

it. "etscape A Internet 3#plorer A and )ebT( do not support this structure and will produce errors if you use

The 'try - catch - finally' control stucture allows you to detect errors and %uietly deal with them without producing error messages or aborting the script and in fact without even interrupting the

flow of the script that is running. This ma!es it superior to the original way of handling script errors 0without error messages1 where scripts are completely aborted$
window"onerror = referenceTo71nction.

The synta# of the 'try - catch - finally' control stucture is as follows$


try F //do something that might ca1se an error G catch/ myOrror 0 F //if an error occ1rs2 this code will be r1n //two properties will /by defa1lt0 be available on the //object passed to the statement alert/ myOrror"name % ,6 , % myOrror"message 0. G finally F //optional $ this code will always be r1n before the //control str1ct1re ends2 even if yo1 rethrow the error //in the catch G

If an error occurs in the 'try' section it immediately 4umps to the 'catch' part passing some information about the error. ,ifferent browsers provide different information for the same error so don't trust it 0in theory ,6. browsers will use a specific set of error types but this depends on their level of ,6. support - Internet 3#plorer is the least compliant here1. 6nce the 'try' or 'catch' parts have been run the 'finally' part is run if you have provided one then the script following the control structure is run unless you throw another error. If you nest these statements 0one 'try - catch' inside another1 you can rethrow the error from the 'catch' part of the inner statement to the 'catch' part of the outer statement 0the 'finally' part - if there is one - would still be run before the outer 'catch' is run but the script following the inner structure will not be run1. This is done using the ,throw, method$

tryF //"""some other code goes in here try F var a = nonexist"b. //this will prod1ce an error G catch/myOrror0 F //this catches the error and alerts the message alert/ myOrror"message 0. //re$throw the error 1p to the o1ter try $ catch throw/ myOrror 0. G //"""some other code goes in here G catch/ myOrror8bject 0 F //5 re$threw the first error2 so this is the same error object //the message sho1ld be the same alert/ myOrror8bject"message 0. G

*ou can also throw your own errors at any point by creating an ob4ect with the re%uired properties and passing it as the parameter when using throw$
tryF var myOr = new 8bject/0. myOr"name = ,Hy error,. myOr"message = ,Ko1 did something 5 didnL,t li!e,. throw/ myOr 0. G catch/ detectedOrror 0 F

alert/ detectedOrror"name % ,Ln, % detectedOrror"message 0. G

'hat is wrong with it4 It's lac! of support in older browsers is its ma4or failing. Than!fully these browsers are hardly used any more. It would be very useful to use this structure detect errors in "etscape A 0li!e the 'this' !eyword J inline method bug - for e#ample - there are lots more errors1 but that browser does not support the statement. It would also be useful for chec!ing for stupid bugs li!e where chec!ing for something li!e navigator"taintOnabledcauses errors in Internet 3#plorer. -owever the error is not correctly thrown for these errors. @nfortunately if you use this structure in any script run by a browser that does not support it the browser will abort the entire script with errors even if it does not use the part containing the structure. It should never be used to detect if a browser supports a method or property

li!edoc1ment"getOlementSy5d as a proper ob4ect detect would suffice.

So when shoul it be use 4 It can be used for ):+ ,6. scripting where you may want to avoid ,6. mutation errors 0for e#ample1 which are valid errors but serve to warn you not to do something and do not always need to abort the whole script. 6lder browsers do not support the ,6. anyway so it doesn't matter if they don't understand this part of it. -owever they will still run the script 0it is not possible to protect them by using the language attribute on the script tag as you need to use JavaScript <.= - not anything higher - to enable Internet 3#plorer H support1. This means that the older browsers will still produce errors unless you define the old error handling method in an earlier script. It can be used for throwing your own errors if you create the 'error' deliberately under certain circumstances. It can be used to chec! if accessing a frameset frame will cause a browser security error 0for e#ample if the page in the frame belongs to another site1. It could also enable you to avoid problems where different browsers support the same methods but e#pect a different synta# for e#ample the selectSox"add method 0I did not include this method in my ,6. section of the tutorial due to this problem1$

try F selectSox"add/option8bject2other8ption8bject0. G catch / e 0 F selectSox"add/option8bject2index0. G

)on itionals without a con ition4 *ou may notice in the e#ample for >The %uic! 'if' statement> that I tested for a property without testing for any specific value$ 'if/ doc1ment"getOlementSy5d 0' That is valid and is one of the most useful parts of JavaScript. This is a very important rule to learn as it forms the basis of ob4ect and capability detection and is fundamental to ma!ing cross browser scripts. This will be true if$
doc1ment"getOlementSy5d #= "" PP doc1ment"getOlementSy5d #= : PP doc1ment"getOlementSy5d #= false PP doc1ment"getOlementSy5d #= 1ndefined PP doc1ment"getOlementSy5d #= n1ll

The opposite is also possible$ 'if/ #doc1ment"getOlementSy5d 0' This will be true if$
doc1ment"getOlementSy5d == "" QQ doc1ment"getOlementSy5d == : QQ doc1ment"getOlementSy5d == false QQ doc1ment"getOlementSy5d == 1ndefined QQ doc1ment"getOlementSy5d == n1ll

@sing this you can detect one type of capability and if it fails detect another type and continue until you find one that wor!s. *ou can also do this anywhere where a condition is e#pected such as with the 'while' loop condition the'do - while' loop condition and the 'continueWasWlongWasWcondition' in the for loop.

)hecking for properties with 1in1



)ebT( crashes if you use the 'in' operator to chec! for a property that does not e#ist. "etscape A Internet 3#plorer H.G- on )indows and Internet 3#plorer on .ac cannot use the 'in' operator as

shown here.

The 'in' operator used in the 'for - in' loop has another purpose. It can also be used to chec! for the e#istence of named properties of an ob4ect. In most cases it is best to use a conditional without a condition as shown above. -owever there are some cases where you want to test for the e#istence of a property even thought the property's value may be one that does not evaluate to true. An e#ample would be where you want to chec! for the e#istence of a property whose value may be G or an empty string or null. If you !now what the type of the property will be it is possible to achieve this using identity operators or thetypeof operator as shown here$
if/ typeof/ doc1ment"body"inner-THR 0 == ,string, 0 F

-owever it is also possible to use the 'in' operator to test for a property. This allows you to test for its e#istence no matter what value it currently holds and no matter what type of value it currently has 0even if it has been assigned a value of 1ndefined1. In the 'for - in' loop the 'in' operator returned the name of properties as a string and so here it e#pects the name to be a string. This limits the usefulness a little as it can only search for the name and cannot be used to see if one of the properties holds a specific value or value type.
if/ ,inner-THR, in doc1ment"body 0 F

"ote that this is around =G times slower in Internet 3#plorer than the conditional without a condition as shown above. In most other browsers the two alternatives perform about the same. In general I consider it best to use the more common alternatives unless you have a specific use that needs the behaviour of the 'in' operator.

$ssignments insi e a con itional JavaScript allows you to perform an assignment at the same time as testing if the assignment wor!ed. This can be used inside any conditional including inside an 'if' 'for' 'while' and 'do - while'.
if/ x = doc1ment"getOlementSy5d/,mydiv,0 0 F"""G do F alert/ node"tagAame 0. G while/ node = node"parentAode 0.

"ote that Internet 3#plorer on .ac will produce an error if you try to do this with an array when it steps off the end of the array.

)ontinue an break statements an labels

Labels /abels are used to name the 'while' 'do - while' 'for' 'for - in' and 'switch' control structures. The synta# used is$
RabelAame6 'ontrol Str1ct1re

/abels are very rarely used in JavaScript.

The break statement )riting brea! inside a switch for for-in while or do - while control structure will cause the program to 4ump to the end of the statement. If you 4ust use for e#ample$
for/ var x = 9. x < @. x%% 0 F var y = 9. while/ y < = 0 F

y%%. if/ y == @ 0 F brea!. G doc1ment"write/y0. G G

The script will 4ump past the end of the while loop when y is H. 'ut if you use this$
my7orRoop6 for/ var x = 9. x < @. x%% 0 F var y = 9. while/ y < = 0 F y%%. if/ y == @ 0 F brea! my7orRoop. G doc1ment"write/y0. G G

The script will 4ump past the end of the for loop when y is H.

The continue statement )riting continue inside a 'for' 'for - in' 'while' or 'do - while' control structure will cause the program to 4ump to the test condition of the structure and re-evaluate it having performed any 'doWthisWeachWtime' instructions. If you 4ust use this for e#ample$
for/ var x = 9. x < @. x%% 0 F var y = 9.

while/ y < = 0 F y%%. if/ y == @ 0 F contin1e. G doc1ment"write/y0. G G

This script will 4ump to the test condition of the while loop when y is H so H will never be written but M and I will be. If you use this instead$
my7orRoop6 for/ var x = 9. x < @. x%% 0 F var y = 9. while/ y < = 0 F y%%. if/ y == @ 0 F contin1e my7orRoop. G doc1ment"write/y0. G G

-ere the script will increment # as part of the for loop and then re-evaluate the for condition.
!riting wit" script

'e careful when writing with script. If script is not available that content will not be created. *ou should limit your use of this to parts of the page that are not needed to access page content. If you do write important parts of the page that are unavailable without scripting use <noscript> tags to provide an alternative. you should

'riting while the page is still loa ing If your code is being e#ecuted while the page is still loading 0in other words if it is run as part of the initial page layout1 put the following$
<script type="text/javascript"> doc1ment"write/,<p>Mhat ever yo1 want to write<L/p>,0. doc1ment"writeln/,<p>Mhat ever yo1 want to write<L/p>,0. //writeln p1ts a line brea! after the line" //This is treated as a line brea! in the so1rce of -THR </script>

It will write whatever you put in whatever part of the page the script is currently running. 6f course you can include -T./ tags in there too or some pre-programming. "ote that if you write content using an event handler 0such as the onload handler for an image1 it will be treated as if the page has completed loading even if it has not.

'riting after the page has loa e After the page has completed loading the rules change. Instead of adding content to the page it will replace the page. To do this you should firstly open the document stream 0most browsers will automatically do this for you if you 4ust start writing1. Then you should write what you want and finally you should close the document stream. Again most browsers will automatically close the stream for you. The notable e#ception here is the .o7illa&Firefo# family of browsers that will continue to show a loading graphic until you close the stream. Some other browsers may fail to render part or all of the content. Just to be safe ma!e sure you always close the stream.
<script type="text/javascript"> doc1ment"open/0. doc1ment"write/,<p>Mhat ever yo1 want to write<L/p>,0. doc1ment"write/,<p>Hore st1ff yo1 want to write<L/p>,0.

doc1ment"close/0. </script>

That will remove everything that is currently being shown and replace it with what you write in there. This is the e%uivalent of moving the user to a completely new page. *ou should put EhtmlF tags and things li!e that in there too if you want to use that method. *ou may notice that I close my -T./ tags inside the script with a bac!slash before the forward slash in the closing tag. This is a re%uirement of the specification 0and can cause the -T./ validator not to validate your page if you forget it1 although all browsers will understand if you omit the bac!slash. -owever since you can write -T./ with script you can write style or even script tags with it ma!ing one script import another. If you omit the bac!slash on any E&scriptF tags that you are writing with the script the browser will read that as the closing tag for the current script and your script will fail. The same applies to opening or closing comments 0although I fail to see why you would want to write comments using a script1. These can be written as ,<,%,#$$, and ,$,%,$>,. )hen the script runs the plus sign tells it to append the strings creating a valid -T./ comment.

0roblems with ol browsers Although not really in use any more you may want to be nice to older browsers li!e "etscape A. If using doc1ment"write to dynamically write a div element do not give the div an inline style with left$ or top$ positioning. This will cause "etscape A to fail completely and be unrecoverable without careful use of dialogs and tas! !ills. Also "etscape A will completely fail to load if you attempt to use this method to create a <div
style="position6absol1te"> and instead you should use the unnofficial <layer> tag. *ou can use if/ doc1ment"layers 0 to detect if the layer tag should be used.

!riting #unctions

+eneral s!ntax

5re-alpha versions of T!html -v: do not correctly interpret the Function class constructor.

Functions group together script code2 control structures operations method calls etc. in the same way as a normal script. These functions can then be called when needed and the code contained within them will be run. This ma!es it very easy to reuse code without having to repeat it within your script. Functions are defined using one of these constructs$ "ormal function construct
f1nction name8f71nction/list8f+ariableAames0 F f1nction code sho1ld be written here G

Anonymous function assigned to a variable @sing this synta# for ob4ect methods in early "etscape A versions will cause problems with the 'this' !eyword due to bugs.
name8f71nction = f1nction /list8f+ariableAames0 F f1nction code sho1ld be written here G.

"ormal function construct assigned to a variable


name8f71nction = f1nction anotherAame7orThe71nction/list8f+ariableAames0 F f1nction code sho1ld be written here G.

"ote that in this particular case because the function is being assigned and not defined normally the name anotherAame7orThe71nction can be used by the code inside the function to refer to the function itself but the code outside the function cannot see it at all 0note that some browsers mainly Internet 3#plorer do not implement this correctly so you should not rely on it - it is better to usearg1ments"callee as shown below1. The Function class constructor
f1nctionAame = new 71nction/"f1nction code sho1ld be written here"0.

This construct evaluates the code as a string and is much slower than assigning anonymous functions. It should only be used in places where it is actually needed. The Function class constructor with parameters
f1nctionAame = new 71nction/"varAame"2"varAame4"2"etc""2"f1nction code"0.

See the section on ';eferencing' subsection 'Avoiding referencing conflicts' to see how to choose names for your functions. Functions are called using one of these$

name8f71nction/list8f+ariables0. window"name8f71nction/list8f+ariables0. object"onOventAame = name8f71nction.

)hen created using the normal function construct the definition does not have to appear at the start of the script 0though it is usually best to do so for the sa!e of clarity1. It can even be defined after the the code that calls it. In most cases no matter where you choose to define your function the JavaScript engine will create the function at the start of the current scope. "ote that you should never create a function using the normal function construct inside an 'if' statement 0or any e%uivalent control structure1$
if/ some'ondition 0 F f1nction f1nctionAame/0 F """this will not wor! in most browsers"""

G G

This is permitted by .o7illa's JavaScript <.H but this conflicts with 3+.AScript : the core language used by JavaScript <.H. As a result .o7illa based browsers allow it and most others do not 0they will always evaluate the function even if the condition evaluates to false1. It is best not to rely on either behaviour and do not try to declare functions in this way. ,eclaring functions inside these statements is possible in all current browsers using assigned anonymous functions and this is the correct way to achieve the desired effect$
var f1nctionAame. if/ some'ondition 0 F f1nctionAame = f1nction /0 F """ G. G

0assing variables to functions (ariables passed to a function are !nown as arguments. )hen a function is called the variables or values passed to it in the brac!ets are assigned to the variable names in the brac!ets of the function definition.
f1nction chec!val/passvar0 F //if 5 ran the f1nction 1sing the command "chec!val/,hello,0" //then passvar wo1ld ta!e on the val1e ,hello, if/ passvar #= "" 0 F doc1ment"myform"mytextinp1t"val1e = passvar. G

This function when called will set the value of a te#t input to whatever value of passvar was as long as passvar was not blan!. As an e#ample part of my html will contain this$
<inp1t type="b1tton" on'lic!="chec!val/,pygmy,0">

)hen the user clic!s on the button the te#t input's value will change to 'pygmy'. *ou can pass more than one variable to a function using commas to separate the values$
f1nction f1nctionAame/variable92variable42variable;2etc"0 F f1nction code G f1nctionAame/@2<2=2etc"0.

If not enough variables are passed to fill up all of the variables in the function declaration then any remaining variables will contain the value 1ndefined. *ou can pass no variables to a function li!e this
f1nction f1nctionAame/0 F f1nction code G f1nctionAame/0.

If I called that last function using something li!e this$


f1nctionAame/9242;2my+ar2window2,stringy bit,0

The variables would still be passed to the function but I would only be able to access the variables using thearg1ments collection 0which can also be referenced as referenceTo71nction"arg1ments1. *ou can use the arg1ments collection to refer to the arguments even if you did not write the variable name in the function definition or you can mi# it so that some variable names are defined but others are only available using the arg1ments collection$
f1nction f1nctionAame/variable92variable40 F

window"alert/variable90. //alerts @ window"alert/arg1ments&:*0. //alerts @ window"alert/variable40. //alerts < window"alert/arg1ments&9*0. //alerts < window"alert/arg1ments&4*0. //alerts = window"alert/f1nctionAame"arg1ments&;*0. //alerts J G f1nctionAame/@2<2=2J0.

The arg1ments collection also has a very useful property2 arg1ments"callee. This is a reference to the function itself meaning that code running inside an anonymous function can still obtain a reference to the function that is being run. This property is not available in some older browsers.

,sing the return statement The return statement causes a function to stop e#ecuting at that point. The code that called the function will still continue to e#ecute.
f1nction doMhatever/0 F var apod = Hath"pow/;2=0. ret1rn. //the following code will not be exec1ted2 //no matter what apod = ;?. ; <= apod 0 F

if/ =:: ret1rn.

//ret1rn on its own is more 1s1ally //1sed as part of a conditional

G else F window"alert/,The script has made a mista!e,0. G G

The following is an e#ample of using the return statement to return a variable from a function$
f1nction append'omment/passvar0 F //in this case2 5 have passed a string variable and 5 ret1rn //a string variable" 5 co1ld ret1rn any variable type 5 want" passvar %= , witho1t yo1r help,. ret1rn passvar. G

var myString = append'omment/,5 did it,0. //myString is now ,5 did it witho1t yo1r help,

"ote that if you need your code to wor! in older browsers it is important to ma!e sure that if the return statement is used to return a value you must ensure that in all cases the function returns a value or some "etscape A versions will produce errors. Ta!e for e#ample the action of fading. I want to write the same thing repeatedly slowly fading from one colour to another. ;ather than having to calculate this manually I want to run some script that calculates the fade for me. The script will run nicely as part of a function where the function returns the ne#t colour at each step which I can then use. This is useful because I can then use the same function to produce a variation of the same effect later on based on different parameters.
f1nction fade'olo1r/ fromcol2 tocol2 fadeCortion 0 F //in the format fade'olo1r/ ,ff::UJ,2 ,fe:U;?,2 :"4; 0 var o7 = &*2 oT = &*2 oC = &*.

var o- = &,:,2,9,2,4,2,;,2,?,2,@,2,<,2,=,2,J,2,U,2,a,2,b,2,c,2,d,2,e,2,f,*. //get the red2 green and bl1e s1bstrings """ for/ var x = :. x < ;. x%% 0 F //""" and convert them from hex into decimal """ o7&x* = eval/ ,:x, % fromcol"s1bstring/ 4 oT&x* = eval/ ,:x, % tocol"s1bstring/ 4 x2 / 4 x2 / 4 x 0 % 4 0 0. x 0 % 4 0 0.

//""" add on the reV1ired portion of difference between the two """ oC&x* = Hath"ro1nd/ o7&x* % / / oT&x* $ o7&x* 0 //""" and convert it bac! into hex """ oC&x* = o-& / oC&x* $ / oC&x* > 9< 0 0 / 9< * % o-& oC&x* > 9< *. G //""" and p1t them bac! together again as a colo1r string ret1rn ,W, % oC"join/,,0. G fadeCortion 0 0.

for/ var y = :. y < 9:. y%% 0 F //in 9: steps2 fade the colo1r $ also see the section on writing with script doc1ment"write/ ,<span style="color6, % fade'olo1r/ ,d4cbff,2 ,::::UU,2 y / U 0 % ,.">7ade#<L/span> , 0. G

for/ var y = :. y < 94. y%% 0 F //in 94 steps2 fade the colo1r doc1ment"write/ ,<span style="color6, % fade'olo1r/ ,ff::::,2 ,::::::,2 y / 99 0 % ,.">7ade#<L/span> , 0.

FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY FadeY !arning if you are returning a value from a function do not call the function directly from the <a
href=method to activate it or many browsers will 0correctly1 create a new page containing the

returned value as the page content. *ou can still use ret1rn. on its own. *ou can only return values if you call the function script from another piece of script 0li!e another function1. If you need to call the function using the <a href= method use the void operator. "ote returning false for many events will cancel the action. As an e#ample if a user submits a form returning false will cause the form not to be submitted. The e#ception is onmouseover where returning true will stop the mouseover from having any effect 0such as with a lin! where returning true will stop the lin! url from being displayed in the status bar1.

5ariable scope (ariable scope is one of the very useful features of languages li!e JavaScript so even though it may seem a little complicated it is worth ta!ing the time to learn how it wor!s. In a basic script there may be any number of variables and functions. Ta!e the following e#ample$
var a = 92 b = 42 c = ;. f1nction sample/0 F var d. a = =. G sample/0. alert/a0.

The variables a b and c are not inside any function when they are declared so they are in a scope called the global scope. They are available anywhere. +ode anywhere else in the script including

inside thesample function has access to them. The sample function is also global since it is not inside any other functions. If any other piece of code changes the contents of those variables then every other part of the code now sees the new contents. As a result the alert here will show 'I' since the value held by the global variable is changed when the function is run. (ariable d is defined inside the sample function so it is not global. It is in the local scope of the function. )hat that means is that only the code inside the function can see it. +ode outside the function does not even !now it e#ists. This happens with any function. They have the ability to create their own scopes and their own local variables without them interfering with variables located in the global scope. (ariable names written in the brac!ets of the function definition are also created as variables in the local scope 0and the same applies to the arg1ments collection1$
f1nction sample/myvar0 F //myvar is now a variable in the local scope alert/myvar0. G sample/,hello,0.

"ow try this modification to the earlier code$


var a = 92 b = 42 c = ;. f1nction sample/0 F var a2 d. a = =. G sample/0. alert/a0.

-ere the variable a is redefined inside the function. 'ecause it is declared using the var !eyword it becomes a local instance of a variable. 3ven though it shares the same name as a global variable the two are completely independent. The changes made to that variable inside the function only affect the local variable not the global one. As a result the alert will show '<' and not 'I'.

"ow imagine that the code inside the function wants to reference the global variable ,a, instead of the local one. The global scope is special. In JavaScript the global scope can be referenced using the name,window,. The code inside this is the why function methods can li!e use window"a to alert can be reference called the using global ,a, variable. Incidentally

either alert or window"alert since these methods are globally available 0unless they are overwritten in the current scope of course1.

Neste functions It is possible to create functions inside other functions. Simply declare another function inside the code of an e#isting function$
var a = 92 b = 42 c = ;. f1nction sample/0 F var a2 d2 e. f1nction anothersample/0 F var e2 f. G anothersample/0. G sample/0.

In that e#ample the anothersample function only e#ists inside the sample function and it can only be called by the code inside the sample function. +ode outside that function does not even !now it e#ists. The scopes are also nested so the code inside the anothersample function has access to b and c from the global scope a and d from the sample scope and then e and f from its own local scope. It can also use window"ato reference the variable a from the global scope. 6f course if you assign a reference to the nested function to a global variable then the function can be accessed globally through that variable. There is not much point in doing that here but it becomes very useful when creating ob4ect methods 0these will be covered in detail in a later chapter1.

Scopes have memor! Scopes are actually very clever since they persist over time. Imagine that the code inside a function creates a local variable. It also creates an event handler function that will be triggered when the user clic!s a lin!$
f1nction sample/0 F var a = 4:. doc1ment"lin!s&:*"onclic! = f1nction /0 F alert/a0. G. G sample/0.

The action that calls the event handler 0inner1 function happens much later a long time after the script that created it has finished running. -owever the variable ,a, has survived so the alert will display the number =G.

,sing scope to prevent conflicts Imagine that you are running a script that uses many global variable and function names. *ou want to put another script on the same page but there is a chance that the two scripts will use the same variable names as each other and may conflict. It is easy to wor!around this problem by putting the code from each script inside a function and running the function. That way the local scope provided by the function will protect the variables overwriting each other in the global scope. "ote that when doing this it is very important that you remember to declare your variables properly. The easy way to do this without creating a global function is to create an anonymous function and enclosing it in parenthesis 0internally the engine will then replace that entire construct with the function reference1. *ou can then use the open-close parenthesis to run it immediately. This construct may loo! a little odd but it wor!s$
/f1nction /0 F //C1t yo1r script code in here

G0/0.

,sing neste function scope to preserve instantaneous values This is an advanced topic that is covered in its own article given below.
$"e problem

This problem is encountered with event handlers and in other situations such as when adding methods to an ob4ect. .ost )eb authors first encounter it with event handlers so that is what this article will concentrate on but you should be aware that it also applies to those other situations. In JavaScript whether using traditional event handlers or ,6. events event handlers are attached to their relevant ob4ect as a reference to the function. In standards compliant browsers when the event fires the function is e#ecuted as a method of the ob4ect and passed a single parameter2 the event ob4ect. In Internet 3#plorer it is not passed any parameters at all$
f1nction myhandler/e0 F """ G mydiv"onclic! = myhandler. mydiv4"addOventRistener/ ,clic!,2 myhandler2 false 0.

There are many occasions when it is desirable to pass a local variable to the handler function. An e#ample would be when looping through a list of elements and assigning the same event handler to each of them but needing to pass a uni%ue identifier to each handler so it can always reference the inde# of the element within a collection. *ou may also want to pass an ob4ect not 4ust an inde#. 5erhaps this would be a reference to another element that is relevant to the handler. The obvious desire is to try something li!e this$
mydiv"onclic! = myhandler/i2myobject0.

-owever this does not wor!. )hat it will do is immediately e#ecute the handler as a normal function passing it the variables. Then whatever the function returns even if that is a string or perhaps

nothing at all is assigned as a property of the element with the name of the event handler. 6bviously this will not wor! correctly as an event handler. There are three main ways to overcome the problem. The first two are the most common but have limitations. The third is one of the most complete solutions but is not very common. The demonstrations are all prepared assuming the following e#ample algorithm$
f1nction myf1nction/0 F var paras = doc1ment"getOlementsSyTagAame/,p,0. var spans = doc1ment"getOlementsSyTagAame/,span,0. for/ var i = :. i < paras"length. i%% 0 F paras&i*"onclic! = f1nction /e0 F //ass1me that here2 we want to !now // $ what the val1e of i was for this element // $ the span that corresponds to spans&i* G. G G """ myf1nction/0.

In that e#ample the event handler is e#ecuted in the scope of the outer function so paras spans and i are all preserved. -owever they will have the values that they have in that scope at the time the handler is e#ecuted not the values they had at the time the assignment was made. This means that 0e#cept in e#tremely rare cases where the event handler is e#ecuted before the end of the loop is reached1 i will hold the value of paras"length and not the value we need. The solutions are$

*, @sing the Function constructor ., Assigning variables as properties of the element 3, @sing scope to remember the instances of the local variables

%sing t"e &unction constructor

This is the most limited and problematic approach but it is the most commonly used - typically because the author was not aware of the alternatives or their advantages. The idea is to write the function code as a string with the local variables added to the string. )hen the event handler runs it is evaluated in the current scope 0not the scope it was created in1. The problems with this approach are numerous$
o

It has very poor performance. This comes from the conversion from string to

e#ecuted code 0similar toeval1 and the creation of multiple functions that cannot be optimised by the JavaScript engine into a single stored function.
o o

The local scope variables are lost. In this case

that means that the

variable spans no longer e#ists. It can only pass literals 0strings numbers booleans regular e#pression patterns null1 and not ob4ects or arrays directly into the code. They can be referenced by name but only if they are available in the global scope or the scope that the event handler will be e#ecuted in. This means that although it is possible to pass i into the function code spans will need to be made global and the elements in it referred to using the inde# i as part of the function code$
var spans. f1nction myf1nction/0 F var paras = doc1ment"getOlementsSyTagAame/,p,0. spans = doc1ment"getOlementsSyTagAame/,span,0. for/ var i = :. i < paras"length. i%% 0 F paras&i*"onclic! = new 71nction/ ,var a = ,%i%,2 b.Ln,% ,b = spans&a*.Ln,% ,""" etc", 0. G G

""" myf1nction/0.

"ote that the ob4ects returned by getOlementsSyTagAame are dynamic so if the number of spans changes between creating the event handler and running it the spans ob4ect will be updated and the inde# will not wor!.

Assigning variables as properties o# t"e element

The idea for this approach is to store all the variables that will be needed as properties of the element that detects the event. Then when the function is e#ecuted it can loo! for these properties on the element referenced using the 'this' !eyword. This approach wor!s well in most situations but can have problems. Say for e#ample that you want to use the same function multiple times attaching it as a handler on the same element for multiple events where each one e#pects different variables to be available. It is possible to wor! around this but it can get messy. If using this it is important to ma!e certain that the chosen variable names will never be used by any browser as part of the ,6. properties for that element. This also adds weight to the element ob4ects and is not the cleanest approach but it does wor!$
f1nction myf1nction/0 F var paras = doc1ment"getOlementsSyTagAame/,p,0. var spans = doc1ment"getOlementsSyTagAame/,span,0. for/ var i = :. i < paras"length. i%% 0 F paras&i*"originalindex = i. paras&i*"relatedspan = spans&i*. paras&i*"onclic! = f1nction /e0 F var a = this"originalindex2 b = this"relatedspan. """ etc" G. G

G """ myf1nction/0.

Since this e#ecutes the event handler in the local scope it would also be possible to reference the span using$
b = spans&this"originalindex*.

"ote that again the ob4ects returned by getOlementsSyTagAame are dynamic so if the number of spans changes between creating the event handler and running it the spans ob4ect will be updated and the inde# will not wor!.

%sing scope to remember t"e instances o# t"e local variables

This is the most complete and advanced approach and solves all of the problems created by the other techni%ues. The idea is to draw on the initial mista!e of e#ecuting a function and use that to our advantage. .a!e it run a function passing it the parameters. That function returns another function that e#ists inside it within its local scope. This becomes the event handler when it is assigned and is e#ecuted inside the local scope of the outer function with the local variables that were passed to it preserved within that scope. This is !nown as a 'closure'$
f1nction scopepreserver/a2b0 F ret1rn f1nction /0 F //do something with a and b """ etc" G. G f1nction myf1nction/0 F var paras = doc1ment"getOlementsSyTagAame/,p,0. var spans = doc1ment"getOlementsSyTagAame/,span,0.

for/ var i = :. i < paras"length. i%% 0 F paras&i*"onclic! = scopepreserver/i2spans&i*0. G G """ myf1nction/0.

The main problem with this approach is its lac! of understanding due to the number of authors who are not aware of it and may be confused by what the code is attempting to do. *ou can always leave a comment in your code pointing them to this article. If you have trouble understanding it yourself I suggest you see thefunction scope part of my JavaScript tutorial where I describe how scopes li!e this wor!. There is also the point that the handler function and the scope relating to it are preserved indefinitely and can use up memory. -owever this is no worse than the other alternatives which can also hold on to large numbers of variables indefinitely. *ou can always remove the handlers once you are finished with them which will allow the garbage collector to free up the memory they used. If you do not want to use an e#ternal function it is also possible to define the scope preserving function inline and e#ecute it immediately. This has the added advantage that it preserves the scope of the main function 0myf1nction in the e#amples1 as well as the inner scopes but has the disadvantage that it becomes less easy for others to understand$
f1nction myf1nction/0 F var paras = doc1ment"getOlementsSyTagAame/,p,0. var spans = doc1ment"getOlementsSyTagAame/,span,0. for/ var i = :. i < paras"length. i%% 0 F paras&i*"onclic! = /f1nction /a2b0 F ret1rn f1nction /0 F //do something with a and b """ etc"

G. G0/i2spans&i*0. G G """ myf1nction/0.

'e#erencing

How browsers affect it ;eferencing is in my e#perience the hardest thing to learn to get right. It is not helped by the fact that the methods re%uired may be different in different browsers and so you have to include several different versions of the code to ensure it will wor! in all of them. I have put together a list of the most popular browsers available that support JavaScript. 6pera .o7illa and Safari-based browsers currently have the highest level of JavaScript support but many scripts are poorly written and are based on the implementation of 4ust a few browsers typically 4ust Internet 3#plorer and one other browser. @nfortunately Internet 3#plorer does not have a very good JavaScript implementation. It often does not comply with the standards relying instead on authors to use its non-standard e#tensions. .any authors do not realise these are non-standard and end up writing code that relies on these e#tensions. 6ther browsers may implement some of these e#tensions in an attempt to get these scripts to wor!. )hat I have done in this tutorial is to carefully test the responses of as many different browser engines as I could and put together something that wor!s in as many of them as possible. )here possible I will rely on the standards compliant version and only fall bac! to the alternatives if a standards compliant techni%ue cannot be used.

*b"ect hierarch! To reference items 0ob4ects1 on the page refer to an ob4ect structure or hierarchy. The topmost ob4ect is usually ,doc1ment, and the ne#t will be different depending on the document structure. .ost elements 0-T./ tags1 cannot be referenced in all Ath generation browsers. Those that can are$

body referred to as doc1ment div referred to using browser specific references targetting its id span referred to using browser specific references targetting its id 0it is best not to reference img referred to through the doc1ment ob4ect targetting its name a referred to through the doc1ment ob4ect targetting its inde# form referred to through the doc1ment ob4ect targetting its name input select or te#tarea referred to through the form targetting its name

this for Athgeneration ,-T./ as layers browsers have bugs that will show up if you do1

In most browsers these components will be available to scripts immediately after they have been written. If being written by script they should be available immediately but in some older browsers they may not be available until that script has completed e#ecuting 0after the </script> tag1. In some more poorly written old browsers these document components will only be available after the document has loaded. *ou can detect when the document has loaded using the window.onload event 0which can also be written in -T./ as <body onload= """1. Strangely 8ec!o browsers 0.o7illa&Firefo#&"etscape MJ1 will need at least one non-entity character to be written between the element's opening tag and the script even if the element is an image or the element will not be available to script until after the page loads. There are a few others elements that can be referenced. For a full list of ob4ects properties collections and methods refer to the section on The JavaScript ob4ect. I have written a generic referencing function that can be used to reference all document components that can be referenced 0e#cept lin!s1 but I suggest you wor! through the ne#t few sections of the tutorial first instead of ta!ing a shortcut. *ou might actually understand what I am doing instead of blindly using my code without !nowing how it wor!s.

$voi ing referencing conflicts ;emember that all names in JavaScript are case sensitive. "ames must begin with a-7 or A-V or W and may only contain the characters a-7 A-V G-D and W. The convention is to use names that describe the ob4ect. If the name is made up of more than one word there should never be a space between the words and it is not usual to have an underscore 0 W 1 between the words. The usual practice is to capitalise the first letter of all words e#cept the first.

For e#ample I have a variable that I will be using to store some te#t about me. I decide the best name is 'te#t about me' and I must remove the spaces and capitalise the first letters of all words e#cept the first. Therefore the variable name becomes ,text)bo1tHe,. In order to avoid referencing conflicts you must ma!e sure that no two JavaScript ob4ects or document elements are given the same name 0e#cept inputs - see the ne#t section1. )hen choosing names for variables functions and both names and I,s of -T./ elements there is a set of reserved words which you must not use regardless of the case. These are$ abstract arguments boolean brea! byte case catch char class const continue debugger default delete do double else enum e#port e#tends false final finally float for function goto if implements import in instanceof int interface long native new null pac!age private protected public return short static super switch synchroni7ed this throw throws transient true try typeof var void volatile while with. In addition it is generally a good idea not to use names that conflict with the names of e#isting properties or methods of the global&window ob4ect 0unless you really want to overwrite them1. See the section on The JavaScript ob4ect for more details.
$"e JavaScript object

This page gives a list of ob4ects properties collections and methods for documents and JavaScript components. This view of all properties available from the respective element types is referred to as the JavaScript ob4ect. Some browsers may provide aditional properties or methods but as this stage of the tutorial is intended to teach you how to program so that your scripts wor! in all the possible 0so called Ath generation1 browsers I have given those that are available in all possible browsers or those which have an alternative which I will also have given. This is the last chapter of this tutorial where I will deal with such a wide range of browsers. In the ne#t few chapters I will abandon A th generation browsers and move on to the much more advanced ,6. browsers 0also !nown as Hth generation browsers1.

)ontents

Standard document components - all addressable components of a web page. 5ositioned elements - all addressable components of an absolutely positioned div. 3vent ob4ects - all accessible information about an event. Intrinsic ob4ects - variable types with constructors.

6e!

(arent object
o o o o o

"ild object "ild property "ild object being accessed t"roug" a collection)* Event Met"od+,

For items written in the format$ 'methodAame/&some8therSt1ff*0' some8therSt1ff is optional and does not need to be written. The PQ brac!ets must be removed. For items written in the format,methodAame/type varAame0, ,type, gives the type of variable e#pected by the method or collection calledvarAame in this case. To use this structure to refer to any ob4ect property collection or method treat each new branch level as a new child level. For e#ample$
window"doc1ment"name8f7orm"name8f5np1t"defa1lt+al1e = ,5 love it,.

"ote all collections also have the length attribute. Also note window is often omitted when referring to child ob4ects.

Stan ar

ocument components

window or sel#
o o o o o o

Array -oolean closed .ate

parse+string dateAsAString,

de#aultStatus document

bg olor body

clientHeig"t client!idt" scroll/e#t

scroll$op style

bac0ground bac0ground olor color

coo0ie documentElement

clientHeig"t client!idt" scroll/e#t scroll$op style


bac0ground bac0ground olor color

domain #g olor IdO#(ositionedElement lastModi#ied nameO#&orm


action encoding lengt" met"od name nameO#Input1textarea1select or nameO#InputsS"aring2ame)int index*


c"ec0ed de#ault "ec0ed de#aultValue disabled #orm lengt" name selectedIndex type value

options)int numberO#Option!it"SelectInput*

de#aultSelected index selected text value

onblur onc"ange onclic0 ondblclic0 on#ocus on0eydown on0eypress on0eyup onmousedown onmouseup blur+, #ocus+, select+,

target elements)int numberO#Input* onreset onsubmit reset+, submit+, border complete "eig"t lowsrc name src widt" onabort onerror onload onmousedown

nameO#Image

onmouseup

re#errer title %'/ all)string IdO#Element* anc"ors)int numberO#A$ag!it"2ame.e#ined*


name o##set/e#t o##set(arent o##set$op x y nameO#(ublic(roperty nameO#(ublicMet"od+, "eig"t "idden name pluginspage src type units widt" onload nameO#(ublicMet"od+,

applets)int numberO#Applet$ag*

embeds)nameOr2umberO#EmbeddedObject*

#orms)int numberO#&orm* images)nameOr2umberO#Image* layers)string IdO#(ositionedElement* lin0s)int numberO#A$ag!it"Hre#.e#ined*See (ositioned Element


"as" "ost "ostname "re# inner$ext o##set/e#t o##set(arent

o##set$op pat"name port protocol searc" target text x y onblur onclic0 ondblclic0 on#ocus onmousedown onmousemove onmouseout onmouseover onmouseup blur+, #ocus+,

plugins)numberO#Object* onclic0 ondblclic0 on0eydown on0eypress on0eyup onmousedown onmousemove onmouseout onmouseover onmouseup captureEvents+Event3Event$ype, close+, getElement-yId+string IdO#Element, open+, write+string content, writeln+string content,

o o

event Event

/I 4 .-/ /I 4 4E5.O!2 4E5('ESS 4E5%( MO%SE.O!2 MO%SEMOVE MO%SEO%$ MO%SEOVE' MO%SE%(

o o

&unction "istory

bac0+, #orward+, go+int numer$oJump,

o o o o o

Image innerHeig"t inner!idt" lengt" location


"as" "ost "ostname "re# pat"name port protocol searc" reload+)bool #orce&ull'eload*, replace+string location, E /26 /278 /O96E

Mat"

o o

/O978E (I S:'$7;6 S:'$6 abs+number n, acos+number n, asin+number n, atan+number n, atan6+number n<number 0, ceil+number n, cos+number n, exp+number n, #loor+number n, log+number n, max+number a<number b<number c<33333, min+number a<number b<number c<33333, pow+number n<number 0, random+, round+number n, sin+number n, s=rt+number n, tan+number n,

name navigator

app ode2ame app2ame appVersion language plat#orm userAgent user/anguage mime$ypes)nameOr2umberO#MIME$ype*


description enabled(lugin su##ixes type

plugins)nameOr2umberO#(lugin*

o o o o o o o o o o

description #ilename lengt" name nameOr2umberO#MIME$ype

javaEnabled+, taintEnabled+, MA>;VA/%E MI2;VA/%E 2a2 2E9A$IVE;I2&I2I$5 (OSI$IVE;I2&I2I$5

2umber

Object opener Option outerHeig"t outer!idt" page>O##set page5O##set parent 'egExp


?7 333 ?@ input lastMatc" or ?A last(aren or ?B le#t ontext or ?C rig"t ontext or ?D availHeig"t avail!idt" color.ept" "eig"t pixel.ept" widt"

screen

o o

status String

o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o o

#rom "ar ode+number ascii "aracterValue, name

#rames)nameOr2umberO#&rame* onblur onerror on#ocus onload onunload alert+object, blur+, clearInterval+interval object, clear$imeout+timeout object, close+, con#irm+string message, escape+string text$o%'/Encode, eval+string script$oEvaluate, #ocus+, is&inite+number number$o "ec0, is2a2+number number$o "ec0, move-y+int xO##set<int yO##set, move$o+int x(os<int y(os, open+string url)<string target2ame)<string options)<bool replaceHistoryEntry***, parseInt+string text ontainingAnInteger)< int radix*, parse&loat+string text ontainingA&loat, print+, prompt+string message<string de#aultValue, resiEe-y+int xO##set<int yO##set, resiEe$o+int x!idt"<int y!idt", scroll-y+int xO##set<int yO##set, scroll or scroll$o+int x(os<int y(os, setInterval+string or #unction script$oEvaluate<int timeInMilliseconds, set$imeout+string or #unction script$oEvaluate<int timeInMilliseconds, unescape+string text$o%'/%nEncode,

0ositione elements In ,6. and proprietary ,6. browsers this could actually be any element not 4ust one that is positioned. -owever at this stage of the tutorial only A th generation ,-T./ is being discussed and therefore this is referred to as a positioned element. The ne#t chapter will show how this applies to all elements not 4ust those that are positioned.

(ositionedElement
o o

bg olor clip

bottom le#t rig"t top

o o o o o o

document id innerH$M/ le#t name style


bac0ground bac0ground olor clip color "eig"t le#t pixelHeig"t pixel/e#t pixel$op pixel!idt" top visibility widt" EIndex

o o o o

top visibility EIndex onclic0

o o o o o o o o o o o

ondblclic0 on0eydown on0eypress on0eyup onmousedown onmousemove onmouseout onmouseover onmouseup captureEvents+Event3Event$ype, resiEe$o+int widt"<int "eig"t,

7vent ob"ects

window3event or #irst argument passed to "andler #unction


o o o o o o o o o o o o o o o o o

alt4ey button client> client5 ctrl4ey 0ey ode modi#iers page> page5 screen> screen5 s"i#t4ey target t"is type srcElement w"ic"

8ntrinsic ob"ects showing constructors The constructors are all properties of the window ob4ect but they are almost always used without 'window.'. Synta#$
var variableAame = new intrinsic8bject'onstr1ctor/options0.

For e#ample$
var my)rray = new )rray/,here,2,there,2,everywhere,0.

$rra!

Array+)int lengt"*, +not in JavaScript 736, Array+)element 8)< element 7)< element 333 n***, )element 8< element 7< element 333 n*
o o o o o o o o o o o o

lengt" concat+element$oAdd)<element$oAdd)<element$oAdd)<etc3***, join+)string separator$o'eplace omma*, pop+, pus"+element$oAppend, reverse+, s"i#t+element$oAppend, slice+int o##set&romStart)<int o##set$oEnd*, sort+)#unction sort&unction*, splice+int o##set&romStart<int number$o'emove)<element$oAdd)<element$oAdd)<etc3***, toString+, or valueO#+, uns"i#t+,

9oolean

-oolean+)bool value*, true or #alse


o o

toString+, valueO#+,

Date "ote a @"I9 timestamp 0milli1 is the number of milliseconds since GG$GG$GG.GGG G<&G<&<DIG currently <=LHMI<<I<HLI. "ote also that @T+ is the time as it would be in the 8.T time7one so 8.T and @T+ are e%uivalent.

.ate+, .ate+int %2I>$imestampMilli, .ate+year< mont"< date)< "ours)< minutes)< seconds)<ms****,


o o o o o o o o o o o o o o o o o o o o o o o o o o o o o

get.ate+, get.ay+, get&ull5ear+, getHours+, getMilliseconds+, getMinutes+, getMont"+, getSeconds+, get$ime+, get$imeEoneO##set+, get%$ .ate+, get%$ .ay+, get%$ &ull5ear+, get%$ Hours+, get%$ Milliseconds+, get%$ Minutes+, get%$ Mont"+, get%$ Seconds+, get5ear+, set.ate+int dayO#Mont", set&ull5ear+int yearInF.igit&ormat)<int mont")<int dayO#Mont"**, setHours+int "ours)<int minutes)<int seconds)<int milliseconds***, setMilliseconds+int milliseconds, setMinutes+int minutes)<int seconds)<int milliseconds**, setMont"+int mont")<int dayO#Mont"*, setSeconds+int seconds)<int milliseconds*, set$ime+int %2I$>$imestampMilli, set%$ .ate+int %2I$>$imestampMilli, set%$ &ull5ear+int yearInF.igit&ormat)<int mont")<int dayO#Mont"**,

o o o o o o o o o

set%$ Hours+int "ours)<int minutes)<int seconds)<int milliseconds***, set%$ Milliseconds+int milliseconds, set%$ Minutes+int minutes)<int seconds)<int milliseconds**, set%$ Mont"+int mont")<int dayO#Mont"*, set%$ Seconds+int seconds)<int milliseconds*, set5ear+int numberO#5earsSince7@88, to%$ String or to9M$String+, toString or to/ocaleString+, valueO#+,

:unction

&unction+)string var2ame<)string var2ame6<)etc3***string script$oEvaluate, #unction #unction2ame+listO#Variables, G #unction code H #unction2ame I #unction +listO#Variables, G #unction code H
o o o o o o o o

caller prototype t"is arguments)*

callee

apply+objectJ t"isObject)<arrayJ arguments*, call+objectJ t"isObject)<argument)<argument)<etc3***, toString+, valueO#+,

8mage

Image+)int widt"<int "eig"t*,

Number

2umber+numberOrString value, number in "ex< octal or decimal


o o o o o

to&ixed+precision, to(recision+precision, toExponential+precision, to/ocaleString+, toString+,

valueO#+,

*b"ect

Object+, G property2ame7J value7)< property2ame6J value6)< etc3** H


o o o o

constructor "asOwn(roperty+string property2ame, toString+, valueO#+,

*ption

Option+)string text<string value)<bool selected**,

&egular 7xpression

'egExp+string pattern<string options, 1pattern1options


o o o o o o o

compile+string pattern<string options, exec+string string$oMatc", global ignore ase lastIndex source test+string string$oMatc",

String

String+)stringOrObject$o-e'epresentedAsString*, DcontentD KcontentK


o o o o o o o

lengt" anc"or+string nameO#Anc"or, big+, blin0+, bold+, c"arAt+int index, c"ar odeAt+int index,

o o o o o o o o o o o o o o o o o o o o o o

concat+string string$oAppend)<string string$oAppend)<string string$oAppend etc3**, #ixed+, #ontcolor+string colorValue, #ontsiEe+int siEe, indexO#+string searc"String)<int o##set*, italics+, lastIndexO#+string searc"String)<int o##set*, lin0+string "re#$o/in0$o, matc"+'egExp searc"Expression, replace+'egExp searc"Expression<string replacement$ext, searc"+'egExp searc"Expression, slice+int o##set&romStart)<int o##set&romEnd*, small+, split+'egExp separator)<int maxArray/engt"*, stri0e+, sub+, substr+int startIndex)<int lengt"*, substring+int startIndex<int endIndex, sup+, to/ower ase+, to%pper ase+, valueO#+,

-rowser inspeci#ic re#erencing

"ote that to avoid referencing problems no two elements should 3(3; be given the same name or id. The only e#ception is form inputs which can share names.

+lobal references (ariables are referenced simply by typing their name or by using window"variableAame. Functions are referenced simply by typing their name or by using window"f1nctionAame.
,window, 0or ,self,1 may be used to reference the global ob4ect for the current document

regardless of what scope your script is running in. If your script is running in another script and you are having trouble referencing global variables because a local variable uses the same name this

problem can be %uic!ly solved by adding ,window", to the start of the variable name. For e#ample window"myvariable 'y a similar nature you can use ,this, to represent the current ob4ect. 'y default ,this, will be thewindow ob4ect. If you are writing the script as part of a -T./ event handler ,this, will be the element that detected the event. For e#ample this can be used to alert the value of the te#t input$
f1nction my71nction/x0 F window"alert/x"val1e0. G """ <inp1t type="text" on!eypress="my71nction/this0">

@sing this same function from a script running in the global scope the word ,this, refers to the windowob4ect. The window ob4ect does not have a value property so the function would alert 'undefined'. -owever if the on!eypress method is activated manually the word ,this, once again refers to the input so the function will alert the value of the input$
doc1ment"forms&:*"elements&:*"on!eypress/0.

:rameset references There are four very useful references that refer to parts of is a frameset. These and

are ,window, or ,self, ,window"parent, ,window"top, 0window the window"frames collection.


self and window

usually

omitted1

These refer to the global ob4ect of current web page.


parent

;efers to the window ob4ect of the page that is holding the current page in a frameset.
top

;efers to the window ob4ect of the page at the top of the frames hierarchy.
window"frames&name8rA1mber8f7rame*

;efers to a frame or iframe held by the current page. )ith iframes 0if the browser supports them1 you have to use the e#tra word 'window' on the end to reference the window ob4ect of the document contained by the iframe 0there are alternatives but this one wor!s in all browsers that support iframes ma!ing it superior to all other techni%ues since they only wor! in a selection of browsers1$
window"frames&name8rA1mber8f7rame*"window

If the page is the only page being displayed top parent self and window will be e%ual. If the page is being held within a frameset self and top will not be e%ual. If the page is the page containing the frameset and it itself is not being held within a frameset self and top will be e%ual. If someone is loading your page into their frameset and you don't want them to you can use the selftop relationship to remove your page from their frameset and replace their frameset page with your page using$
if/ self #= top 0 F top"location"replace/self"location"href0. G

"ote I could have used this$


if/ self #= top 0 F top"location"href = self"location"href. G

-owever that ma!es the browser add the new entry into its history so if they clic!ed their bac! button they would be forwarded bac! to your page again. @nfortunately 8ec!o browsers 0.o7illa&Firefo#&"etscape MJ1 will only allow the second option as they have very high security levels relating to cross-site scripts. "ote that using scripts to force pages in and out of framesets is a very bad idea. It causes usability problems for many users brea!s search engines and annoys your visitors. I !now you !now how to do it but that does not mean that you should. )ith all frames the name is set using the name="name8f7rame" attribute in the <frame """> tag. The number is automatically generated by the browser in the order that the frames are defined in the -T./ beginning at G. To fully reference the window ob4ect of another frame when inside a frameset use one of these$
parent"frames"otherframename

parent"frames&,otherframename,* parent"frames&4* 0assuming = is the inde# of the frame1 parent"otherframename

From there you can reference items inside that document using doc1ment"whatever
parent"frames&,otherframename,*"doc1ment"images&,imagename,*"src = "sample"gif".

Ta!e for e#ample the following frame page structure. The main page - main.html - 0which by default has no name although it can be set with JavaScript contains two a page inner.html or by opening the page with the page two containing a further targetZ>new"ame>1 frames2 ,left, and ,right,. ,left, contains

'lin!s.html'. ,right, contains

frames2 ,banner, and ,mainpart,. The locations of ,banner, and ,mainpart,are upper.html and lower.html respectively. The names of the files are irrelevant but it helps me to e#plain the structure to you. This produces the following frame tree structure$
1nnamed frame /main"html0 333333333333Q333333333333 Q left /lin!s"html0 Q right /inner"html0 3333333333Q33333333333333 Q banner /1pper"html0 Q mainpart /lower"html0

The following e#amples use the frames collection although any of the above synta#es would be fine. If a script were running in main.html it would be able to reference the window and document ob4ects of lower.html using this$
window"frames&,right,*"frames&,mainpart,* window"frames&,right,*"frames&,mainpart,*"doc1ment

If a script were running in lower.html it would be able to reference the window ob4ect of lin!s.html using either of these$

window"parent"parent"frames&,left,* window"top"frames&,left,*

Attempting to access the contents of a frame before they have loaded will cause an error. In all browsers the window ob4ect will not e#ist for that frame unless the page has loaded.
if/ #window"frames&,name8f7rame,* 0 F window"alert/ ,7rame has not loaded, 0. G

This algorithm also wor!s with iframes without re%uiring any changes.

:orms "ote that this changes in "etscape A and other layers browsers if the form is put inside a positioned element. See the section on 3lement contents for more details. To fully reference a form the name="name8f7orm"attribute use doc1ment"formname for a form that was defined with in the <form
"""> tag

or doc1ment"forms&n1mber3of3form* either should wor!. The number is generated automatically by the browser in the order that the forms are defined in the -T./ beginning at G. To fully reference an input use any of these$
reference3to3form"inp1tname reference3to3form"elements&,inp1tname,* reference3to3form"elements&n1mber3of3inp1t3/not3image3inp1t0*

"ame the <inp1t

is

defined

using

the name="name8f5np1t" attribute


"""> or<select

in

"""> <textarea

"""> <b1tton

"""> tags. "umber is generated

automatically by the browser in the order that the inputs are defined in the -T./ beginning at G. *ou can read or write the value of te#t inputs and te#tareas with their 'value' property. See the section on The JavaScript ob4ect for a full list of what parts of a form can be read or changed. If more than one input of any !ind in the same form share the same name 0as is common with radio button inputs1 they must be referenced using the numerical array associated with that name. The array will contain an entry for each input with that name in ascending order of how they appear in

the source of the document

beginning at G. For e#ample

if a radio button has the

name ,myb1tton, it can be referenced using this$


doc1ment"name8f7orm"myb1tton

'ut if two radio buttons share the name ,myb1tton, the second button 0for e#ample1 can be referenced using this$
doc1ment"name8f7orm"myb1tton&9*

This will be the case for any input type even if inputs of different types share the same name. In practice radio buttons will almost always share a name and chec!bo#es may occasionally share a name. 3ven if inputs share a name they will still have individual entries in the elements collection. For select bo#es each individual option can be referenced

using inp1t3name"options&n1mber3of3option*. For e#ample$


if/ doc1ment"my7orm"mySelect"selected5ndex == 9 0 F doc1ment"my7orm"mySelect"options&;*"selected = tr1e. if/ #doc1ment"my7orm"myNadio&9*"chec!ed 0 F doc1ment"my7orm"myNadio&4*"chec!ed = false. doc1ment"my7orm"myNadio&9*"chec!ed = tr1e. doc1ment"my7orm"myNadio&:*"chec!ed = false. G

*ou can reference the value of an option tag with ,"val1e, and the te#t it displays with ,"text,. *ou can also find out how many options there are by using the ,"length, property of the options collection. "ote setting a select option to null will remove it from the select bo#$
doc1ment"forms&n1mber3of3form*"mySelect"options&:* = n1ll.

All other options will have their inde# numbers ad4usted to reflect this change. To add or replace one use this$
doc1ment"forms&n1mber3of3form*"mySelect"options&n1mber* = new 8ption/,text,2,val1e,0.

.ost commonly number used is the length of the collection as that will add the new option onto the end$
doc1ment"forms&n1mber3of3form*"mySelect"options"length

)arning$ although the selectInput6b4ect.selectedInde# property should be read-write it is read-only in Internet 3#plorer A. If this causes problems you car use this$
select5np1t8bject"options&index*"selected = tr1e.

8mages "ote that this changes in "etscape A and other layers browsers if the form is put inside a positioned element. See the section on 3lement contents for more details. To reference an image use any of these$
doc1ment&,imagename,* doc1ment"images&,imagename,* doc1ment"images&n1mber3of3image*

"ame is defined using the name="name8f5mage" attribute in the <image """> tag. "umber is generated automatically by the browser in the order that the images are defined in the -T./ beginning at G. "ote if you compare documentP'imagename'Q.src to a string constant you will find that in some browsers it may be the same whereas in others it is not. This is because some browsers will give the image src in the format 'myimage.gif' whereas others may give it in the format 'http$&&mydomain.co.u!&myimage.gif'$
if/ doc1ment&,imagename,*"src == "pig"gif" 0 F

""" if/ doc1ment&,imagename,*"src == my5mage"src 0 F

A solution to this is to use the string method ,index8f/0,. If the parameter is not contained within the string the method returns -< else it returns the position of the first occurrence of the parameter within the string. For e#ample$
if/ ,http6//mydomain"co"1!/myimage"gif,"index8f/,myimage"gif,0 % //This will be exec1ted G if/ ,http6//mydomain"co"1!/myimage"gif,"index8f/,yo1rimage"gif,0 % //This will not be exec1ted G if/ ,http6//mydomain"co"1!/myimage"gif,"index8f/,image"gif,0 % //This will be exec1ted" SO M)NAO(2 this may ca1se a problem G 9 0 F 9 0 F 9 0 F

Links# anchors an areas "ote that this changes in "etscape A and other layers browsers if the form is put inside a positioned element. See the section on 3lement contents for more details. To reference an <a """> element there are two ways 0e#cluding those provided by the ,6.1. If the name attribute is set so ma!ing the element an anchor 0used in <a href="Wname8fRin!">1 you can refer to it using this$
doc1ment"anchors&n1mber3of3<a>3element*

Alternatively if the href attribute is set you can refer to it using this$
doc1ment"lin!s&n1mber3of3<a>3element*

"umber is generated automatically by the browser in the order that the lin!s or anchors are defined in the -T./ beginning at G. As <area """> tags also have the href attribute they may also be accessed using the lin!s collection but not the anchors collection. If an <a """> element has both the the href and name attributes set it will appear in both collections although its inde# may be may not be the same in each. In layers browsers any lin!s or anchors referred to using the anchors collection will have only the name property available. The collection provides access to the anchors purely for the purpose of changing the name used when setting the location with location"hash.
-rowser speci#ic re#erencing

The fact that this referencing is browser specific does not mean that it will not wor! in all browsers. )hat it does mean is that you will have to include more than one way of referencing items to ensure that you manage to reference them correctly. There are four ways to reference items$

):+ ,6. "etscape layers compliant "etscape alternative compliant - strictly spea!ing this is also layers compliant 5roprietary ,6.

The main one is the ):+ ,6. which is supported by all current browsers. /ater on in this tutorial I will move over to concentrating only on the ,6. version since it is much more capable than the others. -owever since this stage of the tutorial deals with the tas!s re%uired for Ath generation ,-T./ I will use all of these techni%ues so the code will wor! in older browsers as well. )hen you write your own code some of this may be unnecessary depending on what browsers people use to view your site but you will fre%uently encounter code that uses techni%ues so it helps to understand what they are doing and why. There are many similarities and crossovers between the different methods and in many cases there are only two different variations re%uired at a time for e#ample when finding the si7e of the screen or the button of the mouse that was clic!ed 0see the sections ')indow si7e and scrolling' and '3vent information'1. )riting script using browser specific referencing is not difficult. The main thing to remember is never to ma!e assumptions. Just because a browser uses "etscape compliant synta# to reference an element that does not mean that is uses "etscape compliant synta# to reference the style. The way I will show you to write never ma!es assumptions. )hat is more it uses all four types of synta# 0where they e#ist1 allowing browsers that support any one of the types of referencing to wor!. That is the only way to produce true cross-browser scripts.

To download the browsers themselves see my list of 'AthJ generation' browsers.

7lement position

Internet 3#plorer will only get the values right after the page has loaded until then it returns incorrect values Safari <.:- gets the offset wrong for fi#ed position elements as it adds on the L pi#el body margin. )ebT( 3scape "etFront :.:- T!html -v: and 6mni)eb A.=- do not provide a way to wor! out the "etscape A can only wor! out the positions of lin!s not other elements. "etscape A will not provide the # and y properties as children of the lin! ob4ect if the name attribute is set. 6pera L- can have trouble wor!ing out positions if the '6,* or -T./ element has auto left&right margins I am unsure of the capabilities of "et'o# i5anel .icro'rowser and 6penT( here.

usually G G.

position of elements 0for a brief while 3scape A.L could1.

Instead they will be children of the corresponding anchor ob4ect. ordisplay6table.

As an e#ample of browser specific script I will demonstrate how to find the position of an element on a web page. "ote that in older browsers this can be a little unreliable with elements that are in another element that is positioned absolutely or relatively using +SS. To be nice to "etscape A I will demonstrate this with a lin! but it could wor! anywhere in other browsers. In "etscape compatible browsers every lin! ob4ect has two properties that give its current position lin!8bject"x and lin!8bject"y. In ,6. compatible browsers these do not e#ist. Instead theelement8bject"offsetReft and element8bject"offsetTop properties are given. These give the position of the lin! relative to an arbitrary ancestor node !nown as the offsetCarent. ,ifferent ,6. browsers give a different offsetCarent some may say the paragraph that the lin! is in while some may say the container the paragraph is in. This can all get a bit complicated. Fortunately with ,6. browsers the offsetCarent will also have

the offsetTop and offsetReftproperties giving its position relative to its offsetCarent and so the cycle continues until theoffsetCarent is the topmost node in the document which will always be at offset 0G G1. )e can access theoffsetCarent using element8r'1rrentAode"offsetCarent. So all we have to do is add the offsets together and we will end up with the same answer as we would if we had the lin!8bject"x andlin!8bject"y properties. There is one e#ception to this2 if an element has position6fixed its offsetCarent should be the viewport which cannot be referenced so the offsetCarent is n1ll instead. -owever its offsetTop andoffsetReft still hold real values. 0The situation is actually the same for the

-T./ or '6,* element when they are attached to the viewport but they generally have no offset there so it does not matter.1 )hat this means is that even when the offsetCarent is null you still need to remember to add on the last set of offsetTop and offsetReft values. 6pera DJ Internet 3#plorer and I+3'rowser get this right. 6ther browsers will treat the offsetCarent of a fi#ed position element as either the -T./ or '6,* elements but this is harmless because they themselves have no offsets so the algorithm will always wor!. The following function returns an array containing &leftCosition2topCosition* for an element.
f1nction findCosition/ oOlement 0 F if/ typeof/ oOlement"offsetCarent 0 #= ,1ndefined, 0 F for/ var posX = :2 posK = :. oOlement. oOlement = oOlement"offsetCarent 0 F posX %= oOlement"offsetReft. posK %= oOlement"offsetTop. G ret1rn & posX2 posK *. G else F ret1rn & oOlement"x2 oOlement"y *. G G

Test it here$ get the position of this lin!. )ith lin!s you can also chec! what the te#t of the lin! is$
var theText = lin!8bject"text T lin!8bject"text 6 lin!8bject"innerText.

7lement position with scrolling offsets

6pera doubles the scrolling offsets for inline elements but is reliable for bloc! elements.

The simple find5osition script calculates the position of elements anywhere on the page but only if they are not inside a scrollable element. This serves the vast ma4ority of purposes and is the preferred approach in most cases. Inside a scrollable element 0created using the overflow style1

the element can scroll the contents but the calculated position will assume the element is not scrolled at all. To wor! out the position after scrolling the script needs to step through all parent elements 0or positioned containers if at least one element in the offsetCarent chain is positioned absolutely1 and subtract any scrolling offsets for them. )or!ing out which scrollable elements are actually going to affect the position re%uires !nowledge of what elements are containers for any positioned elements in the chain. This can be complicated to calculate for a script so the easiest approach is to ma!e sure that every element with an overflow of anything other than visible also has a position style set to something other than the default static. This way they will all appear in the offsetCarent chain and can be easily subtracted in the same loop that adds theoffsetReft and offsetTop. As a separate complication there is the document scrolling. The document scrollbar can be produced by either the S8(K or -THR elements depending on the browser ,6+T*53 and overflow styles on the elements. ,ifferent browsers also reflect this scrolling in different ways when chec!ing for scrolling on these elements and this ma!es it completely unreliable. The easiest approach is simply to e#clude any scrolling on these elements. If needed it can be added later by wor!ing out how far the document has been scrolled 0covered in the window si7e and scrolling chapter1. The scrolling offset for each element is available as the scrollTop and scrollReft properties for those elements. The following code performs as described 0including ma!ing sure it does not subtract any scrolling for the target element itself1. .a!e sure all scrollable elements have the position style set as shown above.
f1nction findCositionMithScrolling/ oOlement 0 F if/ typeof/ oOlement"offsetCarent 0 #= ,1ndefined, 0 F var originalOlement = oOlement. for/ var posX = :2 posK = :. oOlement. oOlement = oOlement"offsetCarent 0 F posX %= oOlement"offsetReft. posK %= oOlement"offsetTop. if/ oOlement #= originalOlement PP oOlement #= doc1ment"body PP oOlement #= doc1ment"doc1mentOlement 0 F posX $= oOlement"scrollReft. posK $= oOlement"scrollTop.

G G ret1rn & posX2 posK *. G else F ret1rn & oOlement"x2 oOlement"y *. G G

"ote that this performs much more slowly than the simple find5osition script so it should only be used where absolutely necessary. It is possible to use ,6. to step up the entire parentAode chain and subtract the scrolling offsets for elements from the value returned by the simple find5osition script. If the computed position style is fixed it can stop. If it is absol1te it can stop including scrolling offsets until it reaches another element whose computed position style is not static 0done by 4umping to the element's offsetCarent1. This would then wor! without needing to set the position style on all scrollable elements. -owever as!ing a browser to perform this many computations will cause the script to run very slowly so should be avoided. I do notrecommend using this code but it is here if you still feel you need it$
f1nction findCositionMithScrolling/ oOlement 0 F f1nction getAext)ncestor/ oOlement 0 F var act1alStyle. if/ window"get'omp1tedStyle 0 F act1alStyle = get'omp1tedStyle/oOlement2n1ll0"position. G else if/ oOlement"c1rrentStyle 0 F act1alStyle = oOlement"c1rrentStyle"position. G else F //fallbac! for browsers with low s1pport $ only reliable for inline styles act1alStyle = oOlement"style"position.

G if/ act1alStyle == ,absol1te, QQ act1alStyle == ,fixed, 0 F //the offsetCarent of a fixed position element is n1ll so it will stop ret1rn oOlement"offsetCarent. G ret1rn oOlement"parentAode. G if/ typeof/ oOlement"offsetCarent 0 #= ,1ndefined, 0 F var originalOlement = oOlement. for/ var posX = :2 posK = :. oOlement. oOlement = oOlement"offsetCarent 0 F posX %= oOlement"offsetReft. posK %= oOlement"offsetTop. G if/ #originalOlement"parentAode QQ #originalOlement"style QQ typeof/ originalOlement"scrollTop 0 == ,1ndefined, 0 F //older browsers cannot chec! element scrolling ret1rn & posX2 posK *. G oOlement = getAext)ncestor/originalOlement0. while/ oOlement PP oOlement #= doc1ment"body PP oOlement #= doc1ment"doc1mentOlement 0 F posX $= oOlement"scrollReft. posK $= oOlement"scrollTop. oOlement = getAext)ncestor/oOlement0. G ret1rn & posX2 posK *.

G else F ret1rn & oOlement"x2 oOlement"y *. G G

-ow the various ,6. parts of this wor! will be covered in later chapters of this tutorial.
.H$M/

6ne of the most popular uses of JavaScript is ,-T./ 0,ynamic -yperTe#t .ar!up /anguage1. Strictly spea!ing ,-T./ is using JavaScript to modify the +SS styles of -T./ elements. All current browsers support much more than I will describe at this stage of the tutorial. For now I will concentrate on the capabilities introduced by Ath generation browsers. 6ld browser versions 0such as "etscape A and 6pera M-1 limit the abilities of 'Ath generation' ,-T./ as these can only handle basic ,-T./. -owever they still provide easily enough fle#ibility to ma!e features li!e pop-up menus message scrollers mouse trails or falling snow effects. This re%uires parts of the page to move or appear&disappear. This can be done reliably using the div element and in many cases the span element when they are positioned using the position$ absolute2 or position$ relative2 style 0e#cept when changing the display style1. 5ersonally I almost always use the div element and I can guarantee that it will wor! with everything I show you here. Some old browsers 0particularly "etscape A1 have problems using the span element when positioned absolutely. 6nce you have set up the -T./ 0using a few wor!arounds for bugs1 you can reference the positioned element. *ou can then use that reference to change the visibility position bac!ground colour 7-inde# clipping and si7e of the positioned element. *ou can even rewrite the contents of the positioned element orcreate new positioned elements after the page has loaded. ,-T./ also allows you to change the bac!ground colour of the whole document and change the display style of A"* element. Sadly ,-T./ is always browser specific in other words different browsers re%uire different commands. @sing the techni%ues I will show you this is not difficult to wor! with to ma!e sure that no matter what synta# the browser e#pects the script can chec! what to use and use it correctly. .any authors ma!e the mista!e of detecting browsers and assuming capabilities or detecting one capability and assuming another. This tutorial does not rely on these mista!en assumptions. At no point should you need to detect specific browsers.

;th generation browsers There are several browsers that I !now of that can handle ,-T./ 0often called 'version A' or 'Ath generation' browsers even though their version number may not actually be as high or low as A1. The following list gives a different line for each significantly different browser. Some of these browser engines are used in a large number of other browsers. For e#ample$

The Internet 3#plorer 0)in1 engine is used in .a#thon Avant many A6/ versions and The 8ec!o engine is used in +amino U-.eleon Floc! and many others. The 6pera engine is used in a large number of devices in a variety of different applications. The U-T./&)eb!it engine is used in 6mni)eb and Shiira.

many others.

Ma"or browsers Internet 3#plorer HJ 0)in1 @ses document.get3lement'yId and document.all .o7illa 8ec!o 0FireFo# "etscape MJ1 @ses document.get3lement'yId 0also secretly uses document.all1 6pera IJ @ses document.get3lement'yId and document.all 0document.all is secretly supported in 6pera D.HJ1 U,3 U-T./&)ebUit 0Safari Uon%ueror :J 6mni)eb A.HJ1 @ses document.get3lement'yId 0Safari : also secretly uses document.all1

8nterme iate browsers 0Internet1 3#plorer H 0.ac1 @ses document.get3lement'yId and document.all i+ab : @ses document.get3lement'yId and document.all

Minor browsers These browsers are not used very much or are no longer the current versions of these browsers. Some may have significant bugs limited capabilities or limited event detection. Several of these use the .o7illa 6rgani7ation's Java based ;hino JavaScript engine to power their browsers. The ;hino JavaScript engine only powers the JavaScript language interpreter it does not govern how JavaScript interacts with the web page. 3ach browser will have its own ,-T./ 0or ,6.1 implementation. Internet 3#plorer A 0)in1 @ses document.all 0Internet1 3#plorer A 0.ac1 @ses document.all 6pera H-M @ses document.get3lement'yId .o7illa ;hino engine 0I+3browser1 @ses document.get3lement'yId and document.all .o7illa ;hino engine 03scape&3vo H1 @ses document.get3lement'yId and document.all .o7illa ;hino engine 03scape A1 @ses document.layers .o7illa ;hino engine 0+lue browser1 @ses document.get3lement'yId and document.all T!htmlJ33S 0T!html -v:1 @ses document.get3lement'yId "etscape A @ses document.layers 6mni)eb A.=-

@ses document.layers 0also optionally supports document.all1 i+ab = @ses document.get3lement'yId and document.all Uon%ueror = @ses document.get3lement'yId and document.all

Television or mobile evice browsers ,ue to the limitations of the devices that these browsers run on most will have limited event detection. "etFront @ses document.get3lement'yId 5oc!et Internet 3#plorer @ses document.all "etgem A browser 0"et'o#1 @ses document.get3lement'yId 6penT( @ses document.get3lement'yId i5anel .icro'rowser with advanced modules @ses document.get3lement'yId )ebT( 0.S" T(1 5lus and e#tended +lassic @ses document.all 0and non-nested layers alternative1

More information For more details of these browsers and to download them please see my list of 'AthJ generation' browsers. 0*ou can also try this site for a fairly complete list.1

)hile many JavaScript and ,-T./ functions wor!ed in Uon%ueror = the browser was unable to detect and handle events properly so most ,-T./ applications did not wor!. Uon%ueror : is a big improvement and is now a highly capable browser so I have given compatibility notes for Uon%ueror :J only. I am unsure of the abilities of "et'o# i5anel .icro'rowser and 6penT( as I do not have them to test. The "et'o# site claims partial +SS = so I assume +SS positioning and ):+ ,6. < so I assume ,-T./. 6penT( claims absolute +SS positioning and ,6. ,-T./. The 3IS claims that one of their advanced modules for i5anel .icro'rowser can handle ,6.. They might not support inner-T./ because that is not part of the ,6. standard even though it has been widely accepted by almost all ,6. browsers. "ote that even though 3scape A is a layers browser li!e "etscape A it supports both the "etscape synta# and the style ob4ect for changing element style with the e#ception of clipping. )ebT( =.LJ also supports both synta#es but is a proprietary ,6. browser.

Setting up the HTML There are two types of positioning that are of interest here. These are absolute and relative. Absolute allows you to position an element anywhere you want to in relation to the page. ;elative positions the element where it normally would be and offsets it by whatever amount you specify. .ost ,-T./ is done with absolutely positioned elements. ;elatively positioned elements do not accept the 'clip' style and do not allow their clipping to be changed. The useful feature of relatively positioned elements is that they become containers for absolutely positioned elements. So if you put an absolutely positioned element inside a relatively positioned element its position will be in relation to the relatively positioned element and not the whole page. *ou can create an absolutely positioned elements using this$
<div id="mydiv" style="position6 absol1te. left6 9:px. top6 94:px.">contents</div>

And you can create an relatively positioned elements using this$


<div id="mydiv" style="position6 relative. left6 9:px. top6 94:px.">contents</div>

The I, is important because that is what will be used to reference the positioned element. /ayers browsers call these positioned elements 'layers'.

9ugs % workaroun s If using document.write to create the positioned element "etscape A will fail to load the page. "etscape A is not really important any more so I suggest you ignore it. If you really need to support it you can use the unofficial <layer """> tag instead of an absolutely positioned div and the unofficial <ilayer """> tag instead of of a relatively positioned div. @se if/ doc1ment"layers 0 to find out if you need to. Similarly in "etscape A setting any styles using inline style attributes on elements inside a positioned element will cause the page not to load. Instead create a class for the elements and style them in the main stylesheet.

&eferencing the positione element

i+ab =- does not support positioning but it can still reference the unpositioned element.

To reference a positioned element there are several ways. The official one is a standard called the ):+,6.. It is supported well enough by almost all current browsers. There are also two alternatives for the few old browsers that may still be in use. 6ne of these techni%ues has two different versions.

D*M ,6. browsers use the doc1ment"getOlementSy5d method to reference the element. *ou can use a simpleif statement to chec! for the e#istence of this method.
if/ doc1ment"getOlementSy5d 0F var myNeference = doc1ment"getOlementSy5d/,div5(,0. G

0roprietar! D*M 5roprietary ,6. browsers use the doc1ment"all collection to reference the element. Some browsers support both the ,6. and proprietary ,6. for referencing elements.
if/ doc1ment"all 0F

var myNeference = doc1ment"all&,div5(,*. G

La!ers /ayers browsers use the doc1ment"layers collection to reference the element. /ayers in the layers collection can be accessed using either their I, or their numerical inde#. They will also be able to reference the element through doc1ment"div5( 0where divI, is the id that you gave the div1. "etscape A is the main layers browser and was the first browser capable of performing ,-T./. -owever the layers approach has been abandoned by current browsers.
if/ doc1ment"layers 0F var myNeference = doc1ment"layers&,div5(,*. G

/ayers also have one behaviour that sets them apart from the other approached and can ma!e them difficult to write for. If a positioned element is inside another positioned element the inner one does not appear inside the layers collection of the document. Instead it appears inside the layers collection for the document ob4ect of the outer layer. This means that that to reference any layer by its I, you must recursively step through every layers collection in the document until you find the right one. Since I, attributes must be uni%ue within a document anyway this approach is needlessly convoluted which is one of the reasons why it was abandoned.

)ombining the approaches The three techni%ues can be combined into a single function that will use the ,6. method if it is available. Failing that it will use the proprietary ,6. and failing that layers. If it fails to find it in the document's layers collection it steps through the entries in the collection and chec!s the layers collection of each of those and continues recursively.
f1nction getNefTo(iv/div5(2o(oc0 F if/ doc1ment"getOlementSy5d 0 F ret1rn doc1ment"getOlementSy5d/div5(0. G

if/ doc1ment"all 0 F ret1rn doc1ment"all&div5(*. G if/ #o(oc 0 F o(oc = doc1ment. G if/ doc1ment"layers 0 F if/ o(oc"layers&div5(* 0 F ret1rn o(oc"layers&div5(*. G else F //repeatedly r1n thro1gh all child layers for/ var x = :2 y. #y PP x < o(oc"layers"length. x%% 0 F //on s1ccess2 ret1rn that layer2 else ret1rn nothing y = getNefTo(iv/div5(2o(oc"layers&x*"doc1ment0. G ret1rn y. G G ret1rn false. G

)hanging the visibilit!



i+ab =- does not support visibility. 6mni)eb A.=- fre%uently ma!es mista!es with visibility. .any device browsers will ignore visibility when in small screen reformatting mode.

+hanging the visibility style allows you to ma!e a positioned element appear and disappear. It can be set to either ,visible, or ,hidden,. /ayers browsers use ,show, and ,hide,. There are some layers browsers that support both versions. The code here will detect what is supported and use it instead of detecting one thing and assuming something else. 6nce you have referenced the positioned element you will need to reference its style. In non-layers browsers you will have to add '"style' to the end of the reference. /ayers browsers treat the styles as direct properties of the element itself. To wor! out which one to use simply chec! for the e#istence of the styleproperty. *ou can then set the relevant value$ So after all of that a full set of instructions to ma!e a positioned element visible would be$
f1nction show(iv/div5(3as3a3string0 F

//get a reference as above """ myNeference = getNefTo(iv/div5(3as3a3string0. if/ #myNeference 0 F window"alert/,Aothing wor!s in this browser,0. ret1rn. //don,t go any f1rther G //now we have a reference to it if/ myNeference"style 0 F //(8H P proprietary (8H myNeference"style"visibility = ,visible,. G else F //layers syntax myNeference"visibility = ,show,. G G

show(iv/,my(iv,0.

"""

"""

<div style="position6absol1te.left6:px.top6:px." id="my(iv"> contents </div>

Test it here$ show the hidden element.

6f course don't actually alert the message '"othing wor!s in this browser' instead offer them an alternative that does not re%uire the fancy script.

)hanging the position



i+ab =- does not support positioning. 6mni)eb A.=- does not understand relative positioning and ma!es mista!es with absolute positioning. )ebT( can only change hori7ontal position not vertical. +lue browser sometimes only allows hori7ontal position to be changed and sometimes does not allow

positions to be changed at all.

*ou can ad4ust the position by using left or top the same way as we used visibility above and then specifying the position in pi#els. 0"ote this top is not the same as the window"top mentioned in the section on frameset references.1 In order to retrieve the left and top properties as I am about to do the left andtop styles must have been set using the inline style synta# or by being initially set with JavaScript. )hen a strict doctype is used many browsers re%uire you to use the correct units 0=Gp# not =G1 but many older browsers do not understand this such as 6pera H 0,top, only1 layers browsers )ebT( etc. There is no direct way to detect if a browser understands the units or not since it may accept the values even if it does not support them. For this reason I detect doc1ment"childAodes as this is one of the basic re%uirements for proper ,6. support. ,6. style re%uires units to be used and therefore all browsers that understand ,6. also understand the units. In this e#ample left and top are both initially set to <Gp# using an inline style attribute. The code will chec! if it needs to use a '"style' reference and if so it will change the reference the style ob4ect instead allowing the style to be changed for all versions in 4ust one step. It will then retrieve the current positions add on the new amount and set that as the new position. )hen it retrieves the current value it uses parseInt because the value may contains the units depending on the browser.
<div style="position6absol1te.left69:px.top69:px." """

""" """

var noCx = doc1ment"childAodes T ,px, 6 :.

if/ myNeference"style 0 F myNeference = myNeference"style. G myNeference"left = / parse5nt/myNeference"left0 % 9: 0 % noCx. myNeference"top = / parse5nt/myNeference"top0 % 4: 0 % noCx.

The div will move <G pi#els down and =G pi#els to the right. It will now be at coords - top$ :Gp#2 left$ =G p#2 Test it here$ move this element. This can %uite easily be used along with a timer which fires every few milliseconds and repositions a positioned element according to the scrolling offset to ma!e the element appear static on the screen 0position6fixed. is preferred however1.

)hanging the backgroun colour



6ld 8ec!o browsers have bugs that are easily avoided. See my 8ec!o engine mouseout bug )ebT( and 6mni)eb A.=- do not allow you to change the bac!ground colour.

documentation.

It would be nice to change the te#t colour as well but layers browsers cannot do that. To change the bac!ground colour there are three ways. /ayers browsers use bg'olor. ,6. and proprietary ,6. browsers can
1se bac!gro1nd and bac!gro1nd'olor.

6pera

H.#

can

only

change

the bac!gro1nd style all the others 0including 6pera MJ1 can change both. ,myNeference, must be obtained as above. "ote2 some versions of 6pera H will only change the bac!ground colour if it has already been e#plicitly defined and is not inherited. )arning 6pera I-I.< will return the string ')arning' if you chec! for bg'olor - so if you are chec!ing for which one to change you must put that synta# last.
if/ myNeference"style 0 F myNeference = myNeference"style. G if/ myNeference"bac!gro1nd 0 F //s1pported by most browsers //li!e Bec!o browsers and the 5O series myNeference"bac!gro1nd = ,W::ff::,.

G else if/ myNeference"bac!gro1nd'olor 0 F //s1pported by most browsers myNeference"bac!gro1nd'olor = ,W::ff::,. G else if/ myNeference"bg'olor 0 F //1sed by layers browsers myNeference"bg'olor = ,W::ff::,. G else F //7)5RINO2 there is no way to change the bac!gro1nd colo1r G

As setting the wrong one will not cause any problems this can be easily simplified to$
if/ myNeference"style 0 F myNeference = myNeference"style. G myNeference"bg'olor = ,W::ff::,. myNeference"bac!gro1nd = ,W::ff::,. myNeference"bac!gro1nd'olor = ,W::ff::,.

Test it here$ change the bac!ground colour of this element.

)hanging the <2in ex



i+ab =- does not support positioning so cannot support 7-inde#. )ebT( and +lue browser do not support 7-inde#.

The Y$index of positioned elements defines what order they should be stac!ed above each other. TheY$index should be a positive integer. The higher the Y$index the more positioned elements it will be stac!ed on top of. Two elements must not be given the same Y$index. To read the Y$
index of a positioned element it must be already defined using the inline style synta#.
if/ myNeference"style 0 F myNeference = myNeference"style. G

myNeference"Y5ndex = 9::.

Test it here$ +lic! the lin! in each positioned element to raise its Y$index above the Y$index of the other element. 3lement Increase its 7-inde#. 3lement Increase its 7-inde#. =. <.

)hanging the clipping



6pera M- Uon%ueror :.G- 6mni)eb A.=- )ebT( "etFront :.:- i+ab =- and T!html -v: do not support Internet 3#plorer I- does not follow current standards when using >standards rendering mode> and needs In 6pera I-I.< 0fi#ed in later releases1 the bac!ground colour shows through the clipping on clipped Although 3scape A.# supports the style ob4ect it does not support the style.clip synta#.

clipping 0i+ab =- does not support positioning so cannot support clip1. special attention as shown below. elements. The solution is to clip one element and hold a coloured element inside it.

+lipping can only be used on absolutely positioned elements. This techni%ue is usually used for message scrollers. In browsers that do not support clipping it is possible to provide them with an iframe so that the contents of that can be scrolled. 5lease see my scroller e#ample for a more detailed e#plaination of what clipping is and how it wor!s. *ou may want to chec! that the element can be clipped 0there is no real need to as browsers that do not understand it will 4ust ignore you1. This is very difficult as browsers li!e 6pera M- will give 'rect01' if as!ed for the clip style but have no way of using it. I have found no good way to do this. The best I can do is to chec! ifmyNeference"inner-THR and myNeference"clip are supported. I do not !now of any browsers that should have problems with this as they support inner-T./ but not clipping but do give 'rect01' if as!ed for the clip style. -owever setting the clipping in browsers that do not support it will not cause errors it 4ust has no effect. As 3scape supports the style ob4ect but does not support the style.clip synta# it is important to ma!e sure it uses the clip ob4ect instead so this is put first.
if/ myNeference"clip 0 F myNeference"clip"left = :.

myNeference"clip"top = :. myNeference"clip"right = 9:. myNeference"clip"bottom = 9:. G else if/ myNeference"style 0 F //top right bottom left myNeference"style"clip = ,rect/:px29:px29:px2:px0,. G else F //7)5RINO2 nothing wor!s G

Test it here$ select a clipping rectangle for the positioned element below. The bac!ground shows through wherever the clipping hides parts of the element$

/ine

rect0Gp# =HGp# =Gp# Gp#1 rect0<Gp# =HGp# :Gp# Gp#1 rect0=Gp# =HGp# AGp# Gp#1
one of the positioned element. 'ac!ground *our browser does not support clipping.

/ine two of the positioned element. 'ac!ground 'ac!ground 'ac!ground 'ac!ground 'ac!ground

"ote that although the +SS =.< standard re%uires browsers to support rect/0 with commas between parameters Internet 3#plorer M and I do not apply the rule if it contains commas if the page's ,6+T*53 triggers >standards rendering mode>. 0This is due to a mista!e in the +SS =.G specification.1 "ote that this only applies when the style is set with a stylesheet2 if set with a script it will wor! with the correct synta#. To avoid this problem simply set the style twice in the stylesheet once with commas and once without. 'rowsers will use whichever version they understand.

)hanging the si<e



)ebT( cannot change element si7e. 3scape&3vo H will produce errors because I chec! for document.child"odes. I+3browser will change element si7e but may not show any change until the browser window is resi7ed.

i+ab =- produces strange overlaps when changing si7e because it does not support positioning. In +lue browser the element may 4ust disappear.

/ayers browsers e#pect you to use the resiYeTo method while a few browsers e#pect you to change the pi#el)idth and pi#el-eight properties of the style ob4ect. All other browsers e#pect you to change the height and width properties of the syle ob4ect. *ou can set these last two anyway reguardless of what the browser e#ects because the browser will 4ust ignore them. Some browsers will not re-arrange the contents of the element to suit the new si7e. In layers browsers this is e%uivalent to setting clip"bottom and clip"right which are the properties that should be read to get the current si7e. Although this is not accurate as the layer could e#tend beyond either of these clips it is the best that layers browsers provide. To change only width or height in layers browsers you must change the right or bottom properties of the clip ob4ect. Some browsers will not shrin! the element smaller than its contents. Some will clip the contents to the new si7e. Some will rearrange the contents to fit the new si7e. Some will shrin! the element but leave the contents as they were still visible. As with element position some older browsers do not li!e to have the units 0p#1 written after the si7e while newer browsers re%uire it for strict doctypes. Again a %uic! detect sorts the good browsers from the not-so-good.
if/ myNeference"style 0 F myNeference = myNeference"style. G if/ myNeference"resiYeTo 0 F myNeference"resiYeTo/ newMidth2 new-eight 0. G var noCx = doc1ment"childAodes T ,px, 6 :. myNeference"width = newMidth % noCx. myNeference"pixelMidth = newMidth. myNeference"height = new-eight % noCx. myNeference"pixel-eight = new-eight.

Try it here$ select a new si7e for the element$


=G # =G :G # AG

bac! to HG # HG

Test Test

&ewriting the contents



6pera M- and 6mni)eb A.=- cannot rewrite the contents of positioned elements. )ebT( may 4ust crash. /ayers browsers can only rewrite the contents of absolutely positioned elements. "etscape A loses style in positioned elements when their contents are rewritten. In +lue browser the element may 4ust disappear along with the document below it.

In the following e#ample

my;eference is obtained as before. .ost browsers provide

the inner-THRproperty which you can rewrite with the new -T./. /ayers browsers allow you to use the methods open write and close on the document ob4ect of the layer. Some browsers 0li!e 6pera1 will also provide thedoc1ment property of the positioned element but that is a reference bac! to the main document. ;ewriting that will cause no end of problems so we must chec! that this is not the case first.
if/ typeof/ myNeference"inner-THR 0 #= ,1ndefined, 0 F //1sed by all c1rrent browsers myNeference"inner-THR = ,some <b>new</b> content,. G else if/ myNeference"doc1ment PP myNeference"doc1ment #= window"doc1ment 0 F //1sed by layers browsers myNeference"doc1ment"open/0. myNeference"doc1ment"write/,some <b>new</b> content,0. myNeference"doc1ment"close/0. G

It is also possible to e#tend support to 6pera H and M if needed by providing an iframe 0which should be given a name attribute1 chec!ing if it has loaded then rewriting its contents$

if/ typeof/ myNeference"inner-THR 0 #= ,1ndefined, 0 F //1sed by all c1rrent browsers myNeference"inner-THR = ,some <b>new</b> content,. G else if/ myNeference"doc1ment PP myNeference"doc1ment #= window"doc1ment 0 F //1sed by layers browsers myNeference"doc1ment"open/0. myNeference"doc1ment"write/,some <b>new</b> content,0. myNeference"doc1ment"close/0. G else if/ window"frames PP window"frames"length PP window"frames&,name8f5frame,* 0 F //1sed by browsers li!e 8pera <$ myNeference = window"frames&,name8f5frame,*"window. myNeference"doc1ment"open/0. myNeference"doc1ment"write/,some <b>new</b> content,0. myNeference"doc1ment"close/0. G

Test it here$ rewrite the contents of the positioned element below 0the 6pera H-M wor!around is not included1. This is the positioned element. The contents have not yet been rewritten.

)reating new positione elements



6pera M- and 6mni)eb A.=- "etFront :.=- and +lue browser cannot create positioned elements once the )ebT( will replace the entire content of the parent element as it incorrecty always reads inner-T./ as a i+ab =- cannot position the element and should create them as unpositioned elements.

page has loaded. blan! string.

As the page is loading we can create new positioned elements using doc1ment"write or 4ust regular -T./. 6nce the page has loaded Hth generation browsers allow us to create any new

elements but some Ath generation browsers also allow us to create elements after the page has loaded. .ost browsers allow the inner-THR property of an element to be manipulated 0the Internet 3#plorer series also provide insert)djacent-THR but most other ,6. browsers do not include it1. /ayers browsers 0with the e#ception of 6mniweb A.=-1 provide a constructor that creates new empty layers whose contents can then be written. 'efore trying to use this constructor we must chec! it e#ists. Although 6mni)eb A.=provides the Rayer constructor using it causes errors so I use doc1ment"classes to isolate 6mni)eb A.=- and protect it from the script. )ith the layers synta# the new layer is entered into the layers collections using its numerical inde# but is not entered into the collection with a name so we can add it there ourselves if we want to. )e also have to specify a nominal ma#imum width. It will be positioned differently in different layers browsers so we have to position it e#actly ourselves. It will be hidden so we must show it. )ith the inner-THR synta# we can create A"* new content but to be cross browser I will create a positioned element. 6pera I-I.< incorrectly strips all e#isting tags in the parent element of their style attributes when reading inner-T./ producing an odd effect. To combat this I use insertAd4acent-T./ if the browser provides it as this does not produce problems. This first e#ample will create a new positioned element as a child of the document.
if/ doc1ment"layers PP window"Rayer PP doc1ment"classes 0 F //create a layer ;@:px wide doc1ment"layers&,newAame,* = new Rayer/ ;@: 0. //write its content doc1ment"layers&,newAame,*"doc1ment"open/0. doc1ment"layers&,newAame,*"doc1ment"write/,new content,0. doc1ment"layers&,newAame,*"doc1ment"close/0. //style it doc1ment"layers&,newAame,*"left = :. doc1ment"layers&,newAame,*"top = :. doc1ment"layers&,newAame,*"visibility = ,show,.

G else if/ doc1ment"body 0 F var theString = ,<div style="position6absol1te.left6:px.top6:px., % ,width6;@:px.">new content</div>,. if/ doc1ment"body"insert)djacent-THR 0 F doc1ment"body"insert)djacent-THR/ ,beforeOnd,2 theString 0. G else if/ typeof/ doc1ment"body"inner-THR 0 #= ,1ndefined, 0 F doc1ment"body"inner-THR %= theString. G else F //7)5RINO2 nothing wor!s G G else F //7)5RINO2 nothing wor!s G

Th ne#t e#ample will create a new positioned element as a child of an e#isting positioned element 0my;eference is obtained as above1$
if/ doc1ment"layers PP window"Rayer PP doc1ment"classes 0 F //create a layer ;@:px wide doc1ment"layers&,newAame,* = new Rayer/ ;@:2 myNeference 0. //write its content doc1ment"layers&,newAame,*"doc1ment"open/0. doc1ment"layers&,newAame,*"doc1ment"write/,new content,0. doc1ment"layers&,newAame,*"doc1ment"close/0. //style it doc1ment"layers&,newAame,*"left = :.

doc1ment"layers&,newAame,*"top = :. doc1ment"layers&,newAame,*"visibility = ,show,. G else F var theString = ,<div style="position6absol1te.left6:px.top6:px., % ,width6;@:px.">new content</div>,. if/ myNeference"insert)djacent-THR 0 F myNeference"insert)djacent-THR/ ,beforeOnd,2 theString 0. G else if/ typeof/ myNeference"inner-THR 0 #= ,1ndefined, 0 F myNeference"inner-THR %= theString. G else F //7)5RINO2 nothing wor!s G G

Test it here$ create a new element 0new elements will alternate in colour and will be slightly offset from each other to ma!e it more easy to see what is happening1. This is the original content of the e#isting positioned element. It will not be changed.

)hanging the backgroun colour of the whole ocument



6pera H 6mni)eb A.=- and 3scape&3vo cannot change the bac!ground colour of the document 03scape 6pera M and +lue browser will only change the colour behind the content the original bac!ground colour will "etFront :.:- will allow you to set the colour to '' but will not show any change until you scroll.

will change the bac!ground colour but only at the very end of the document after all of the content1. remain where the content is smaller than the window.

There are three ways to change the bac!ground colour. 6ld browsers use the bg'olor property to style the bac!ground of the entire document. In current browsers the -T./ element and the '6,* element are rendered separately by default with the -T./ element ta!ing up 4ust a few pi#els outside the '6,*. They are able to be styled separately so to change the document bac!ground

both of them need to be changed. The -T./ element is referenced in these browsers as doc1ment"doc1mentOlement and the '6,* is referenced as doc1ment"body. Setting the wrong one will not cause errors 0as long as they e#ist1 so I set all of them at the same time.
if/ doc1ment"doc1mentOlement PP doc1ment"doc1mentOlement"style 0 F doc1ment"doc1mentOlement"style"bac!gro1nd'olor = ,red,. G if/ doc1ment"body PP doc1ment"body"style 0 F doc1ment"body"style"bac!gro1nd'olor = ,red,. G doc1ment"bg'olor = ,red,.

Test it here$ change the bac!ground colour of this document to$


CfMfMfM Cd=cbff CIIIIII '' 0returns to default1 - not allowed by some old browsers

)hanging the ispla! st!le of an! element



)ebT( does not support the display style. !arningJ "etscape A 3scape A 6pera M- 6mni)eb A.=- "etFront :.=- and +lue browser support the i+ab =- sometimes ma!es mista!es with rendering when changing the display style and interprets 'bloc!' as .any device browsers will ignore the display style when in small screen reformatting mode. Internet 3#plorer A on )indows does not understand inline display. 3scape A does actually allow you to change the display style 0only bloc! inline and none accepted1 using

display$ none2 style but do not allow JavaScript to change it. See the guidelines below. 'return to default'.

the style ob4ect but only on layers and ilayers. Since the best use of the display style is for unpositioned elements and considering that changing from none to inline or bloc! has no effect in 3scape until the window is resi7ed i do not recommend even attempting it.

"6T3$ most ma4or browsers support the display style and can be told to display any element li!e an inline element 0display6inline.1 li!e a bloc! element 0display6bloc!.1 or not to display it at all0display6none.1. Some also support many other display styles. -owever not all browsers allow

the display style to be changed with JavaScript so if the display style is initially set to 'none' and then you attempt to set it to 'bloc!' or '' the display style will not actually change and the content will remain invisible. For this reason it is best to change the display style with script after the page has loaded. 'rowsers that do not understand it will 4ust ignore you and allow the user to view the content. It may not be as neat as being able to show and hide it but at least they will be able to see it. The display style is different from the visibility style. Setting the visibility style to ,hidden, will hide the element from view but will leave the space for it. Setting the display style to ,none, will remove it from view and will re-arrange the contents of the page to fill the hole. This can ma!e the feature very useful for menu systems as with very simple programming the browser can ta!e care of all the re-arranging to ma!e the page loo! nice again. 'rowsers that allow elements to have their display style changed will all

use doc1ment"getOlementSy5d ordoc1ment"all not doc1ment"layers. This ma!es life slightly easier. 6f course it is nice to be able to tell users that this will not wor! in their browser so we will want to detect if the browser allows us to change the display style first. To do this we must initially set the display style using inline style sheets with it set the the element's default display 0,inline, for elements li!e spans and bloc! for elements such as paragraphs or ,I(1.

The HTML In this e#ample I will have a span inside a paragraph


<p>This is a paragraph" <span style="display6inline." id="aIniV1e5d">This is a span within the paragraph whose display style has been set to ,inline, 1sing an inline style sheet"</span> This is another sentence in the paragraph2 b1t not in the span"<p>

$"e JavaScript
f1nction change(isplay/ element5d2 setTo 0 F var theOlement.

if/ doc1ment"getOlementSy5d 0 F //(8H theOlement = doc1ment"getOlementSy5d/ element5d 0. G else if/ doc1ment"all 0 F //Croprietary (8H theOlement = doc1ment"all& element5d *. G if/ #theOlement 0 F / The page has not loaded2 or the browser claims to

s1pport doc1ment"getOlementSy5d or doc1ment"all b1t cannot act1ally 1se either ret1rn. G //Neference the style """ if/ theOlement"style 0 F theOlement = theOlement"style. G if/ typeof/ theOlement"display 0 == ,1ndefined, 0 F //The browser does not allow 1s to change the display style //)lert something sensible /not what 5 have here """0 window"alert/ ,Ko1r browser does not s1pport this, 0. ret1rn. G //'hange the display style theOlement"display = setTo. G /

Try it here$ select a display style for the span in the paragraph below$

'' 0default1 'inline' 'bloc!' 'none'

This is a paragraph. $"is is a span wit"in t"e paragrap" w"ose display style "as been set to DinlineD using an inline style s"eet3 This is another sentence in the paragraph but not in the span.
Element contents

The ,6. provides an easy way to reference all elements no matter where they are in a document. -owever it is possible to reference many elements in a way that wor!s in ,6. browsers and older browsers. This can be useful if you need your scripts to wor! in browsers li!e "etscape A even though they are not used very much any more. /ayers browsers li!e "etscape A are different to all other browsers. They give each positioned element a newdoc1ment ob4ect. All forms images lin!s and child layers inside that layer must be referenced through this new document ob4ect. So instead of doc1ment"formname it becomes myNeference"doc1ment"formname etc.

How to reference an!thing in a generic wa! .acro.edia first came up with a generic 'wysiwyg' reference-all function. It could reference images and forms and all types of layers. This would loo! for any ob4ect with a name or id that matched the re%uired name. Inspired by that I have written my own 0completely separately1 that could also reference a few other things. It is a little larger as a result. The only thing it cannot reference is a lin! ob4ect because by their nature lin! ob4ects are only accessible using their numerical inde#. Also unli!e anchor ob4ects the name attribute is not accessible with lin! ob4ects even if they have one. If referred to using the anchors collection the lin! properties are not available although the name attribute is. 'y chec!ing every anchor to see if its name matches the re%uested name I can reference the correct anchor. -owever I cannot reference the lin!. "ote that if the name refers to inputs in a form that share the same name this function will return the collection of inputs sharing that name.
f1nction HMJ3find8bj/ oAame2 o7rame2 o(oc 0 F

if not wor!ing on a layer2 doc1ment sho1ld be set to the

doc1ment of the wor!ing frame if the wor!ing frame is not set2 1se the window object of the c1rrent doc1ment M)NA5AB6 $ cross frame scripting will ca1se errors if yo1r page is in a frameset from a different domain /

if/ #o(oc 0 F if/ o7rame 0 F o(oc = o7rame"doc1ment. G else F o(oc = window"doc1ment. G G

//chec! for images2 forms2 layers if/ o(oc&oAame* 0 F ret1rn o(oc&oAame*. G

//chec! for p(8H layers if/ o(oc"all PP o(oc"all&oAame* 0 F ret1rn o(oc"all&oAame*. G

//chec! for (8H layers if/ o(oc"getOlementSy5d PP o(oc"getOlementSy5d/oAame0 0 F ret1rn o(oc"getOlementSy5d/oAame0. G

//chec! for form elements for/ var x = :. x < o(oc"forms"length. x%% 0 F if/ o(oc"forms&x*&oAame* 0 F ret1rn o(oc"forms&x*&oAame*. G G

//chec! for anchor elements //A8TO6 only anchor properties will be available2

//A8T lin! properties /in layers browsers0 for/ var x = :. x < o(oc"anchors"length. x%% 0 F if/ o(oc"anchors&x*"name == oAame 0 F ret1rn o(oc"anchors&x*. G G

//chec! for any of the above within a layer in layers browsers for/ var x = :. doc1ment"layers PP x < o(oc"layers"length. x%% 0 F var the8b = HMJ3find8bj/ oAame2 n1ll2 o(oc"layers&x*"doc1ment 0. if/ the8b 0 F ret1rn the8b. G G

//chec! for frames2 variables or f1nctions if/ #o7rame PP window&oAame* 0 F ret1rn window&oAame*. G if/ o7rame PP o7rame&oAame* 0 F ret1rn o7rame&oAame*. G

//if chec!ing thro1gh frames2 chec! for any of the above within //each child frame for/ var x = :. o7rame PP o7rame"frames PP x < o7rame"frames"length. x%% 0 F var the8b = HMJ3find8bj/ oAame2 o7rame"frames&x*2 o7rame"frames&x*"doc1ment 0. if/ the8b 0 F ret1rn the8b. G G

ret1rn n1ll. G

without comments this becomes$


f1nction HMJ3find8bj/ oAame2 o7rame2 o(oc 0 F

if/ #o(oc 0 F if/ o7rame 0 F o(oc = o7rame"doc1ment. G else F o(oc = window"doc1ment. G G if/ o(oc&oAame* 0 F ret1rn o(oc&oAame*. G if/ o(oc"all PP o(oc"all&oAame* 0 F ret1rn o(oc"all&oAame*. G if/ o(oc"getOlementSy5d PP o(oc"getOlementSy5d/oAame0 0 F ret1rn o(oc"getOlementSy5d/oAame0. G for/ var x = :. x < o(oc"forms"length. x%% 0 F if/ o(oc"forms&x*&oAame* 0 F ret1rn o(oc"forms&x*&oAame*. G G for/ var x = :. x < o(oc"anchors"length. x%% 0 F if/ o(oc"anchors&x*"name == oAame 0 F ret1rn o(oc"anchors&x*. G G for/ var x = :. doc1ment"layers PP x < o(oc"layers"length. x%% 0 F var the8b = HMJ3find8bj/ oAame2 n1ll2 o(oc"layers&x*"doc1ment 0. if/ the8b 0 F ret1rn the8b. G G if/ #o7rame PP window&oAame* 0 F ret1rn window&oAame*. G if/ o7rame PP o7rame&oAame* 0 F ret1rn o7rame&oAame*. G for/ var x = :. o7rame PP o7rame"frames PP x < o7rame"frames"length. x%% 0 F var the8b = HMJ3find8bj/ oAame2 o7rame"frames&x*2 o7rame"frames&x*"doc1ment 0. if/ the8b 0 F ret1rn the8b. G G ret1rn n1ll. G

This function can be called in two ways2 to reference an item in the current document$
var the8b = HMJ3find8bj/ Aame8r5d 0.

To reference an item in any other document in a frameset you can choose how high in the frame structure to start. ;emember that if using 'top' someone else may load your page in their frameset and this will produce an error.
var the8b = HMJ3find8bj/ Aame8r5d2 NeferenceToTopHost7rameToSearch 0.

!indow siEe and scrolling

:in ing the si<e of the browser win ow



+lue browser can only wor! out window width. T!html -v: has the body&document3lement client-eight&)idth values reversed - versions before September

=GGI also do not support inner-eight&)idth so they cannot wor! with this script.

There are some constants available that give the document area of the window that is available for writing to. These will not be available until after the document has loaded and the method used for referencing them is browser specific. The available constants are$
window"inner-eight/Midth

5rovided by most browsers but importantly not Internet 3#plorer.


doc1ment"body"client-eight/Midth

5rovided by many browsers including Internet 3#plorer.


doc1ment"doc1mentOlement" client-eight/Midth

5rovided by most ,6. browsers including Internet 3#plorer. This is a little messy because the client-eight/Midth properties can mean different things in different browsers and even different things in the same browser depending on whether the document type declaration triggers the browser's strict mode or %uir!s mode. In some cases they refer to the dimensions of the window and sometimes they refer to the dimensions of the contents of the document. The table below shows what the properties mean in different browsers and different modes$ 5roperties and what they relate to documen window t Browser inner!ei body "ht client!ei "ht Opera $ %& strict

document document#le ment client!ei"ht

window

document window

5roperties and what they relate to documen window t Browser inner!ei body "ht client!ei "ht Opera $ %& quir's

document document#le ment client!ei"ht

window

window

document

Opera ()$ * window Opera + window

window window

document !-

Mo,illa strict window Mo,illa quir's -!.M/ 0a1ari i2ab 3 i2ab * 4# +& strict

document window

window

window

document

window window window window !-

document document document document document document window !-

document window window window window window !+ !document document !-

4# %)( quir's !4# 5 42#browser .'html !v3 6etscape 5 !window window window

As you can see the browsers seem to have settled on at least one reliable property2 inner-eight. Internet 3#plorer is the one that cannot ma!e up its mind and its influence means that other browsers change theirclient-eight behaviour in different versions in order to match it. For now almost all browsers providewindow"inner-eight/Midth so that can be used. Internet 3#plorer has chosen to swap the values around when it is in strict mode. Fortunately it gives G in %uir!s mode. This means that if we see a value on thedoc1mentOlement,s properties and the browser does not provide the properties on the window ob4ect we can assume it is Internet 3#plorer in strict mode. The most accurate method I could come up with uses the following algorithm although it may have problems with future browsers a situation which I am definitely not happy with$ <. If window.inner-eight&)idth is provided that is fully trustworthy use that 0-oorayY1. =. 3lse if document.document3lement.client-eight&)idth is provided and either one is greater than G use that. :. 3lse use document.body.client-eight&)idth. This algorithm will fail with I3 MJ in 'standards compliant mode' if the window is shrun! to Gp# by Gp#. This is only possible when the user actively shrin!s the window to hide the page within it. 3ven then it will 4ust give the height of the document instead so it should not be a problem. The following code performs the algorithm as described.
f1nction alertSiYe/0 F var myMidth = :2 my-eight = :. if/ typeof/ window"innerMidth 0 == ,n1mber, 0 F //Aon$5O myMidth = window"innerMidth. my-eight = window"inner-eight. G else if/ doc1ment"doc1mentOlement PP / doc1ment"doc1mentOlement"clientMidth QQ doc1ment"doc1mentOlement"client-eight 0 0 F //5O <% in ,standards compliant mode, myMidth = doc1ment"doc1mentOlement"clientMidth. my-eight = doc1ment"doc1mentOlement"client-eight.

G else if/ doc1ment"body PP / doc1ment"body"clientMidth QQ doc1ment"body"client-eight 0 0 F //5O ? compatible myMidth = doc1ment"body"clientMidth. my-eight = doc1ment"body"client-eight. G window"alert/ ,Midth = , % myMidth 0. window"alert/ ,-eight = , % my-eight 0. G

Test it here$ get the inner dimensions of this window. "ote that browsers may ta!e the width either inside or outside the scrollbar 0if there is one1. I do not cover any way to wor! with these differences.

:in ing how far the win ow has been scrolle



6mni)eb A.=- "etFront :.:- and +lue browser do not provide any way to do this. Safari and 6mni)eb A.HJ have bugs that do not affect this script - see below.

)hen trying to produce document effects li!e falling snow or more serious things li!e menus that remain in the same place relative to the browser window when the user scrolls it is essential to be able to obtain the scrolling offsets in both the hori7ontal and vertical direction. There are also three ways to find this out but it is easier than finding the si7e of the window. .ost browsers provide window"pageX8ffset/pageK8ffset. These are completely reliable. 6nce again Internet 3#plorer is the odd one out as it does not provide these properties. Internet 3#plorer and some other browsers will provide doc1ment"body"scrollReft/Top. In strict mode I3 M and a few other browsers providedoc1ment"doc1mentOlement"scrollReft/Top. If the scrollReft/Top properties are provided on either

the doc1ment"body ordoc1ment"doc1mentOlement they are reliable in everything e#cept Safari and 6mni)eb A.HJ which return -L if the scrolling is G but get all other scrolling offsets correct. -owever as they correctly providewindow"pageX8ffset/pageK8ffset this script will not have any problems.

The following script will obtain the scrolling offsets.


f1nction getScrollXK/0 F var scr8fX = :2 scr8fK = :. if/ typeof/ window"pageK8ffset 0 == ,n1mber, 0 F //Aetscape compliant scr8fK = window"pageK8ffset. scr8fX = window"pageX8ffset. G else if/ doc1ment"body PP / doc1ment"body"scrollReft QQ doc1ment"body"scrollTop 0 0 F //(8H compliant scr8fK = doc1ment"body"scrollTop. scr8fX = doc1ment"body"scrollReft. G else if/ doc1ment"doc1mentOlement PP / doc1ment"doc1mentOlement"scrollReft QQ doc1ment"doc1mentOlement"scrollTop 0 0 F //5O< standards compliant mode scr8fK = doc1ment"doc1mentOlement"scrollTop. scr8fX = doc1ment"doc1mentOlement"scrollReft. G ret1rn & scr8fX2 scr8fK *. G

Test it here$ get the scrolling offsets.


Event in#ormation

As with ,-T./ this is always browser specific. )hen an event is triggered the browser !eeps some information about the event that we can use. There are two ways that browsers use to allow us to access this information. ,6. compatible browsers pass the event information to the event handler function as the first argument. Some older browsers also use this version. Internet 3#plorer

and a few other browsers store the event information in an event register which we can access by writing 'window.event'. )e also have to tell the browser what ob4ects should detect what events and we also have to tell it what to do when that ob4ect detects that event. Although it is hardly used now you may want the script to wor! in "etscape A since it is capable of doing this. )ith positioned elements and the document itself "etscape A and 3scape A will need to be told to capture the events first. Some other browsers 0such as .o7illa&Firefo#&"etscape MJ1 may also provide the methods but they do not actually do anything. Some others provide them but do not !now how to use them so you should chec! for the specific 3vent type as well. For e#ample he simplest code used to listen for a !eyup event would 4ust be this$
//8nly Aetscape ? and Oscape ? need this first line if/ doc1ment"capt1reOvents PP Ovent"ZOKIC 0 F doc1ment"capt1reOvents/ Ovent"ZOKIC 0. G doc1ment"on!ey1p = alert!ey. //where alertZey is a f1nction that will handle the event

5roblems can arise if one element detects an event where a parent element also detects it. For e#ample if the document is told to detect when the user presses a !ey and a te#t bo# in the document is also told to detect when the user presses a !ey when the user presses a !ey in the te#t bo# should the document react or the te#t bo#T 6r bothT And in what orderT Some browsers will use capturing to say which element0s1 should detect the event and in what order while some will use bubbling and many will do neither. I will not describe either of these here as they are far beyond the scope of this stage of the tutorial. I will cover them later in the ,6. events part of the tutorial. For a full list of events that elements can detect cross-browser see the section on The JavaScript ob4ect' subsection 'Standard document components. To see what events can be captured using capt1reOvents see the same section subsection 'window.3vent. To see what information is passed about events see the same section sub section '3vent ob4ects. The following e#amples attempt to solve as many problems as possible.

Detecting the ke!up event over the page an extracting the ke! co e=

(arious browsers may restrict which non-printing !eys fire what events. Safari :.<J in particular will not fire

the !eypressevent for any non-printing !eys which in many cases 0such as the Osc !ey1 ma!es it incompatible with all other browsers.

Uon%ueror :.:- Safari <.G and "etFront :.:- can only detect !ey events on te#t bo#es. i+ab :- only passes !ey code information in input bo#es. 'la7er 0a version of "etFront1 detects limited !ey events 0due to the !eyboard handling on the device1 and )ebT( and 3scape A can only detect !ey events on te#t bo#es and may be a little unreliable. 6mni)eb A.=- and 6pera H for .ac do not pass !ey code information. "etscape A on /inu# does not detect any !ey events properly. +lue browser and T!html -v: cannot detect !ey events. I am unsure of the capabilities of "et'o# i5anel .icro'rowser and 6penT( here.

returns nonsense !ey codes 0such as -<DLI:GA1.

"ote that browsers may give different !ey code numbers for !eypad !eys. Also many browsers do not give !ey code numbers for control !eys 0li!e F< delete bac!space alt arrow !eys etc.1. "etscape gives a different !ey code for the letter 'a' to all other browsers. It may be more useful to useString"from'har'ode/!ey3code0 which converts the !ey code bac! to its relevant !ey 0li!e '8' for e#ample1.
//first2 tell the browsers to react to the event if/ doc1ment"capt1reOvents PP Ovent"ZOKIC 0 F //remove this part if yo1 do not need Aetscape ? to wor! doc1ment"capt1reOvents/ Ovent"ZOKIC 0. G / this next line tells the browser to detect a !ey1p

event over the whole doc1ment and when it detects it2 it sho1ld r1n the event handler f1nction ,alert!ey, doc1ment"on!ey1p = alert!ey. /

//now create the event handler f1nction to process the event f1nction alert!ey/e0 F

if/ #e 0 F //if the browser did not pass the event information to the //f1nction2 we will have to obtain it from the event register if/ window"event 0 F //5nternet Oxplorer e = window"event. G else F //total fail1re2 we have no way of referencing the event ret1rn. G G if/ typeof/ e"!ey'ode 0 == ,n1mber, //(8H e = e"!ey'ode. G else if/ typeof/ e"which 0 == ,n1mber, 0 F //AS ? compatible e = e"which. G else if/ typeof/ e"char'ode 0 == ,n1mber, //also AS <%2 HoYilla :"U% e = e"char'ode. G else F //total fail1re2 we have no way of obtaining the !ey code ret1rn. G window"alert/,The !ey pressed has !eycode , % e % 0 F 0 F

, and is !ey , % String"from'har'ode/ e 0 0. G

Test it here$ +lic! this lin! to start & stop !eyup detection then press any !ey to test this script. "ote that some !eys give (3;* odd responses with String.from+har+ode. The only reliable ones are letter and number !eys on the main part of the !eyboard.

Detecting the mouse coor inates when it moves over a positione element

In Internet 3#plorer the mouse position will be offset by the thic!ness of the window border 0which can

detect mouse movements as if it were the page body1. 6n )indows 95 this would typically be = pi#els for the default and classic themes 0meaning when the mouse is at G G it will be reported as = =1 and Gp# in fullscreen mode but it can be different for other themes or operating systems. There is no !nown wor!around for this bug.

i+ab =- cannot detect mouse events over the page itself only over specific elements within it 0such as lin!s1. )ebT( only detects mouse events over lin!s. 6mni)eb A.=- does not provide any information about events. +lue browser only detects mousedown&up events and only over lin!s. I am unsure of the capabilities of "et'o# i5anel .icro'rowser and 6penT( here.

There are three ways that are reliably supported which give mouse coordinates. There is also one unreliable way. All are given as properties of the event ob4ect such as event8bject"clientX. These will be used to obtain the coordinates relative to the entire page. )ith clientX/K the standard was not very well written so some older browsers made mista!es when implementing it. The coordinates should be relative to the displayed portion of the page but 6pera M- Uon%ueror =- and i+ab =- give the coordinates relative to the entire page. There is no easy way to detect if a browser supports it correctly and the only way to write this piece of script is to detect the browsers that do not comply with the standard and provide appropriate scripts. This is the only time I will tell you to do this. +lue browser also ma!es but as it cannot detect scrolling there is no need to compensate. "ote that 6pera IJ Uon%ueror :J and i+ab :J actually comply with the standard but as they also providespageX the script I will show you uses that instead so again the problem is avoided. 6pera M- can be detected because the property ' navigator"1ser)gent' contains the string '6pera' even if it is running in I3H emulation mode. i+ab =- can be detected because its window"ScriptOngine method contains the string 'InScript' even if it is running in emulation

mode. Uon%ueror = can be detected because the property 'navigator"vendor' is 'U,3' even if it is running in emulation mode.

*, If pageX/K is supplied pageX/K is relative to the whole page and is completely reliable. ., If clientX/K is supplied clientX/K should be relative to displayed portion of page 0,6.
compatible1.

3, Sometimes clientX/K is relative to the whole page 0in browsers that did not implement the
specification properly1. .ost browsers provide both pageX/K and clientX/K. Internet 3#plorer is the only current browser that provides clentX/K but not pageX/K. See the last section ')indow si7e and scrolling' for information on how to detect how far the page has been scrolled. See the section on ',-T./' for how to reference the positioned element.
if/ myNeference"capt1reOvents PP Ovent"H8ISOH8+O 0 F //remove this part if yo1 do not need Aetscape ? to wor! myNeference"capt1reOvents/ Ovent"H8ISOH8+O 0. G myNeference"onmo1semove = alert'oord.

f1nction alert'oord/e0 F if/ #e 0 F if/ window"event 0 F //5nternet Oxplorer e = window"event. G else F //total fail1re2 we have no way of referencing the event ret1rn. G G

if/ typeof/ e"pageX 0 == ,n1mber, 0 F //most browsers var xcoord = e"pageX. var ycoord = e"pageK. G else if/ typeof/ e"clientX 0 == ,n1mber, 0 F //5nternet Oxplorer and older browsers //other browsers provide this2 b1t follow the pageX/K branch var xcoord = e"clientX. var ycoord = e"clientK. var bad8ldSrowser = / window"navigator"1ser)gent"index8f/ ,8pera, 0 % 9 0 QQ / window"ScriptOngine PP ScriptOngine/0"index8f/ ,5nScript, 0 % 9 0 QQ / navigator"vendor == ,Z(O, 0. if/ #bad8ldSrowser 0 F if/ doc1ment"body PP / doc1ment"body"scrollReft QQ doc1ment"body"scrollTop 0 0 F //5O ?2 @ P < /in non$standards compliant mode0 xcoord %= doc1ment"body"scrollReft. ycoord %= doc1ment"body"scrollTop. G else if/ doc1ment"doc1mentOlement PP / doc1ment"doc1mentOlement"scrollReft QQ doc1ment"doc1mentOlement"scrollTop 0 0 F //5O < /in standards compliant mode0 xcoord %= doc1ment"doc1mentOlement"scrollReft. ycoord %= doc1ment"doc1mentOlement"scrollTop. G G G else F //total fail1re2 we have no way of obtaining the mo1se coordinates

ret1rn. G window"alert/,Ho1se coordinates are /,%xcoord%,2,%ycoord%,0,0. G

Test it here$ pass your mouse over this lin! to obtain its coordinates. To detect mouse coordinates over the whole document use doc1ment instead of myNeference. Since all the problematic old browser versions have now been replaced with versions that wor! correctly you may want to remove the sniffer and !eep the code clean. *ou may not want to do this if there is a chance that any of your visitors are using those older versions. If that is not a problem for you you could use this code instead$
doc1ment"onmo1semove = alert'oord.

f1nction alert'oord/e0 F var xcoord2 ycoord. if/ #e 0 F e = window"event. G if/ #e 0 F ret1rn. G if/ typeof/ e"pageX 0 == ,n1mber, 0 F xcoord = e"pageX. ycoord = e"pageK. G else if/ typeof/ e"clientX 0 == ,n1mber, 0 F xcoord = e"clientX. ycoord = e"clientK. if/ doc1ment"body PP / doc1ment"body"scrollReft QQ doc1ment"body"scrollTop 0 0 F xcoord %= doc1ment"body"scrollReft. ycoord %= doc1ment"body"scrollTop.

G else if/ doc1ment"doc1mentOlement PP / doc1ment"doc1mentOlement"scrollReft QQ doc1ment"doc1mentOlement"scrollTop 0 0 F xcoord %= doc1ment"doc1mentOlement"scrollReft. ycoord %= doc1ment"doc1mentOlement"scrollTop. G G else F ret1rn. G window"alert/,Ho1se coordinates are /,%xcoord%,2,%ycoord%,0,0. G

Detecting mouse buttons



Uon%ueror Safari on .ac 6mni)eb A.HJ i+ab :J T!html -v: and 3scape A do not detect right clic!s 6pera users can choose to allow scripts to detect right clic!s - enabled by default since 6pera <G. Internet 3#plorer A- Safari <.<- 6pera Uon%ueror I+3'rowser "etFront T!html -v:J "etscape A )ebT( i+ab =- "etFront :.:- and +lue browser do not pass information about mouse buttons. )ebT( cannot detect mousedown or mouseup events. 6mni)eb A.=- does not provide any information about events. I am unsure of the capabilities of "et'o# i5anel .icro'rowser and 6penT( here.

using normal mouse events.

3scape 6mni)eb A.=- )ebT(&.S"T( and +lue browser do not support the oncontextmen1 event.

This e#ample gives two methods for detecting then handling events with an lin! element. 6ne is written using the standard -T./ synta# and one of which is written using JavaScript synta#. It will e#tract the mouse button that triggered the event. "ote$ this may not wor! with 'clic!' events. There is also the onconte#tmenu event that fires in a few browsers when a user activates their conte#t menu but that is not the same thing since it also covers +trlJ+lic! on .acs and the conte#t menu !ey on )indows and /inu#&@"I9 0and is also not very well supported1. The mouse button is passed using either the which or b1tton properties. )ith 'which' < is left button = is middle button : is right button. )ith button the standard says that G is left button < is middle button = is right button but in I3 compatible browsers < is left button A is middle button = is right button. 3scape&3vo H uses a totally different numbering system < is left button = is middle button G is right button - I suggest you ignore 3scape&3vo.

The only time you should ever detect a button is when you want for e#ample to create a drag-drop type effect and you want to ensure they are using the left 0normal dragging1 button. *ou should never abuse it to brea! the user's conte#t menu as that will only ma!e your site inaccessible and annoying for your users and is not reliable anyway. The event registration attribute 0onmo1se1p="etc""1 is e%uivalent to an event handler function and has access to all the usual function information such as the attributes collection. It can get a bit messy writing all of the button detection code in there so I want to pass it to the main handler function. ;emember that in ,6. compatible browsers the first argument is the event so I need to pass that too. I also want the handler to have access to the element that triggered the event so I must pass that.
<script type="text/javascript">

//lin! and form elements do not need to be told to capt1re" //Ising the JavaScript syntax2 we have to wait for the relevant //part of the page to load before telling it to detect the event //This is easiest done with a load event listener window"onload = f1nction /0 F doc1ment"lin!s&:*"onmo1sedown=alertS1t. G

f1nction alertS1t/ e2 evOlement 0 F if/ #e 0 F if/ window"event 0 F //5nternet Oxplorer e = window"event. G else F //total fail1re2 we have no way of referencing the event ret1rn. G

G if/ typeof/ e"which 0 == ,n1mber, 0 F //Aetscape compatible e = e"which. G else if/ typeof/ e"b1tton 0 == ,n1mber, 0 F //(8H e = e"b1tton. G else F //total fail1re2 we have no way of obtaining the b1tton ret1rn. G if/ #evOlement 0 F evOlement = this. G / ,this, will exist if 5 have 1sed object"onOventAame = alertS1t.

5f 5 have passed evOlement from the onmo1se1p attrib1te2 ,this, will refer to window /

window"alert/ evOlement % , was clic!ed with b1tton , % e 0. G

</script>

<a onmo1se1p="alertS1t/arg1ments&:*2this0." href="whatever">

Test this here$ clic! this lin! and the script will try to wor! out what button you used. "ote that browsers may prevent you from using JavaScript dialogs 0li!e alert1 in right clic! or middle clic! event handlers to prevent you from pointlessly brea!ing the browser's @I interaction.

There is also an oncontextmen1 event supported by many current browsers 0not available in all browsers2 most obviously not supported in 6pera D- but supported since 6pera <G1 that fires instead of the onclic! event when the user right clic!s or when they press the conte#t menu !ey or otherwise trigger the conte#t menu. This can be cancelled in order to replace the conte#t menu with a custom conte#t menu. "ote however that the user may be able to prevent it being detected and disabling it can ma!e your page inaccessible for users who use the conte#t menu for navigation. It is also entirely possible that a browser may not support it 0since it is not part of e#isting standards1 and browsers may not always trigger it for all ways of activating the conte#t menu. @se it sparingly and only for places where you want to provide a custom conte#t menu that provides additional functionality relating to the item that was clic!ed. It should never be relied on as the only way to provide functionality.
<script type="text/javascript">

f1nction show'ontextHen1/ e 0 F if/ #e 0 F //5nternet Oxplorer e = window"event. //no need to chec! for its existence. //no browser that s1pports oncontextmen1 will fail to provide event information G //""" p1t code to get the mo1se coordinates here /shown above02 //and show the (-THR layer that will be 1sed as the men1 /shown in the (-THR chapter0 """ G

</script>

<a oncontextmen1="show'ontextHen1/arg1ments&:*0.ret1rn false." href="whatever">

Test this here$ right clic! this lin! and the script will try to replace the conte#t menu with an alert.
reating objects

"etscape A I3 A on )indows and .ac and I3 H on .ac do not support the instanceof operator.

Any function in JavaScript can be used to create custom ob4ect classes simply by calling it using the !eywordnew. )hen called in this way the special variable this inside the function references the new ob4ect that is being constructed 0it normally refers to the 'current' ob4ect function can be used as demonstrated to create an ob4ect of class myobject$
f1nction myobject/0 F this"contained+al1e = :. this"othercontained+al1e = :. this"anothercontained+al1e = :. G

which is

usually window e#cept inside methods1. The function should not return a value. The following

var mything = new myobject/0.

And there you go mything is now an instance of class myobject. It will have the following properties all of which will be G$
mything"contained+al1e mything"othercontained+al1e mything"anothercontained+al1e

*ou could also now write this$


myobject"prototype"new'ontained+al1e = some+al1e.

This will cause all instances of class myobject will have the property new'ontained+al1e with valuesome+al1e. @se the instanceof operator to find out if your ob4ect is an instance of a given ob4ect class$

if/ myvar instanceof )rray 0 F """ G if/ myvar instanceof myobject 0 F """ G

)reating an ob"ect with metho s "ow I will give you an e#ample showing you how to create methods for your ob4ects. As an e#ample I will create a circle as my ob4ect. The methods will be
name8f'ircle"ret)rea/0

;eturns the area of the circle 0pi r=1


name8f'ircle"ret'irc/0

;eturns the circumference of the circle 0= pi r1


name8f'ircle"mvSy/x(is2y(is0

.oves the circle by #,is in the # direction and y,is in the y direction The following lines point the methods to functions that the ob4ect will use as the methods$

this"ret)rea = getThe)rea. this"mvSy = mv'clSy. this"ret'irc = f1nction /0 F """ G.

The third of these defines the method using an anonymous function in one line and does not wor! in some early "etscape A releases. "ote it has a semicolon after the 'O' and is one of the few places where this is correct practice.
f1nction mycircle/x2y2r0 F this"xcoord = x. this"ycoord = y. this"radi1s = r. this"ret)rea = getThe)rea. //This next line 1ses an alternative syntax

this"ret'irc = f1nction /0 F ret1rn / Hath"C5 this"mvSy = mv'clSy. G f1nction getThe)rea/0 F ret1rn / Hath"C5 G f1nction mv'clSy/x(is2y(is0 F this"xcoord %= x(is. this"ycoord %= y(is. G this"radi1s this"radi1s 0.

this"radi1s

4 0. G.

/ create a mycircle called testcircle where testcircle"xcoord is ; and testcircle"ycoord is ? and testcircle"radi1s is @ / var testcircle = new mycircle/;2?2@0. / 1se the mvSy method to displace the centre of testcircle" move it by 4 in the x direction and ; in the y direction / testcircle"mvSy/42;0. //testcircle"xcoord is now @ and testcircle"ycoord is now =

window"alert/ ,The area of the circle is , % testcircle"ret)rea/0 0. window"alert/ ,The circ1mference is , % testcircle"ret'irc/0 0.

The special 1toString1 metho All ob4ects have the ,toString, method even if you do not define it yourself. The method returns a string representation of the ob4ect and is automatically called whenever a string representation of an ob4ect is re%uired such as when you use alert/my8bject0. In most browsers this returns ,&object 8bject*, although some more useful browsers return a string li!e this$
,Fproperty96val1e92property46val1e42method96f1nction /0 F """ G2etc"G,

-owever for your own ob4ects you may wish to provide a special string that may provide more useful information. To do this simply define the ,toString, method$
this"toString = f1nction /0 F ret1rn ,'ircle object. xcoord6 , % this"xcoord % ,2 ycoord6 , % this"ycoord % ,2 radi1s6 , % this"radi1s. G.

$ vance ob"ect techni3ues These deal with concepts that are rarely used in JavaScripting. JavaScript is a more powerful programming language than most people ma!e use of but that is because in normal scripting these powerful features are not really necessary. If you are 4ust learning or if you are interested only in day-to-day scripting I suggest you move on to the ne#t chapter. Some of these techni%ues may not wor! in older browsers li!e early "etscape A releases.

ing extra properties%metho s using protot!pe

Internet 3#plorer H.=Safari <.:Uon%ueror :.:"etscape A and )ebT( do not implement the has8wnCroperty method.

Ta!e the mycircle e#ample from the top of this section 0creating new ob4ects1. )e have already created an instance of the mycircle class called ,testcircle,. And we can also assume that we have created a few other mycircles. "ow let us assume that we want to add another property to each circle. For e#ample we want each circle to have a ,text1re, property. )e could use this$

testcircle"text1re = ,smooth,.

And we could do this for each individual mycircle. 'ut since we want to do this for all of them it would be much more easy to give all instances the property at the same time. So we can use the ,prototype,property of the class constructor$
mycircle"prototype"text1re = ,smooth,.

Immediately all of the mycircles that we have created will now inherit the new property$
alert/testcircle"text1re0. //alerts ,smooth,

)e can add new methods the same way$


mycircle"prototype"set)rea = f1nction /o)rea0 F this"radi1s = Hath"sVrt/ o)rea / Hath"C5 0. G. mycircle"set)rea/@0.

This is most useful with instrinsic 0fundamental inbuilt1 ob4ects. For e#ample the regular e#pression construct/a&:$U*b/g is shorthand for new NegOxp/,a&:$U*b,2,g,0. and in fact the same is true for all intrinsic ob4ect classes such as String A1mber and Soolean. So if for e#ample we wanted to create a new method on all strings called ,reverse, that returned their contents in reverse order we could do this$
String"prototype"reverse = f1nction/0 F for/ var oStr = ,,2 x = this"length $ 92 oTmp. oTmp = this"char)t/x0. x$$ 0 F oStr %= oTmp. G ret1rn oStr.

G.

The use of prototype could have been applied to create all of the methods of the mycircle ob4ect not 4ust new ones. This gives a mi#ed response to performance. It will not have to store individual copies of the methods for each instance of the ob4ect so it may re%uire less memory but it will re%uire the browser to search the current and parent scopes to find the methods. This may cause a marginal delay. 8enerally you should use what is appropriate for your code and not base this decision on performance 0unless you are dealing with a very specific controlled environment1$
f1nction mycircle/x2y2r0 F this"xcoord = x. this"ycoord = y. this"radi1s = r. G mycircle"prototype"ret)rea = f1nction /0 F ret1rn / Hath"C5 G. mycircle"prototype"ret'irc = f1nction /0 F ret1rn / Hath"C5 G. mycircle"prototype"mvSy = f1nction /x(is2y(is0 F this"xcoord %= x(is. this"ycoord %= y(is. G. this"radi1s 4 0. this"radi1s this"radi1s 0.

In some cases it may be desirable to wor! out if a property on an ob4ect is attached to the ob4ect instance itself or somewhere in its prototype chain. In JavaScript all ob4ects have a method called has8wnCropertythat returns true if the given property is attached to the individual ob4ect instance. 6f course it is also possible to chec! if the ob4ect's constructor also has the same property with the same value as the ob4ect instance itself but that can give the wrong result if separate

properties e#ists with the same value on both the ob4ect instance and the prototype chain. The has8wnCroperty method accepts a single parameter2 the name of the property as a string.
f1nction myclass/0 F this"propertytwo = 4. this"propertythree = ;. G myclass"prototype"propertyone = 9. myclass"prototype"propertytwo = 4.

var myinstance = new myclass/0. myinstance"propertyfo1r = ?.

alert/myinstance"has8wnCroperty/,propertyone,00. //alerts false

alert/myinstance"has8wnCroperty/,propertytwo,00. //alerts tr1e

alert/myinstance"has8wnCroperty/,propertythree,00. //alerts tr1e

alert/myinstance"has8wnCroperty/,propertyfo1r,00. //alerts tr1e

alert/myinstance"has8wnCroperty/,propertyfive,00.

//alerts false

0ublic an private properties This is a concept that is almost never used in JavaScript and there is a good reason. It simply is not necessary. 3ven complicated scripts are almost never comple# enough to re%uire this level of control. -owever many programmers familiar with other programming languages 0such as Java or +JJ1 often desire this behavior in JavaScript simply because it is a concept they are familiar with. This sort of concept is only really useful when putting together large pro4ects from multiple pieces of code. Say for e#ample that I am producing a public functions library. A set of constructors and methods that people can include in their own pro4ects 0something that Java programmers use all of the time1. Say for e#ample that the mycircle constructor is included in it so that you can create your own mycircles. "ow say for e#ample you try this$
var a'ircle = new mycircle/@2<2,abo1t ;mm,0.

That will wor! now 0it's not a valid measurement but my constructor will not argue1 but later on when you try to use the methods that my class provides it will fail. So I can chec! what you have provided and ma!e sure it is a valid number and use a default value if it is not. 'ut then you can say something li!e this$
a'ircle"radi1s = ,some text,.

Again it would brea! 0of course it is your own fault but in more complicated applications it would be possible to ma!e a mista!e where this causes a real problem1. So what I want to do is to not allow you to modify that property directly and only allow you to change it using a method that I control$
this"setNadi1s = f1nction /oNad0 F if/ typeof/oNad0 == ,n1mber, PP oNad >= : 0 F this"radi1s = oNad. G else F

this"radi1s = :. G G.

An alternative situation where this can be important is if I am storing the information in one set of properties. I then upgrade my libraries maybe adding some e#tra functionality. 'ut in order to do so I have to change the properties that I am using. If your script was relying on them e#isting in a specific format and I have now changed that format your script would fail. If I could protect those properties and force you to use only methods then I could do whatever I needed with the properties and as long as I then change the methods to use the new properties your script would !eep wor!ing and you would not even need to !now what I had changed or why. That way we could each manage our own pro4ect and not waste each other's time. It would also help avoid possible conflicts between undisclosed properties and your own scripting. For e#ample if you decide to temporarily assign a property to an ob4ect but you were unaware that internally my ob4ect constructor already used that property name you would overwrite my ob4ect's property and cause problems with the ob4ect. This is what private properties are for. They do not allow scripts that use the contructor to use or modify the properties directly. They only allow the methods of the ob4ect itself to use and modify them. @nli!e many other languages JavaScript does not declare each variable type as 'public' or 'private'. It all depends on how you create them. Saying 'this"propertyname' as I did above will create a public property. Any script can create an ob4ect then use and modify its properties directly. @sing ,var, to define a variable in the constructor will create a private property. "ote that unli!e public properties the private properties are then accessed including from within methods without the 'this.' prefi# - 4ust li!e a normal variable. This ma!es heavy use of JavaScript's scope functionality. 5rivate variables can only be accessed from methods that are declared inline and not e#ternally referenced or created using the prototype construct. .ethods of this !ind are also !nown as privileged methods. An e#ample of its use might be$ this"mymethod = f1nction /0 F alert/ propertyname 0. G.
f1nction myob/0 F this"property9 = ,val1e9,. //this creates a p1blic property var property4 = ,val1e4,. //this creates a private property

this"method9 = f1nction /0 F alert/ property4 0. G.

G var one8b = new myob/0. alert/one8b"property90. //alerts ,val1e9, alert/one8b"property40. //alerts 1ndefined /private property0 one8b"method9/0. //alerts ,val1e4,

Similarly you can also create private methods. These are simply a function that you create inside the constructor function. This may loo! confusing but it wor!s. The private function can only be called by the constructor itself or by methods that are defined inline. 5rivate methods can be used as public methods if they are assigned to a public method constructor and accessed using the public method constructor 0as with 'method=' below1.
f1nction myob/0 F f1nction cantSeSeen/0 F alert/secret+al1e0. G var secret+al1e = ,,. this"method9 = f1nction /0 F secret+al1e = ,no s1rprises,. cantSeSeen/0. G. this"method4 = cantSeSeen. G var one8b = new myob/0. one8b"method9/0. //alerts ,no s1rprises, one8b"method4/0. //alerts ,no s1rprises,

For more information on private public and privileged properties and methods in JavaScript see ,ouglas +roc!ford's '5rivate .embers in JavaScript' page.

Sub2classes an class inheritance This is also hardly ever used in JavaScript despite its popularity in other languages. Ta!e this as an e#ample. I want to ma!e a new type of ob4ect that will store the data to represent a sphere 0a ball in case you don't !now1. Since a sphere is 4ust a three dimensional circle I would probably want to include all the methods I created earlier for the circle ob4ect2 ret)rea to get the cross-section area ret'irc to get the circumference mvSy to move it by a certain amount. Aditionally I would probably want ret+ol to get the volume and retS1rf to get the surface area. I would also need to provide a 7 coordinate when creating the ob4ect and again when calling the mvSy property. So I want to create a new type of ob4ect based on the mycircle but with a few aditions and modifications. I will call this new type of ob4ect a mysphere. "ow I could 4ust rewrite all the code I already wrote for themycircle and change the bits I need. 'ut in a real-world application this might be a lot of wasteful duplication for only one or two modifications. So what I want to do is ma!e the mysphere inherit all the properties and methods of the mycircle then overwrite only the ones I want. This effectively ma!es mysphere a sub-class of mycircle and ma!ing the mysphere class

constructor inherit from the mycircle class constructor is as simple as this$


f1nction mysphere/x2y2Y2r0 F """ constr1ctor code """ G mysphere"prototype = new mycircle/0.

In case you are wondering the way it wor!s is to actually create a mycircle then assign that to themysphere constructor prototype. As a result the mysphere constructor has the mycircle ob4ect added to its prototype chain. )hat this means is that each time a mysphere is created it will inherit the properties and methods of the mycircle ob4ect. It can then override any of these properties using its own prototype or with properties and methods created within its own constructor. If any of these properties are subse%uently removed 0using the ,delete, !eyword1 the inherited ones will become available again. That also means that if the mycircle prototype is changed 0properties are added or deleted etc.1 these changes are replicated down the chain so the mysphere also inherits these changes. "ote that the prototype chain is established for each ob4ect as the ob4ect is created. 6nce an ob4ect has been created its prototype chain cannot be changed 0though new properties and methods can

still be added to its parent classes and those changes will be reflected in the ob4ect1. +hanges to its prototype chain will have no effect2 it will still see the old prototype chain. The new chain will only be used for new instances of that class. This is also the case for the assignment of a new mycircle to the prototype of mysphere 0which as stated creates a new instance of the mycircle class12 any subse%uent changes to the prototype chain of the mycircle class will not be reflected in the mysphere class. For this reason it is very important to ensure that the prototype chain is built in the correct order with class constructors and their prototypes set up before any child class is made to inherit from them. 5roperties and methods can still be added to any class or parent class at any time after their own prototype chain has been set up. The line that ma!es mysphere inherit from mycircle sounds simple enough. And at least it would be but you will remember that mycircle e#pected me to pass it some parameters that it would then use. Then I call my new constructor and these parameters will not automatically be passed to the mycircle constructor function. I need to do this myself for each mysphere that I want to create. 'ut since I am not passing these parameters when assigning the mycircle ob4ect to the mysphere prototype I also need to ensure that themycircle contructor stops before attempting to create its own properties. Instead of defining the public properties immediately I will define them using a method 0that I have decided to call getready1 and if the re%uired parameters have been passed 0arg1ments"length1 I will immediately call the method. If the parameters are present the mycircle constructor !eeps wor!ing and no-one needs to !now that anything was changed at all. To ma!e things easier later on I will ta!e all of the methods out of the constructor and add them later using the prototype. That way the mycircle prototype methods will always be available without me needing to create a new mycircle. @nfortunately this also means that public and private properties are very hard 0or impossible1 to use. It's a trade off - one functionality for another.
f1nction mycircle/x2y2r0 F if/ arg1ments"length 0 F this"getready/x2y2r0. G G mycircle"prototype"getready = f1nction /a2b2c0 F this"xcoord = a. this"ycoord = b. this"radi1s = c.

G. mycircle"prototype"ret)rea = f1nction /0 F ret1rn / Hath"C5 G. mycircle"prototype"ret'irc = f1nction /0 F ret1rn / Hath"C5 G. mycircle"prototype"mvSy = f1nction /x(is2y(is0 F this"xcoord %= x(is. this"ycoord %= y(is. G. this"radi1s 4 0. this"radi1s this"radi1s 0.

"ow bac! to the mysphere constructor. I have already said how to ma!e it inherit but it still needs to run themycircle"getready method to initialise the properties. To do this we will need to reference the parent class prototype and run the method ourselves. This also ensures that even if each parent class uses the same method name 0getready1 the correct one is always referenced. Since we can almost never be sure how many sub-classes we will need it is useful to do it this way and simply use the same method name for each !nowing that we will not have problems with name conflicts. )hen running the method we need to tell JavaScript that even though we are referencing a method for a different prototype we want to run it as if it were a method of the ob4ect we are creating 0to ma!e sure that any properties it creates are added to the ob4ect we are creating1. This could be done using the ,call,method or ,apply, method but unfortunately Internet 3#plorer H does not understand these so I will assign it to a temporary property of the new ob4ect and run it from there. To reference the method from the parent class prototype it would be possible to use the constructor's prototype chain to locate it 0the property that references the constructor will at this point refer to the parent class - more on that later1$
this"constr1ctor"getready

-owever that will only wor! for one level of inheritance due to the way it is run as a method of the current ob4ect for all child classes. As a result it is best to reference it by name which will wor! no matter how many levels of class inheritance are used$
mycircle"prototype"getready

"ote that when assigning the mycircle ob4ect to the mysphere prototype it also overwrites the mysphereprototype constr1ctor property. This is not a ma4or problem but some scripts use it so we will put the reference bac! where we want it$
f1nction mysphere/x2y2Y2r0 F if/ arg1ments"length 0 F this"getready/x2y2Y2r0. G G //inherit from the mycircle prototype mysphere"prototype = new mycircle/0. //p1t the correct constr1ctor reference bac! /not essential0 mysphere"prototype"constr1ctor = mysphere.

mysphere"prototype"getready = f1nction /a2b2c2d0 F //reference the getready method from the parent class this"tempNeady = mycircle"prototype"getready. //and r1n it as if it were part of this object this"tempNeady/a2b2d0. //now that all reV1ired properties have been inherited //from the parent class2 define extra ones from this class this"Ycoord = c. G mysphere"prototype"mvSy = f1nction /x(is2y(is2Y(is0 F

//override the existing method this"xcoord %= x(is. this"ycoord %= y(is. this"Ycoord %= Y(is. G. mysphere"prototype"ret+ol = f1nction /0 F ret1rn / ? / ; 0 G. mysphere"prototype"retS1rf = f1nction /0 F ret1rn ? G. Hath"C5 this"radi1s this"radi1s. Hath"C5 Hath"pow/ this"radi1s2 ; 0.

And finally to use it$


var testsphere = new mysphere/;2?2@2<0.

alert/ ,The cross$section area is , % testsphere"ret)rea/0 0. alert/ ,The circ1mference is , % testsphere"ret'irc/0 0. alert/ ,The vol1me is , % testsphere"ret+ol/0 0. alert/ ,The s1rface area is , % testsphere"retS1rf/0 0.

Test this class inheritance script. There is no limit to how many sub-classes can inherit from a class and there is also no limit to how many levels of sub-classes can be created. As an e#ample I will create a ball class that will inherit from themysphere class$
f1nction ball/x2y2Y2r2m0 F if/ arg1ments"length 0 F this"getready/x2y2Y2r2m0. G

G ball"prototype = new mysphere/0. ball"prototype"constr1ctor = ball.

ball"prototype"getready = f1nction /a2b2c2d2e0 F this"tempNeady = mysphere"prototype"getready. this"tempNeady/a2b2c2d0. this"mass = e. G ball"prototype"ret(ensity = f1nction /0 F ret1rn this"mass / this"ret+ol/0. G.

Test this class inheritance script. The instanceof operator returns true when testing an ob4ect against any class in its prototype chain so it would say that an instance of the ball class was also an instance of the mysphere class and also themycircle class. For more information on sub-classes and class inheritance in JavaScript see Uevin /indsey's class inheritance page.

Static metho s an properties A static property 0or method1 is a property of the class constructor not an individual instance of that class. For e#ample mycircle"myproperty instead of /new mycircle/00"myproperty. )hile not often used in JavaScript they are often encountered in other programming languages and are covered here for those who are familiar with them in other languages. As with most ob4ects in JavaScript the functions used as class constructors can have properties added to them and these will be public static properties$
f1nction mycircle/0 F """ G

mycircle"aStaticCroperty = tr1e. mycircle"aStaticHethod = f1nction /0 F """ G.

.a!ing a private static property is significantly harder as it is a concept that JavaScript 0at least in widely supported implementations1 simply does not recognise. -owever it is possible to provide an appro#imate e%uivalent to this functionality by using an anonymous wrapper function to create a scope where the private >properties> are created as normal variables then having that return another function that will be used as the constructor. As long as the constructor function is declared inside the anonymous function it will have access to the private variables from the anonymous function's local scope when it is e#ecuted. This structure is described in the section on writing functions.
var mycircle = /f1nction /0 F var privateStatic+ariable = tr1e. f1nction privateStaticHethod/0 F """ G f1nction p1blic'onstr1ctor/0 F this"normal5nstanceCroperty = 9. """ alert/privateStatic+ariable0. G. p1blic'onstr1ctor"prototype"normalCroperty = 4. ret1rn p1blic'onstr1ctor. G0/0. mycircle"p1blicStaticCroperty = tr1e. mycircle"p1blicStaticHethod = f1nction /0 F """ G.

Singletons The singleton is one of the design patterns that is commonly seen in other languages and in a simplified format within JavaScript. The idea of a singleton is to have a class that can only have one

ob4ect created from it. 3very time a script tries to create another instance of that class it returns the same copy as before so if the properties are modified on one of them then the other will also see the modifications. The use of singletons can be controversial but I will not cover that here. This tutorial will only show you how to produce them. In JavaScript there is the ability to create a generic anonymous ob4ect to serve this purpose. It can either be created using new 8bject/0 or the shorthand F """ G synta# and can then be given any properties or methods that are needed. -owever this does have limitations2 using a generic ob4ect means that it is not possible to use private properties. In most cases this is functionality that is not needed and the ma4ority of scripts simply use a generic ob4ect. Instead of trying to constuct new instances of the ob4ect scripts will 4ust create another variable that references the ob4ect$
var mySingleton = F foo6 ,bar,2 baY6 ,V1x,2 aHethod6 f1nction /0 F """ G G. """ var anotherNeference = mySingleton.

If you feel the need for private properties read on. )ith other languages the e#pectation is to create a class constructor that refuses to be instantiated by other scripts and provides a public static method that constructs the ob4ect the first time it is called and returns the same ob4ect for each subse%uent call. JavaScript however does not provide a way to prevent a class from being instantiated 0at least in widely supported JavaScript1. If it e#ists as a function it can be called as a constructor. It is tempting 0and sometimes used1 to simply use an anonymous function as the class constructor construct it once and use its scope to !eep variables private. This is limited to normal private properties and cannot be used for private static properties. The theory is that this enforces the singleton principle by preventing another attempt to reference and use the class constructor. This pattern fails to produce a singleton to however it as other code you can simply use the the singleton's constr1ctor property reference although could override

singleton's constr1ctor property this can cause other problems later on if code needs to be able to use that to add properties to the constr1ctor"prototype.
var mySingleton = new f1nction /0 F var privateStatic+ariable = tr1e. f1nction privateStaticHethod/0 F """ G

""" G. var new5nstance = new mySingleton"constr1ctor/0.

It is however possible to adapt the pattern used for private static properties to create private properties for the singleton while at the same time creating a proper singleton. 6nce again an anonymous function is used to contain the private variables and functions. -owever instead of returning a class contructor function it 4ust returns the single ob4ect$
var mySingleton = /f1nction /0 F var privateStatic+ariable = tr1e. f1nction privateStaticHethod/0 F """ G ret1rn F """ G. G0/0.

That is of course a very simple pattern but it shows something important2 by returning a generic ob4ect it is not possible to use new mySingleton"constr1ctor/0 to create a separate instance as that would 4ust produce a generic ob4ect. This particular format is %uite aw!ward however as the generic ob4ect prevents the prototype from being used to cleanly add more properties and methods. It is very simple to e#tend it to ma!e that possible however 4ust by creating the class contructor function inside the anonymous function$
var mySingleton = /f1nction /0 F var privateStatic+ariable = tr1e. f1nction privateStaticHethod/0 F """ G f1nction Crivate'onstr1ctor/0 FG Crivate'onstr1ctor"prototype"p1blicCroperty = tr1e. """ ret1rn new Crivate'onstr1ctor/0. G0/0.

This

now

means

that new

mySingleton"constr1ctor/0 will

create

new

instance

of

a Crivate'onstr1ctorob4ect. -owever the constructor function when called in this way is pulled out of the inner scope during that call and as a result it ends up with a relatively useless ob4ect that has none of the prototype's properties. 6nce again the singleton principle is enforced. "ew properties can be created by modifying the mySingleton"constr1ctor"prototype. The singleton can itself be used as the prototype for another constructor to allow sub-classes to be created. There are some reasons why this particular approach may not be favoured2 specifically that it always creates the singleton even if it is never used. Some may also prefer to use a function call instead of having a global variable always created 0though a function is still a global variable1 as this may ma!e it possible to change the implementation later to use a different design pattern instead of a singleton. It is possible to ta!e care of both of these concerns by returning a function instead of an ob4ect. That function can chec! if the singleton has been created yet store it in a private variable and return the instance. This has the small limitation that an instance of the ob4ect will need to be created by an e#ternal script in order to add properties or methods to the prototype but this is a limitation that is unli!ely to be a problem$
var getSingleton = /f1nction /0 F var privateStatic+ariable = tr1e. f1nction privateStaticHethod/0 F """ G f1nction Crivate'onstr1ctor/0 FG Crivate'onstr1ctor"prototype"p1blicCroperty = tr1e. """ var only5nstance. ret1rn f1nction /0 F if/ #only5nstance 0 F only5nstance = new Crivate'onstr1ctor/0. G ret1rn only5nstance. G. G0/0.

""" var mySingleton = getSingleton/0.

6r an e%uivalent approach that assigns the function to a global variable instead of returning it 0this may be preferred for clarity or to allow you to put the class instantiation methods at the top of the anonymous function instead of the bottom of it1$
var getSingleton. /f1nction /0 F var only5nstance. getSingleton = f1nction /0 F if/ #only5nstance 0 F only5nstance = new Crivate'onstr1ctor/0. G ret1rn only5nstance. G. f1nction Crivate'onstr1ctor/0 FG Crivate'onstr1ctor"prototype"p1blicCroperty = tr1e. """ G0/0.

It is however possible to ma!e the anonymous function return an ob4ect which can be used for prototyping directly but this becomes %uite messy. The Crivate'onstr1ctor can be made to inherit its prototype from the ob4ect that will be returned by the anonymous function. The singleton 0when it is created1 will then inherit any changes made to that ob4ect 0in addition it will inherit the get5nstance method from the returned ob4ect but this is harmless1. I recommend that you avoid getting into a situation where you would need this functionality in a script.
var singletonHa!er = /f1nction /0 F

var privateStatic+ariable = tr1e. f1nction privateStaticHethod/0 F """ G var only5nstance. var ret1rned8bject = F get5nstance6 f1nction /0 F if/ #only5nstance 0 F only5nstance = new Crivate'onstr1ctor/0. G ret1rn only5nstance. G G. f1nction Crivate'onstr1ctor/0 FG Crivate'onstr1ctor"prototype = ret1rned8bject. Crivate'onstr1ctor"prototype"p1blicCroperty = tr1e. """ ret1rn ret1rned8bject. G0/0. """ singletonHa!er"foo = tr1e. var mySingleton = singletonHa!er"get5nstance/0. alert/mySingleton"foo0. //tr1e

For more information on this topic see Uai J[ger's article about singletons in JavaScript.

$HE SI29/E$O2 .ESI92 (A$$E'2 I2 JAVAS 'I($


This singleton pattern despite the controversy surrounding it is definitely one of the most popular 8oF patterns. )hile I agree that using singletons to ma!e global variables loo! li!e 665 is bad the pattern actually has %uite a few >real> uses. A few months ago while I was wor!ing on my A4a# framewor! I was

loo!ing for a way to ensure that the ob4ect I'm using for asynchronous communication could only be instantiated once and that an instance is only created when it's actually needed. A %uic! google for >JavaScript singleton> returned %uite a few pages. -ere's the solution that most of them had come up with$
+lic! anywhere in the code to remove line numbers.

9 4 ; ? @ <

8a# singleton = ne& "(nction/0 F 8a# rand = Hath"ro1nd/Hath"random/0 this"getNand = "(nction/0 F #et(#n rand. G G 9::0.

In order to obtain a reference to the singleton instance you'd 4ust use the global variable singleton. +lose but no cigar. First of loo! at this code$
+lic! anywhere in the code to remove line numbers.

9 4 ;

8a# secondSingleton = ne& singleton"constr1ctor. doc1ment"write/singleton"getNand/0 % 67r7n60. doc1ment"write/secondSingleton"getNand/00.

@sing the constructor attribute of the singleton ob4ect which holds a reference to the anonymous constructor function I can easily create a second instance of the >singleton>. The code snippet above will therefore give you two different outputs one for the original instance and one for the second instance. Two instances Z no singleton. 6f course circumventing the one-instance limitation re%uired some >hac!ing> and therefore doesn't necessarily invalidate this solution. The real problem is that a singleton has a property that this solution doesn't ta!e into account$ an instance of a singleton is only created when a special method 0typically called getInstance1 is invo!ed. The above solution will create an instance of the singleton regardless whether its actually needed or not. If the singleton allocates a lot of resources e#ecutes a bunch of comple# code or even does communication via A4a# in its constructor then this behavior could be a problem. In order to come up with a solution I loo!ed at how singletons are typically implemented in other languages li!e Java$
+lic! anywhere in the code to remove line numbers.

9 4 ; ?

class Singleton F !#i8ate static Singleton instance = n(ll. !#i8ate Singleton/0 F G !(blic static Singleton get5nstance/0 F

@ < = J U 9: G G

i" /instance == n(ll0 F instance = ne& Singleton/0. G #et(#n instance.

For singletons to wor! in JavaScript I needed a way to do private constructors and both private and public static members two concepts that JavaScript doesn't natively support. As ever so often the solution was to use a closure to ma!e the instance attribute and the constructor private. -ere's the solution I came up with$
+lic! anywhere in the code to remove line numbers.

9 4 ; ? @ < = J U 9: 99 94 9; 9? 9@ 9< 9= 9J 9U 4: 49 44

8a# Singleton = /"(nction/0 F 8a# instance = n(ll. "(nction Crivate'onstr1ctor/0 F 8a# rand = Hath"ro1nd/Hath"random/0 this"getNand = "(nction/0 F #et(#n rand. G G #et(#n ne& "(nction/0 F this"get5nstance = "(nction/0 F i" /instance == n(ll0 F instance = ne& Crivate'onstr1ctor/0. instance"constr1ctor = n(ll. G #et(#n instance. G G G0/0. 8a# singleton5nstance = Singleton"get5nstance/0. 9::0.

The tric! here is to define an anonymous function and call it immediately. The function creates a new variable scope in which we define a local variable >instance>. The function then returns a new ob4ect that provides a privileged method >getInstance>. Since this method holds a reference to the instance variable

a closure is formed and the local variable becomes a private static member. The actual constructor function is defined within the anonymous function and hence becomes inaccessible from the outside. Since getInstance also holds a reference to that function another closure is formed allowing getInstance to create new instances using 5rivate+onstructor. In a remotely aspect oriented !ind of way you could even do this$
+lic! anywhere in the code to remove line numbers.

9 4 ; ? @ < = J U 9: 99 94 9; 9? 9@ 9< 9= 9J 9U 4: 49 44 4; 4? 4@ 4< 4= 4J

8a# global = this. "(nction singletonify/constr1ctorAame0 F 8a# constr1ctor71nc = global&constr1ctorAame*. 8a# instance = n(ll. global&constr1ctorAame* = ne& "(nction/0 F this"get5nstance = "(nction/0 F i" /instance == n(ll0 F instance = ne& constr1ctor71nc/0. instance"constr1ctor = n(ll. G #et(#n instance. G G G "(nction Neg1lar'onstr1ctor/0 F 8a# rand = Hath"ro1nd/Hath"random/0 this"getNand = "(nction/0 F #et(#n rand. G G singletonify/6$egular8onstructor60. 8a# my5nstance = Neg1lar'onstr1ctor"get5nstance/0. doc1ment"write/my5nstance"getNand/00. 9::0.

This will turn an e#isting constructor function into a singleton. The name of the constructor needs to be passed as a string to the singletonify function because otherwise it wouldn't be able to overwrite the

orignal constructor. I hope someone find this useful. 5lease let me !now what you thin!.
reating time delays

There are two ways of creating time delays with JavaScript. The first is more simple and will simply wait for a specified amount of time before e#ecuting a function. The second does the same but will repeatedly e#ecute the function. "ote most browsers have a minimum delay length of between =H and IH ms. If a shorter delay is specified the actual delay will be the minimum delay length. 3ven with higher numbers the delay is never perfect. .ost browsers will ta!e slightly longer than the time you as! for typically 4ust a few miliseconds error. Some may correct their errors over time with interval timers. Also note setting many timers with short delays on one page will cause the browser to become slow and somewhat unresponsive. Three or four timers is usually the reliable limit.

setTimeout The first method uses a window method called setTimeo1t/0. The method waits for a specified number of milliseconds then e#ecutes the specified code. The code can either be a direct reference to a function or it can be a string that will be evaluated as if it contained source code.
window"setTimeo1t/referenceTo71nction2time5nHilliseconds0. window"setTimeo1t/,r1nHore'ode/0,2time5nHilliseconds0.

)herever possible you should use a direct function reference as it is much more efficient. @sing a string re%uires the browser to create a new script environment so it can process the script. If you create a timeout the code after the call to setTimeo1t will continue to run as normal. After the specified delay the timeout will start a new thread and the code specified in the call to setTimeout will be run in the new thread along side any code that is still running in the initial thread. @nli!e with many more comple# languages JavaScript does not offer any way to control when those threads sleep wa!e or yield. The JavaScript engine handles all of that and you must accept that your new thread could be e#ecuting at any time ne#t to another thread. .any JavaScript engines will simply allow one thread to complete before allowing the other thread to start. The same applies to events which run in their own threads and can be triggered at any time.

To pass variables to a timeout you can use either format. To use a string it is necessary to ma!e sure the variables you want to pass can be represented in one of the primitive data types and do not contain any characters that will brea! the string format 0such as %uotes1. If possible you should avoid this format but this is an e#ample 4ust in case you need to$
window"setTimeo1t/,r1nHore'ode/L,,%someString%,L,2,%someA1mber%,0,29:0.

The direct function reference is much more easy as you can pass variables as e#tra parameters to the setTimeout method. In addition to being more easy it is also able to accept any type of variable. 'e careful with browsers that use the .o7illa 8ec!o engine 0such as Firefo# and "etscape MJ1 as they will always pass an e#tra parameter to the function - the number of miliseconds error. This e#ample uses an inline anonymous function and is e%uivalent to using a direct function reference$
window"setTimeo1t/f1nction /a2b0 F //do something with a and b G29:2someString2some8bject0.

The variables that are passed to the function will be the values held by the variables at the time that the method was called. For e#ample assume you had a variable called my+ar and it contained the number H. *ou then called a timeout passing it the variable my(ar and set it for a delay of < second. Immediately you change the value of my(ar to I. )hen the timeout fires it will run the function and pass it the number H since that was the value my(ar contained when you called the function.

set8nterval The set5nterval method is identical in synta# to setTimeo1t/0. The difference is that as well as firing after the specified delay it will fire again after the same delay and will continue to fire at the specified interval until it is cancelled.
window"set5nterval/f1nction /a2b0 F //do something with a and b G29:2someString2some8bject0.

)learing timeouts an intervals *ou can cancel a timeout or interval by calling the

relevant clearTimeo1t or clear5nterval method passing it a reference to the interval ob4ect. The code specified in the timer will not be run. In this e#ample an interval timer will be set to fire once every second 0it will perform a useless tas! of incrementing a number 4ust as an e#ample1 and a timeout will be set to cancel the interval after :.H seconds$
var my5nterval = window"set5nterval/f1nction /a2b0 F myA1mber%%. G29:::0. window"setTimeo1t/f1nction /a2b0 F clear5nterval/my5nterval0. G2;@::0.

*ou can obtain the timeout ob4ect in the same way as shown here for the interval and you can cancel it in the same way using clearTimeo1t.
%sing coo0ies

+oo!ies are variables that can be stored on a user's computer and be pic!ed up by any other web pages in the correct domain and path. +oo!ies are set to e#pire after a certain length of time. They are limited to storing string values only. 'e warned that many users 0including me1 will not permit coo!ies on their computers. ,o not ma!e your web sites rely on them. The reason for this is that many web sites only use coo!ies as part of advert tracing systems which they use to trac! your movement around the Internet. I would not want anyone to follow me around a city while I was shopping ta!ing notes of every shop I visit and whether I loo! in the lingerie section as that would be an invasion of my privacy. .any people feel the same applies to the Internet. *ou may find it helps to firstly display a message saying what you are going to use the coo!ie for for e#ample to store a username and password for the ne#t time they visit the site. Some browsers will have a limit to how many coo!ies they can store usually :GG coo!ies or more of which there may be =G coo!ies per domain name. A total of A U' 0after encoding1 of coo!ies can be stored for any domain or path.

The doc1ment"coo!ie ob4ect is a string representation of all coo!ies available to the current web page. Thedoc1ment"coo!ie ob4ect is somewhat unusual in that when you assign string values to it it does not become the value that you assign to it. Instead it ta!es a part of that value and appends its current value to that so ma!ing a string containing several pairs of variableAame=variable+al1e.

)reating % mo if!ing an

eleting cookies

I have also written a coo!ie script to handle all of this for you. +oo!ies are created or modified by assigning a name=val1e pair to the doc1ment"coo!ie ob4ect$
doc1ment"coo!ie = coo!ieString.

The coo!ieString is more than 4ust a single value. As well as a value it can contain other information such as when you want the coo!ie to e#pire and what file paths it should apply to. Any of these values that you want to specify should be put together in a string as !eyword=val1e.!eyword=val1e.etc" and assigned as a single string to doc1ment"coo!ie. 6nly the coo!ie name and value are re%uired all other values are optional. The format of a complete coo!ie string is$
coo!ieAame=coo!ie+al1e&.expires=data)sString&.path=path)sString&.domain=domain)sString &.sec1re****

This is an e#ample of how to set a coo!ie called mycoo!ie and assigning it a value of hello with an e#piry date of <I ,ecember =G<G at <G$GG in the morning$
doc1ment"coo!ie = ,mycoo!ie=hello.expires=7ri2 9= (ec 4:9: 9:6::6:: BHT,.

coo!ie"ame and coo!ie(alue These are strings and must be @;/ encoded. They and can contain any characters. To @;/ encode a coo!ie name or value you can use the escape method. @nfortunately this cannot cope with unicode characters. "ewer browsers will also provide the encodeIN5'omponent method that is able to cope with unicode but if you use this you will lose support for older browsers.

e#pires This must be written in full. The (ate"toBHTString/0 method can return dates in the correct format for you. For e#ample$
var the(ate = new (ate/0. var oneKearRater = new (ate/ the(ate"getTime/0 % ;9@;<:::::: 0. var expiry(ate = oneKearRater"toBHTString/0.

6nce the specified date is reached the coo!ie e#pires and is deleted. If e#pires is not specified the coo!ie will be deleted when the browser is closed. If e#pires is set to a date in the past the coo!ie is deleted immediately. This is how to delete a coo!ie 0some browsers may ta!e a few seconds to actually delete the coo!ie1. In theory computers should be able to accept any future date but in reality @"I9 computers will not currently accept a date after G:$<A on <L Jan =G:L and many .acintosh computers will not currently accept a date after GM$=L M Feb =GAG or the same date as that for @"I9. These are the @"I9 and .acintosh e%uivalent of the millennium bug. path This gives the path or directories that the coo!ie should be accessible from. The default is the current path. Alter this using '..&' 0up one directory1 '&' starting at the base directory and 'subdirectory"ame&' to start from the 'current,irectory&subdirectory"ame&'. "6T3 if two coo!ies are set with the same name but different paths both coo!ies will be permitted. If the script is in a directory where both those paths are satisfied both coo!ies are available and may be returned in any order. There is no way to distinguish between them. This can ma!e scripts difficult to write so be carefulY domain gives the domain that the coo!ie is accessible from. The default is the current domain. The rules reguarding what may be put here were originally written very strictly. ,omain names ending in com edu net org gov mil and int must contain at least = '.' characters 0eg. www"google"com1. Any other domain names must contain at least : '.' characters 0eg. www"howtocreate"co"1!1. The domain should only be the current domain or a subdomain of it. .any browsers will now accept any valid domain name. secure

-aving this written means the coo!ie is only accessible on sites with a secure 0https1 connection.

&ea ing cookies )hen doc1ment"coo!ie is used to retrieve coo!ies they are returned in the following format$
coo!ieAame?=val1e. coo!ieAame;=val1e. coo!ieAame4=val1e. coo!ieAame9=val1e

"ote that the final variable value does not end with a semicolon. If there is no value for a variable some browsers will give 'coo!ieAame=' but some will only give 'coo!ieAame'. +oo!ies are only available through the doc1ment"coo!ie ob4ect and cannot be accessed by simply typing their name 0unless you retrieve the coo!ie and define that as a variable yourself1. )hen trying to retrieve values from this string it is important to ensure that you do not mista!e coo!ies for each other. For e#ample when searching for 'myname' it is important that you do not find a coo!ie called 'notmyname' or 'mynamehere'. There are many scripts that get this wrong but the algorithm I will show you below does not ma!e these mista!es. The simple way to do this is to use the split method to split on the coo!ie separation value ,.
, 0including

the space1. This will return an array of strings

each of which represents

a name=val1e pair. *ou can then use a 'for' loop to cycle through all the array cells splitting each of them on the 'Z' string. This returns an array containing one or two cells. The first will be the coo!ie name and the second 0if it e#ists1 will be the coo!ie value. @se either the 1nescape or decodeIN5'omponent methods to decode the contents of the first cell containing the coo!ie name. If that matches the desired name then you have found the correct coo!ie. @seif/#arrayname&9*0 to chec! if the second cell has a value. If not the coo!ie's value is an empty string. If it does have a value then you can decode it to wor! out what it is. *ou can then brea! out of the 'for' loop. If you reach the end of the first array without discovering the re%uired coo!ie then the coo!ie does not e#ist.
Security

JavaScript is designed as an open scripting language. It is not intended to replace proper security measures and should never be used in place of proper encryption. See also my article about cross site scripting.

JavaScript has its own security model but this is not designed to protect the )eb site owner or the data passed between the browser and the server. The security model is designed to protect the user from malicious )eb sites and as a result it enforces strict limits on what the page author is allowed to do. They may have control over their own page inside the browser but that is where their abilities end.

JavaScripts cannot read or write files on users' computers. They cannot create files on the

server 0e#cept by communicating with a server side script that creates files for them1. The only thing they can store on the user's computer are coo!ies.

They are allowed to interact with other pages in a frameset if those frames originate from the

same )eb site but not if they originate from another )eb site 0the postHessage method from -T./ H does safely e#tend this capability but I will not cover that here1. Some browsers will even treat different port numbers on the same server as a different )eb site.

JavaScript cannot be used to set the value attribute of a file input and will not be allowed to JavaScript cannot read what locations a user has visited by reading them from the location

use them to upload files without permission. ob4ect although it can tell the browser to 4ump bac! or forward any number of steps through the browser history. It cannot see what other )eb pages the user has open.

JavaScript cannot access the coo!ies or variables from other sites. It cannot see when the user interacts with other programs or other parts of the browser It cannot open windows out of sight from the user or too small for the user to see and in

window. most browsers it cannot close windows that it did not open. .ost people who want to !now about security with JavaScript are interested in producing password protected pages or sending encrypted data to or from the user's computer. For true security use SS/&T/S 0-TT5S1 and put all of your chec!s on the server. *ou could also use a security loc!out if too many false attempts are made preventing brute force crac!s. JavaScript cannot replace this functionality. The problem lies in the fact that if a person can read what you are sending over the internet they can also rewrite it. So when you thin! you are filling in a password to access a protected page they have changed it so that you are actually filling in a password that will be sent to them. This re%uires SS/ to be sure that you are protected. Still this tutorial is about JavaScript so I will now show you what can and cannot be done with JavaScript.

0rotecting the source of !our scripts 6h dear. This is 4ust not possible. .any people ma!e futile attempts to do so but to be honest there is no point in trying. In fact in many developers' opinions there is no such thing as copyright with JavaScript although it is theoretically possible. The point with copyright and patents is that you can only copyright or patent something completely new a new innovation something that has not been done or written before. *ou can almost guarantee that nothing you do with JavaScript will be a new innovation or even newly written.Someone will have done it before almost certainly using the e#act same algorithm with 4ust a few variable names changed. JavaScript is 4ust not designed for innovative programming since it 4ust uses A5Is designed by someone else to do what you are doing and they already came up with it before you in order to invent the A5I. 3ven if you write something in a 'new' way it will still be doing something that has already been done and if you did attempt to ta!e things too far and ta!e the matter to court you would 4ust be laughed bac! out of it again. As for protecting what you send JavaScript is passed in te#t not compiled to a binary first so the code is always visible. -ow can you stop people seeing the source when you are sending the source to each viewerT /et me wal! through the problem. If the source of the JavaScript is held in the page you are viewing a simple 'view source' will show you the script. /oo!ing in the browser's cache will show the scripts that are in header files. 6f course you need to chec! the source first to find the name of the header file. .any developers have spotted the fact that both of these methods re%uire the 'view source' to be available so they prevent the viewer from viewing the source. They do this by preventing the conte#t menu from appearing when the user right clic!s and by removing menus by using window"open etc. 'elieve me both of these are useless. *ou cannot stop right clic!s in all browsers 0even in some where you can the user can prevent scripts from bloc!ing it1. So some people try to prevent these browsers from viewing the page by using browser sniffing. This is e%ually uneffective. All the viewer has to do is swich off script when they get to the page or view the source of previous pages to find the location of the protected page. In adition 6pera .o7illa&Firefo# Safari and Internet 3#plorer are all capable of running user scripts that allow the user to override restrictions made by the page. Some people even try to ma!e sure that the page is only delivered if a referrer header is sent to ma!e sure that the user came from the right page and is not attempting to type in a location manually. So the user can use +url a program that allows them to re%uest a page with referrer header coo!ies form fields etc. and save the download to a te#t file. Some people try to encode the script using char+odeAt or escape but as the decoding techni%ue is provided in the page only simple modifications are re%uired to ma!e the script appear in te#t not as embedded script. I have seen one set of scripts that have been 'protected' by changing their variable

names to completely incomprehensible names wor! to turn this bac! into understandable code.

and adding several redundant lines of

incompressible code and removing all redundant spaces and linebrea!s. It does not ta!e too much

*ou may want to protect your code but it simply is not possible. Someone who is determined will be able to find it out.

0asswor protecting a file It is best to do this with a server side script and an encrypted connection. 'ut since this is JavaScript ... Ta!e the following for e#ample. I want to only allow someone to access my page if they put in the correct password. I want to provide a bo# for them to write it and then I want to test if it is correct. If it is I let them view the page. The problem is that in the source of the page I have to write the password in the script to test what they have written. For e#ample$
if/ doc1ment"forms&:*"elements&:*"val1e == ,mypassword, 0 F location"href = ,protectedpage"html,. G

As described in the above section you cannot protect the source of a page especially from someone who is really determined. There is no point in trying. 6nce a user managed to see the source they could see the password or the @;/ in plain te#t or encoded but again that is easy to brea!. For simple security try this techni%ue. "ame the file to be protected whatever*our5asswordIs.html and ma!e sure there is an inde#.html file in the same directory. "ow use the following$
<form action="" ons1bmit="location"href = this"elements&:*"val1e % ,"html,. ret1rn false."> <inp1t type="text"> <inp1t type="s1bmit" val1e="S1bmit"> </form>

The problem with this techni%ue is that the page is still passed in plain te#t across the Internet as is the name of the page that you send. If anyone is snooping at data pac!ets on the Internet they can retrieve the page's contents. In many places pac!et snooping is illegal but that does not mean that no-one does it. This protection techni%ue is !nown as security by obscurity in other words it is only secure because no-one !nows it is there. If someone was determined they would find it. As a more complicated solution try creating your own encryption techni%ue that uses a password as an encryption !ey. 3ncrypt the contents of the file. As the page loads use window"prompt to as! the user for a !ey. Try decrypting the page with their !ey using doc1ment"write to write the page. If your techni%ue is good enough wrong passwords would only produce an incomprehensible output. )ith this techni%ue the password is never transmitted over the internet in plain te#t and neither is the content. This techni%ue could be crac!ed by brute force trying every possible password until something wor!s. 'etter passwords and encryption algorithms will help but if someone was determined they would brea! it. 6ne of my readers has submitted a script to do this based on ;+A and 'aseMA. I have used both of these techni%ues.

7ncr!pting ata before it is sent to !ou "ormally this cannot be done with JavaScript using the Internet alone. *ou can encrypt te#t at the user's end and unencrypt it at your end. The problem is that the user has to encrypt it with a password that you !now so that you can unencrypt it. They would have to tell you by telephone or post. Alternatively you could put the password in the source of the page and get the function to encrypt using that !ey. 'ut this password would have to be sent over the internet in plain te#t. 3ven if you did encode it it would not be too much wor! for a snooper to crac! it. In fact the encryption could even be bro!en with brute force techni%ues. So what do you doT The best possible techni%ue would be to create a symmetric encryption !ey using a twin public&private !ey pair as with techni%ues such as ,iffie--ellman or SS/ or use an asymetric public&private !ey pair and encryption techni%ue as with 585 or ;SA. The problem is that in order to prevent brute force crac!ing techni%ues these re%uire the browser to handle numbers as high as =#<GMGG or higher. JavaScript is 4ust not natively capable of wor!ing with numbers as high as this. As yet I have found no solution to this although onhttp$&&shop-4s.sourceforge.net& there is an algorithm for emulating large number handling and an e#ample of JavaScript powered ;SA. The

techni%ue seems to wor! and ta!es only a few seconds to create !eys by using comple# mathematics and algorithms 0loo! at the source of crypto.4s1 to emulate large number handling. 3ven so if doing the e%uivalent of ;SA 0etc.1 it is still not possible for the user to verify your identity as with SS/ certificates so it would be possible for a third party to in4ect their own code and have the information sent to them instead without the user's !nowledge. For the best security stic! to real SS/.

0rotecting !our email a

ress

This is one of the very useful things that JavaScript can do. For those that don't understand the problem I will summarise. Search engines 'crawl' the Internet following the lin!s in pages and re%uesting other ones so that they can add the pages to their search databases. @sing the same technology spammers crawl the Internet loo!ing for email addresses whether in mailto$ lin!s or 4ust written on the page. These email harvesters are one of the most annoying uses of otherwise useful technologies. Simply writing your email address on any web page 0through newsgroup postings etc1 can leave you flooded with unsolicited emails. .any people fall into the trap of replying to these emails as!ing to be removed from the mailing list and succeed only in confirming that their email address is valid. The problem is that you may actually want your email address on the page or a lin! that automatically opens up a new email to you. There are a couple of steps you can ta!e to prevent the problems with unsolicited emails$

@se a throw-away email address li!e a yahoo or hotmail account when posting to

newsgroups signing online guestboo!s or writing your email address on your )eb pages. That way when you start to get too much spam on that email address you can 4ust dispose of that email account and get a new one.

If you can tell your email client 0program1 not to send read-confirmations when you read 'e careful when setting up auto-replies. )hen you post your email address change it to read with something K

your emails. This way your email client does not automatically confirm your email address.

li!emy"ameK;3.6(3WT-ISmydomain.com or my"ame0replace

symbol1mydomain.com and hope that anyone who legitimately replies to it wor!s out what they need to do to turn it bac! into a proper email address. The problem is that not all of them understand this and don't understand why the email adress does not 4ust wor!. So you can try the ne#t point as well$

@se JavaScript. -owT ;ead onY

,sing JavaScript to write !our email a

ress

I have never heard of an email harvester that is clever enough to interpret JavaScript. All they can do is read the te#t that ma!es up the page. So if you write your email address with JavaScript they will not be able to read it. ;emember that if you write the email address as a single word even in the JavaScript they may still interpret it as an email address so it helps to brea! it up a little$
var theAame = ,myOmailAame,2 the(omain = ,myOmail(omain"com,. doc1ment"write/ ,Hy email address is , % theAame % ,E, % the(omain 0.

This outputs$ Hy email address is myOmailAameEmyOmail(omain"com *ou can also use a mailto lin!$
var theAame = ,myOmailAame,2 the(omain = ,myOmail(omain"com,. doc1ment"write/ ,<a href="mailto6, % theAame % ,E, % the(omain % ,">'ontact me<L/a>, 0.

This outputs$ 'ontact me *ou could even use a combination of both$


var theAame = ,myOmailAame,2 the(omain = ,myOmail(omain"com,. doc1ment"write/ ,<a href="mailto6, % theAame % ,E, % the(omain % ,">, % theAame % ,E, % the(omain % ,<L/a>, 0.

This outputs$ myOmailAameEmyOmail(omain"com There is however a problem with this approach. It relies on your viewers having JavaScript enabled. .any of your more web-aware viewers will not. In my case these are often li!ely to be people who I want to contact me. Fortunately these viewers are the ones who are li!ely to understand what to change if you tell them to as I have showed above 0in the bullet points1. So you can use a combination of both approaches$
<script type="text/javascript"> var theAame = ,myOmailAame,2 the(omain = ,myOmail(omain"com,.

doc1ment"write/ ,<p><a href="mailto6, % theAame % ,E, % the(omain % ,">, % theAame % ,E, % the(omain % ,<L/a><L/p>, 0. </script> <noscript> <p><a href="mailto6myOmailAame/replace with E symbol0myOmail(omain"com"> myOmailAame/replace with E symbol0myOmail(omain"com</a></p> </noscript>

In your browser this outputs$


myOmailAameEmyOmail(omain"com
Semicolons

For use of the semicolon in the 'for' loop see the section on control structures. If you have managed to get through this whole thing and still not wor!ed out where to put semicolons here's how to wor! out where to put them. The basic idea of semicolons is to tell the browser that you have 4ust finished a command. *ou actually don't need them at all if you put each instruction on a different line 0with some e#ceptions discussed below1 but it is good practice to put them in anyway. It is easier to remember where not to put them. ,on't put them immediately after a F or G e#cept when creating ob4ects with the FG synta# or functions with the name = f1nction /0 FG synta#. ,on't put them on an otherwise blan! line. ,o not put two in a row. If you write a command or instruction you should put a semicolon. These are e#amples of where you should put a semicolon$

var myvariable = ,s1gar,. doc1ment"myform"s1bmit/0. doc1ment&,myimage,*"src = myStored5mage"src.

And these are e#amples of where you should not put a semicolon$

if/ x < @ 0. F x%%.

G if/ x < @. 0 F x%%. G if/ x < @ 0 F. x%%. G if/ x < @ 0 F x%%. G. if/ x < @ 0 F x%%.. G

There are some situations where it is very important to include a semicolon before a line brea! even though it may appear to be optional. These occur when the command ends with a variable or function reference and the first character in the ne#t command is a left parenthesis or s%uare brac!et$
var b = = var a = ; % b /otherwindowTotherwindow"doc1ment6doc1ment0"write/,complete,0

)hat will happen is that the JavaScript engine will assume the parenthesis or s%uare brac!et relates to the previous command instead of being a new command and will attempt to run the previous command as a function 0or reference its properties in the case of s%uare brac!ets1 and will pass it the result of the e#pression inside the parentheses as a parameter to it. That ma!es it e%uivalent to this$

var b = = var a = ; % b/otherwindowTotherwindow"doc1ment6doc1ment0"write/,complete,0

That could also be e#pressed as this$


var b = = var foo = otherwindowTotherwindow"doc1ment6doc1ment var bar = b/foo0 var a = ; % bar"write/,complete,0

In this case it will produce errors but there are some cases where it can in fact produce a real output that is meaningless and the problem is very hard to trac! down. There are also many other less obvious situations where the same effect can occur without even appearing to be a variable reference on the preceding command 0such as where the previous command was assigning an anonymous function to a variable1. For this reason it is useful to always use semicolons when they are optional as it removes the ambiguity$
var b = =. var a = ; % b. /otherwindowTotherwindow"doc1ment6doc1ment0"write/,complete,0.

The basic way the script interpreter wor!s is that if there is no semicolon it will continue scanning the ne#t line and if it sees something at the start of it that cannot possibly be a part of the command on the previous line then it will assume you forgot to insert a semicolon and it will effectively put one there for you. If it can be part of the last command it will assume it is part of the last command. 6perators and property references are an obvious e#ample of what will be allowed to continue the last command. This can sometimes be used to your advantage to !eep things neat and readable. -owever it can also trip you up if you are unprepared for it as shown above. As an e#ample of this being ta!en to the e#treme ta!e the following code which uses no semicolons at all and lets the script interpreter attempt to wor! out where the commands start and end$

<p>5</p> <script type="text/javascript"> var myC = doc1ment " //comment getOlementsSyTagAame

another /

comment / ,p, 0 & : * " inner-THR % , was , alert / myC

% & ,here, 2 ,there, * & : * 0 </script>

Functionally that is identical to this$


<p>5</p> <script type="text/javascript"> var myC = doc1ment"getOlementsSyTagAame/,p,0&:*"inner-THR % , was ,. alert/ myC % &,here,2,there,*&:* 0. </script>

$"e JavaScript object

This page gives a list of ob4ects properties collections and methods for documents and JavaScript components. This view of all properties available from the respective element types is referred to as the JavaScript ob4ect. Some browsers may provide aditional properties or methods but as this stage of the tutorial is intended to teach you how to program so that your scripts wor! in all the possible 0so called Ath generation1 browsers I have given those that are available in all possible browsers or those which have an alternative which I will also have given. This is the last chapter of this tutorial where I will deal with such a wide range of browsers. In the ne#t few chapters I will abandon A th generation

browsers and move on to the much more advanced ,6. browsers 0also !nown as Hth generation browsers1.

)ontents

Standard document components - all addressable components of a web page. 5ositioned elements - all addressable components of an absolutely positioned div. 3vent ob4ects - all accessible information about an event. Intrinsic ob4ects - variable types with constructors.

6e!

(arent object
o o o o o

"ild object "ild property "ild object being accessed t"roug" a collection)* Event Met"od+,

For items written in the format$ 'methodAame/&some8therSt1ff*0' some8therSt1ff is optional and does not need to be written. The PQ brac!ets must be removed. For items written in the format,methodAame/type varAame0, ,type, gives the type of variable e#pected by the method or collection calledvarAame in this case. To use this structure to refer to any ob4ect property collection or method treat each new branch level as a new child level. For e#ample$
window"doc1ment"name8f7orm"name8f5np1t"defa1lt+al1e = ,5 love it,.

"ote all collections also have the length attribute. Also note window is often omitted when referring to child ob4ects.

Stan ar

ocument components

window or sel#

o o o o o o

Array -oolean closed .ate

parse+string dateAsAString,

de#aultStatus document

bg olor body

clientHeig"t client!idt" scroll/e#t scroll$op style


bac0ground bac0ground olor color

coo0ie documentElement

clientHeig"t client!idt" scroll/e#t scroll$op style


bac0ground bac0ground olor color

domain #g olor IdO#(ositionedElement lastModi#ied nameO#&orm


action encoding lengt" met"od name

nameO#Input1textarea1select or nameO#InputsS"aring2ame)int index*


c"ec0ed de#ault "ec0ed de#aultValue disabled #orm lengt" name selectedIndex type value options)int numberO#Option!it"SelectInput*

de#aultSelected index selected text value

onblur onc"ange onclic0 ondblclic0 on#ocus on0eydown on0eypress on0eyup onmousedown onmouseup blur+, #ocus+, select+,

target elements)int numberO#Input* onreset onsubmit reset+, submit+,

nameO#Image

border complete "eig"t lowsrc name src widt" onabort onerror onload onmousedown onmouseup

re#errer title %'/ all)string IdO#Element* anc"ors)int numberO#A$ag!it"2ame.e#ined*


name o##set/e#t o##set(arent o##set$op x y nameO#(ublic(roperty nameO#(ublicMet"od+, "eig"t "idden name pluginspage src type units widt" onload

applets)int numberO#Applet$ag*

embeds)nameOr2umberO#EmbeddedObject*

nameO#(ublicMet"od+,

#orms)int numberO#&orm* images)nameOr2umberO#Image* layers)string IdO#(ositionedElement* lin0s)int numberO#A$ag!it"Hre#.e#ined*See (ositioned Element


"as" "ost "ostname "re# inner$ext o##set/e#t o##set(arent o##set$op pat"name port protocol searc" target text x y onblur onclic0 ondblclic0 on#ocus onmousedown onmousemove onmouseout onmouseover onmouseup blur+, #ocus+,

plugins)numberO#Object* onclic0 ondblclic0 on0eydown on0eypress

o o

on0eyup onmousedown onmousemove onmouseout onmouseover onmouseup captureEvents+Event3Event$ype, close+, getElement-yId+string IdO#Element, open+, write+string content, writeln+string content,

event Event

/I 4 .-/ /I 4 4E5.O!2 4E5('ESS 4E5%( MO%SE.O!2 MO%SEMOVE MO%SEO%$ MO%SEOVE' MO%SE%(

o o

&unction "istory

bac0+, #orward+, go+int numer$oJump,

o o o o o

Image innerHeig"t inner!idt" lengt" location


"as" "ost "ostname

"re# pat"name port protocol searc" reload+)bool #orce&ull'eload*, replace+string location, E /26 /278 /O96E /O978E (I S:'$7;6 S:'$6 abs+number n, acos+number n, asin+number n, atan+number n, atan6+number n<number 0, ceil+number n, cos+number n, exp+number n, #loor+number n, log+number n, max+number a<number b<number c<33333, min+number a<number b<number c<33333, pow+number n<number 0, random+, round+number n, sin+number n, s=rt+number n, tan+number n,

Mat"

o o

name navigator

app ode2ame

app2ame appVersion language plat#orm userAgent user/anguage mime$ypes)nameOr2umberO#MIME$ype*


description enabled(lugin su##ixes type description #ilename lengt" name nameOr2umberO#MIME$ype

plugins)nameOr2umberO#(lugin*

o o o o o o o o o o

javaEnabled+, taintEnabled+, MA>;VA/%E MI2;VA/%E 2a2 2E9A$IVE;I2&I2I$5 (OSI$IVE;I2&I2I$5

2umber

Object opener Option outerHeig"t outer!idt" page>O##set page5O##set parent 'egExp


?7 333 ?@ input lastMatc" or ?A

last(aren or ?B le#t ontext or ?C rig"t ontext or ?D availHeig"t avail!idt" color.ept" "eig"t pixel.ept" widt"

screen

o o o o o o o o o o o o o o o o o o o o o o o o o

status String

#rom "ar ode+number ascii "aracterValue, name

#rames)nameOr2umberO#&rame* onblur onerror on#ocus onload onunload alert+object, blur+, clearInterval+interval object, clear$imeout+timeout object, close+, con#irm+string message, escape+string text$o%'/Encode, eval+string script$oEvaluate, #ocus+, is&inite+number number$o "ec0, is2a2+number number$o "ec0, move-y+int xO##set<int yO##set, move$o+int x(os<int y(os, open+string url)<string target2ame)<string options)<bool replaceHistoryEntry***, parseInt+string text ontainingAnInteger)< int radix*, parse&loat+string text ontainingA&loat, print+,

o o o o o o o o

prompt+string message<string de#aultValue, resiEe-y+int xO##set<int yO##set, resiEe$o+int x!idt"<int y!idt", scroll-y+int xO##set<int yO##set, scroll or scroll$o+int x(os<int y(os, setInterval+string or #unction script$oEvaluate<int timeInMilliseconds, set$imeout+string or #unction script$oEvaluate<int timeInMilliseconds, unescape+string text$o%'/%nEncode,

0ositione elements In ,6. and proprietary ,6. browsers this could actually be any element not 4ust one that is positioned. -owever at this stage of the tutorial only A th generation ,-T./ is being discussed and therefore this is referred to as a positioned element. The ne#t chapter will show how this applies to all elements not 4ust those that are positioned.

(ositionedElement
o o

bg olor clip

bottom le#t rig"t top

o o o o o o

document id innerH$M/ le#t name style


bac0ground bac0ground olor clip color "eig"t le#t pixelHeig"t pixel/e#t

o o o o o o o o o o o o o o o

pixel$op pixel!idt" top visibility widt" EIndex

top visibility EIndex onclic0 ondblclic0 on0eydown on0eypress on0eyup onmousedown onmousemove onmouseout onmouseover onmouseup captureEvents+Event3Event$ype, resiEe$o+int widt"<int "eig"t,

7vent ob"ects

window3event or #irst argument passed to "andler #unction


o o o o o o o o o o o

alt4ey button client> client5 ctrl4ey 0ey ode modi#iers page> page5 screen> screen5

o o o o o o

s"i#t4ey target t"is type srcElement w"ic"

8ntrinsic ob"ects showing constructors The constructors are all properties of the window ob4ect but they are almost always used without 'window.'. Synta#$
var variableAame = new intrinsic8bject'onstr1ctor/options0.

For e#ample$
var my)rray = new )rray/,here,2,there,2,everywhere,0.

$rra!

Array+)int lengt"*, +not in JavaScript 736, Array+)element 8)< element 7)< element 333 n***, )element 8< element 7< element 333 n*
o o o o o o o o o o o o

lengt" concat+element$oAdd)<element$oAdd)<element$oAdd)<etc3***, join+)string separator$o'eplace omma*, pop+, pus"+element$oAppend, reverse+, s"i#t+element$oAppend, slice+int o##set&romStart)<int o##set$oEnd*, sort+)#unction sort&unction*, splice+int o##set&romStart<int number$o'emove)<element$oAdd)<element$oAdd)<etc3***, toString+, or valueO#+, uns"i#t+,

9oolean

-oolean+)bool value*, true or #alse


o o

toString+, valueO#+,

Date "ote a @"I9 timestamp 0milli1 is the number of milliseconds since GG$GG$GG.GGG G<&G<&<DIG currently <=LHMI<HD:LLG. "ote also that @T+ is the time as it would be in the 8.T time7one so 8.T and @T+ are e%uivalent.

.ate+, .ate+int %2I>$imestampMilli, .ate+year< mont"< date)< "ours)< minutes)< seconds)<ms****,


o o o o o o o o o o o o o o o o o o o o o o

get.ate+, get.ay+, get&ull5ear+, getHours+, getMilliseconds+, getMinutes+, getMont"+, getSeconds+, get$ime+, get$imeEoneO##set+, get%$ .ate+, get%$ .ay+, get%$ &ull5ear+, get%$ Hours+, get%$ Milliseconds+, get%$ Minutes+, get%$ Mont"+, get%$ Seconds+, get5ear+, set.ate+int dayO#Mont", set&ull5ear+int yearInF.igit&ormat)<int mont")<int dayO#Mont"**, setHours+int "ours)<int minutes)<int seconds)<int milliseconds***,

o o o o o o o o o o o o o o o o

setMilliseconds+int milliseconds, setMinutes+int minutes)<int seconds)<int milliseconds**, setMont"+int mont")<int dayO#Mont"*, setSeconds+int seconds)<int milliseconds*, set$ime+int %2I$>$imestampMilli, set%$ .ate+int %2I$>$imestampMilli, set%$ &ull5ear+int yearInF.igit&ormat)<int mont")<int dayO#Mont"**, set%$ Hours+int "ours)<int minutes)<int seconds)<int milliseconds***, set%$ Milliseconds+int milliseconds, set%$ Minutes+int minutes)<int seconds)<int milliseconds**, set%$ Mont"+int mont")<int dayO#Mont"*, set%$ Seconds+int seconds)<int milliseconds*, set5ear+int numberO#5earsSince7@88, to%$ String or to9M$String+, toString or to/ocaleString+, valueO#+,

:unction

&unction+)string var2ame<)string var2ame6<)etc3***string script$oEvaluate, #unction #unction2ame+listO#Variables, G #unction code H #unction2ame I #unction +listO#Variables, G #unction code H
o o o o o o o o

caller prototype t"is arguments)*

callee

apply+objectJ t"isObject)<arrayJ arguments*, call+objectJ t"isObject)<argument)<argument)<etc3***, toString+, valueO#+,

8mage

Image+)int widt"<int "eig"t*,

Number

2umber+numberOrString value, number in "ex< octal or decimal


o o o o o o

to&ixed+precision, to(recision+precision, toExponential+precision, to/ocaleString+, toString+, valueO#+,

*b"ect

Object+, G property2ame7J value7)< property2ame6J value6)< etc3** H


o o o o

constructor "asOwn(roperty+string property2ame, toString+, valueO#+,

*ption

Option+)string text<string value)<bool selected**,

&egular 7xpression

'egExp+string pattern<string options, 1pattern1options


o o o o o o o

compile+string pattern<string options, exec+string string$oMatc", global ignore ase lastIndex source test+string string$oMatc",

String

String+)stringOrObject$o-e'epresentedAsString*, DcontentD KcontentK


o o o o o o o o o o o o o o o o o o o o o o o o o o o o o

lengt" anc"or+string nameO#Anc"or, big+, blin0+, bold+, c"arAt+int index, c"ar odeAt+int index, concat+string string$oAppend)<string string$oAppend)<string string$oAppend etc3**, #ixed+, #ontcolor+string colorValue, #ontsiEe+int siEe, indexO#+string searc"String)<int o##set*, italics+, lastIndexO#+string searc"String)<int o##set*, lin0+string "re#$o/in0$o, matc"+'egExp searc"Expression, replace+'egExp searc"Expression<string replacement$ext, searc"+'egExp searc"Expression, slice+int o##set&romStart)<int o##set&romEnd*, small+, split+'egExp separator)<int maxArray/engt"*, stri0e+, sub+, substr+int startIndex)<int lengt"*, substring+int startIndex<int endIndex, sup+, to/ower ase+, to%pper ase+, valueO#+,

!L

.OM introduction

This part of the tutorial steps beyond the limits of the older browsers and will cover the much more advanced abilities of the current browsers. Than!s to 55$U for lin!ing to this page from his ,igital )eb article about the ):+ ,6.. -e refers to this as a 'less technical introduction' to the ):+ ,6.. I am happy with that description not only because the 'technical introduction' is a =:D page 5,F of incredible detail but because I don't see why the ,6. should be that technical. It is designed to be intuitive and easy to use so that is how I will teach it. 6f course there are some incredibly advanced and comple# things you can do with the ,6. but with web pages there is almost never the need to do them. So instead of going into =:D pages of information on how to convert the planet 3arth into a ,6. tree I will give you a gentle introduction to the fundamentals of the ,6. and show you how to achieve the results you need with the minimum of fuss. The ):+ ,6. commonly !nown as 'The ,6.' or the ',6. level <0&=&:1' provides a more realistic and more versatile way of loo!ing at the structure of -T./ documents 0as well as 9./ and other document formats1. It views -T./ documents as a tree structure of elements and te#t embedded within other elements. All -T./ elements as well as the te#t they contain and their attributes can be referenced by wal!ing through the ,6. tree their contents can be modified or deleted and new elements can be created for subse%uent insertion into the ,6. tree. -T./ elements the te#t they contain and their attributes are all !nown as nodes. The ,6. is designed to interact with more programming languages than 4ust JavaScript but as this is a JavaScript tutorial 0in case you didn't notice...1 and most browsers only support JavaScript I will only describe how to use JavaScript to interact with it. The ,6. is the present and future of browsers and no doubt it will become the only supported techni%ue for both basic and advanced ,-T./ in the future. The ):+ ,6. is supported by Hth generation browsers. These currently include$

6pera IJ .o7illa 8ec!o 0.o7illa Firefo# "etscape MJ1 U-T./&)ebUit 0Uon%ueror =J Safari 6mni)eb A.HJ1 Internet 3#plorer HJ i+ab :J 0=- is passive only1 I+3browser 3scape&3vo H 0partial only Pand bro!enQ1 T!html -v: 0partial only Pand bro!enQ1 "etFront :J 0partial only1

"etgem A browser 0"et'o#1 - not tested 6penT( - not tested i5anel .icro'rowser with advanced modules - not tested

For more details of these browsers and to download them please see my list of 'AthJ generation' browsers. This list ma!es it clear that Internet 3#plorer A "etscape A 3scape A 6pera A H and M 6mniweb A.=- and )ebT( all do not support the ):+ ,6.. Some of these browsers are still in use and should not be discounted. It is important to chec! that a browser supports the ):+ ,6. before you attempt to use it. "ote that 6pera A-M also supports many of the basic functions of the ):+ ,6. but cannot actually use most of them. i+ab =- cannot perform advanced ):+ ,6. functions. Therefore the best test for ):+ ,6. support that I can find is this$
if/ doc1ment"getOlementSy5d PP doc1ment"childAodes PP doc1ment"createOlement 0 F //do something that reV1ires it G

6f all the current ma4or browsers Internet 3#plorer's ,6. support is by far the worst of all. The )indows version supports half of the ,6. < modules and parts of a few ,6. = modules. The .ac version supports slightly more of ,6. <. 6pera and .o7illa are competing for first place with complete ,6. < support complete or almost complete ,6. = support and a small amount of ,6. : support. U-T./&)ebUit is not far behind with complete ,6. < and almost complete ,6. =. i+ab has partial ,6. < and ,6. =. 6pera DJ is the first and currently only browser to support all ,6. < and = features well enough to claim support for all of them 0as well as a number of ,6. : modules1. Safari also claims support for all ,6. < and = features but its ,6. = Style Sheets and +SS implementation is so bad it should not be allowed to claim support for them at all. This tutorial will concentrate on things that will wor! in all these browsers since they are the most common browsers currently in use and will show how to bridge the gap to allow Internet 3#plorer's non-standard features to be used as a partial replacement for missing parts of important ,6. features. I+3browser has largely complete ,6. < and partial ,6. = 0it also claims some ,6. : but my tests cannot support its claims especially since it is missing large parts of ,6. = that it claims to support1. It will cope with most of the things I will cover in this tutorial.

3scape H can handle enough ,6. to reference elements and their styles and can move them through the document. -owever as soon as you try anything more than that 0wal!ing the ,6. tree creating new elements changing their contents chec!ing for the e#istence of a child"odes collection etc1 it produces script errors and fails to use try...catch correctly so the errors cannot be avoided. In this state it is unusable and it can't even handle many basic ,-T./ scripts either. Just ignore it. It is hardly used by anyone and hopefully they will improve its ,6. support in the near future so that it can handle these scripts. "etFront has recently added ,6. support and it is still very immature. 8enerally versions earlier than :.A will produce errors or crash and as a result should be ignored as ,6. browsers. (ersion :.A usually performs better. 55$U maintains many ,6. < tutorials as well as the ever helpful ,6. compatibility tables. Although the ,6. provides many more methods properties and collections than I have shown here most are not reliable enough to use so I will only tal! you through those that are. If you intend to use other properties or methods you should chec! if the browser supports them first using$
if/ node"property'ollection8rHethodAame 0 F //do something that reV1ires it G

.OM nodes and tree

The D*M tree The following te#t is a snippet of -T./ ta!en from a regular -T./ document.
<p title="The test paragraph">This is a sample of some <b>-THR yo1 might<br>have</b> in yo1r doc1ment</p>

In your browser this renders as this 0hold your mouse over the paragraph to see the title - most browsers display it as a tooltip some display it in the status bar1$ This is a sample of some H$M/ you mig"t

"ave in your document The ,6. tree views this 0simplified1 as follows$

C 333333333333333Q33333333333333 Q childAodes 33333333333333Q33333333333 Q ,This is a sample of some , Q S Q childAodes 3333333333Q3333333 Q ,-THR yo1 might, Q SN Q ,have, Q , in yo1r doc1ment, Q attrib1tes Q title = ,The test paragraph,

6f course the tree also e#tends above the '5' from window.document through the -T./ element down through the body element then through any other container elements to the paragraph. The parts of the ,6. tree are !nown as nodes. The '5' ''' and '';' nodes are element nodes childNodesand attributes are collections attribute node and the te#t strings are te#t nodes. the title=,The
test paragraph, pair is an

&eferencing the element no es



Uon%ueror incorrectly re%uires the get9lements:y&ag!ame parameter to be in lower case when using i+ab : fails to !eep the ob4ect returned by get9lements:y&ag!ame updated. T!html -v: adds all te#t nodes that appear before the opening <body> tag as separate te#t nodes into the 3scape&3vo H fails to use the child!odes collections and will abort the script. Ignore this browser. 3arly I3H .ac did not provide the child!odes,length property. This was fi#ed automatically. If you are

9-T./ strict doctypes but served as te#t&html.

body'schild!odes collection.

worried use something li!e this$ for/ var x = :. node"childAodes&x*. x%% 0

@sing the ,6. there are several ways that we could reference the paragraph. )e can usegetElementsByTagName to reference all paragraphs then choose the one we want. If the paragraph were to be given an id we could also use getElementById$
doc1ment"getOlementSy5d/,id of paragraph,0 doc1ment"getOlementsSyTagAame/,p,0&index8fCaragraph*

If we assigned the paragraph an id so that we could use getElementById the id=,element5(, pair would appear in the attributes collection along side title=,The test paragraph, in the tree diagram above. "ote that if the document is served with an 9./ based content-type header getElementsByTagNamebecomes case sensitive. "6T3$ getElementsByTagName does not return a true collection it returns an ob4ect with element inde# and 'length' properties. This ob4ect !eeps itself up to date so if an element it references is deleted or added it will automatically change its item references to reflect that change. )e could even wal! the entire ,6. tree from the document ob4ect for e#ample$
window"doc1ment"childAodes&:*"childAodes&9*"childAodes&?*

In this case window.document.childNodes[0] should be the -T./ element as it is the first tag in the document 0assuming there is no doctype tag1 and window.document.childNodes[0].childNodes[1]should be the body tag as the head element will be the first child of the -T./ element. Alternatively there is a shortcut to the -T./ element$ document.documentElement so we could use this$
window"doc1ment"doc1mentOlement"childAodes&9*"childAodes&?*

There is also a shortcut to the '6,* element$ document.body so we could use this$
window"doc1ment"body"childAodes&?*

Those last three e#amples are based on a simple page structure where the paragraph is a direct child of the body element. "either of these would be correct in the current document as the document structure is far more comple# also using ,I( elements as parents of the paragraph.

The techni%ues used in those e#amples can be unreliable. .ost browsers will correctly view the blan! space between tags as a te#t node containing only white space characters 0such as space line-brea! or tab1 even if the blan! space is not rendered such as a gap in between a EtrF tag and a EtdF tag or a blan! gap in between EpF tags. -owever some browsers 0mainly Internet 3#plorer1 will not view this empty space as a te#t node at all. This means that the childNodes collection will be different lengths in these different browsers. If you are trying to wal! the ,6. tree to the ne#t element node for e#ample it may be worth chec!ing each entry in thechildNodes collection to see if its nodeType is < or to use node.getElementsByTagName. 'ecause of this and the fact that the structure of the ,6. tree is designed to change as elements are moved added or removed the only reliable way to reference an element is using its I,$
var theCaragraph = doc1ment"getOlementSy5d/,id of element,0

The first entry of the childNodes collection can be accessed using the shortcut firstChild and the last can be accessed using lastChild. node.ne t!ibling references the ne#t entry in the parent node'schildNodes collection and node.pre"ious!ibling references the previous one. To reference the parent node we use node.parentNode. "ote also that all element nodes have the getElementsByTagNamemethod to help reference elements within them. This means that from any node it is possible to reference any of the other notes around it.

&eferencing the attribute no e

T!html -v: does not support the attributes collection.

To reference the title=,The test paragraph, attribute pair we use the attributes collection. ,epending on the browser this collection may be filled up in a variety of different ways and many empty attribute pairs may e#ist in the collection. To find the correct attribute we search through the attributes collection for an attribute whose nodeName matches what we want. The nodeName may be in any case in -T./ documents 0typically upper case1 and should be case sensitive in 9-T./ and 9./ if served using an 9./ based .I.3 type.
for/ var x = :. x < theCaragraph"attrib1tes"length. x%% 0 F if/ theCaragraph"attrib1tes&x*"nodeAame"toRower'ase/0 == ,title, 0 F

window"alert/ ,The val1e of the L,titleL, attrib1te is6 , % theCaragraph"attrib1tes&x*"node+al1e 0. G G

Test it here$ get the attribute value.

$n eas! wa! to check the attribute no e



"etFront gets the case wrong when retrieving attribute values 0align is returned as '+enter' instead of 6pera I-L will retrieve resolved values instead of specified values for attributes li!e 'href' and 'src'. .any browsers 0particularly Internet 3#plorer I-1 will have trouble retrieving values for style and class as

'center'1.

well as event handlers.

If all you want to do is to chec! the value of an attribute not manually edit its entry it is easier to 4ust useget#ttribute.
window"alert/ ,The val1e of the L,titleL, attrib1te is6 , % theCaragraph"get)ttrib1te/,title,0 0.

Attribute names are case sensitive. For e#ample bgcolor must be written as bg+olor. Test it here$ get the attribute value. "ote that according to the specification get#ttribute should always return a string. -owever this ma!es it impossible to differentiate between empty attributes and unspecified attributes. For this reason browsers will return null for unspecified attributes even though this is wrong. 6pera I-L returns an empty string - this was changed to null in 6pera D. As a result code that chec!s for attributes and incorrectly tests against null will fail in 6pera I and L because a string will never e%uate to null. There is no need to test against null 4ust chec! if get attribute failed to retrieve a value$
if/#element"get)ttrib1te/,attrib1te3name,00

)hanging the attribute



Internet 3#plorer I- 0and some minor browsers1 cannot set values for style class or event handlers. 6pera I.G-I.< could not set the align attribute.

The attributes of an element can be set or changed using set#ttribute$


element"set)ttrib1te/,attrib1teAame,2,attrib1te+al1e,0 theCaragraph"set)ttrib1te/,align,2,center,0

Attribute names are case sensitive. For e#ample bgcolor must be written as bgColor. *ou can also remove attributes with a few e#ceptions using remo"e#ttribute$
theCaragraph"remove)ttrib1te/,attrib1teAame,0

.ove

the

paragraph

here

so

you

can

see

what

you

are

doing

then$

+hange the title attribute and +hange it bac! 0hold your mouse over the paragraph to see if the title has changed1.

"etFront :.=- cannot move the e#isting paragraph to a new location 0version :.: may also fail if the device

does not have much memory1 but it gets the rest of the e#ample right.

&ea ing an writing problematic attributes Internet 3#plorer I- 0and some minor browsers1 cannot set values for style class or event handlers usingset#ttribute. Internet 3#plorer L has fi#ed most of these but still cannot set event handlers. A few more browsers also have trouble reading these attributes using get#ttribute. Internet 3#plorer generally returns the wrong type of result such as an ob4ect instead of a string when using get#ttribute for these attributes. The ,6. does provide a few alternatives to allow the functionality to be appro#imated in these browsers. The class is available as a read&write string called className - this is discussed in the ,6. +SS chapter of this tutorial. The event handler attributes are available as referenced functions 0this is not the case for handlers added using ,6. events1 with their names matching the attribute name2 element.onclic$. These

are read&write but must be written as a reference to a function not as a direct string. They can also be written as a string using the %unction constructor$
element"onclic! = new 71nction/code)s)String0.

They may also be read as a string using the to!tring method of the function but note that it will normally contain the anonymous function wrapper and may not be available at all in browsers running on devices with limited capabilities such as mobile phones. "ote also that it will not be available at all if the attribute is not present$
var f1nctioncode = element"onclic!"toString/0.

The string value of the style attribute is available as a read&write string called cssTe t which is a property of the style ob4ect which itself is a property of the element. "ote however that it is not supported very well2 Safari does not support it up to version <.< 0reading it produced the value n1ll1 .o7illa versions prior to <.G could not write to it and i+ab :- "etFront and 3scape&3vo do not support it at all. To avoid problems with its use a combination of cssTe t and get#ttribute&set#ttribute can be used. To read it$
var cssString. cssString = element"style"cssText. if/ typeof/cssString0 #= ,string, 0 F cssString = element"get)ttrib1te/,style,0. G

To write it simply set both versions and the browser will use whichever one wor!s$
var cssString = ,color6lime.font$weight6bold.,. element"style"cssText = cssString. element"set)ttrib1te/,style,2cssString0.

"ote that this will then prevent it from being read correctly if other styles are changed individually. If this will cause a problem chec! if cssTe t is supported first$

var cssString = ,color6lime.font$weight6bold.,. if/ typeof/element"style"cssText0 == ,string, 0 F element"style"cssText = cssString. G element"set)ttrib1te/,style,2cssString0.

&eferencing the text no es

.o7illa&Firefo#&"etscape MJ and 6pera D.=#- will split very long te#t nodes into multiple smaller te#t nodes.

To give a full e#ample I will try to reference the te#t node '-T./ you might'. To do this I will go through the second entry of the childNodes array of the '5'. This will be a reference to the '''. I will then loo! at thefirstChild 0e%uivalent to the first entry in the childNodes collection1 of the ''' to reference the te#t node.
window"alert/ ,The val1e of the text node is6Ln, % theCaragraph"childAodes&9*"first'hild"node+al1e 0.

Test it here$ get the value of the te#t node. Also important to note is that although the specifications say that no matter how much te#t e#ists between tags it should all be in one te#t node in practice this is not always the case. In 6pera ID.=# and .o7illa&"etscape MJ if the te#t is larger than a specific ma#imum si7e it is split into multiple te#t nodes. These te#t nodes will be ne#t to each other in the childNodes collection of the parent element. In 6pera I-D.=# this ma#imum te#t node si7e is := U'. In .o7illa&Firefo#&"etscape MJ it is A U'. Although thenormali&e'( method of the parent node0s1 should be able to replace the multiple te#t nodes with a single te#t node containing all the te#t this only wor!s in .o7illa&Firefo#&"etscape MJ. In 6pera I-D.=# it puts all of the te#t into a single node and then truncates that node to := U' so the contents of all e#cept the first node are lost. ;unning the normali&e method can crash Internet 3#plorer M and does not e#ist in Internet 3#plorer H on )indows. For this reason I do not recommend trying to normali7e. It is better to manipulate the contents of te#t nodes separately. In fact you can create your own te#t nodes and add them to

the childNodes collection. Although to the ,6. they will still appear as separate nodes they will appear as a single piece of te#t in the document. 'asically you need to be aware that your te#t may be split into several nodes if it is A U' or over or if you have added e#tra te#t nodes in yourself. In order to get that te#t in a single variable you may need to loo! through every child node and if they are consecutive te#t nodes append them together to get the total string.

)hanging the text of text no es



U-T./&)ebUit Uon%ueror :.A- Safari <.=- and 6mni)eb A.H-H.G do not always reflow the page when T!html -v: versions before September =GGI cannot change the value of e#isting te#t nodes.

changing the te#t of te#t nodes.

6nce you have a reference to the te#t node you can read or write its contents using its node(alue.
theCaragraph"childAodes&9*"last'hild"node+al1e = ,want to change,.

.ove

the

paragraph

here

so

you

can

see

what

you

are

doing

then$

+hange the te#t node X +hange it bac!.

"etFront :.=- cannot move the e#isting paragraph to a new location 0version :.: may also fail if the device

does not have much memory1 but it gets the rest of the e#ample right.

)reating new no es an removing existing ones

"etFront :.=- cannot create or insert new nodes 0version :.: often crashes with scripts that use this if it is

running on a lower memory device1.

This is what the ,6. was truly created for. In order to create new nodes we use a couple of methods of the document ob4ect to create the node. )e then insert the node into the main ,6. tree at which point the browser will display it. )e can also move e#isting nodes 0li!e the test paragraph1 simply by inserting them into the ,6. tree somewhere else. "ote that when creating element nodes the element name must be in lower case. Although in theory it should not be case sensitive with -T./ I have noticed some problems in Uon%ueror when using upper case with strict doctypes - see the top of this page. It will be case sensitive with 9-T./ 0in all compliant browsers not 4ust Uon%ueror1 and must be in lower case.

var theAewCaragraph = doc1ment"createOlement/,p,0. var theText8fTheCaragraph = doc1ment"createTextAode/,Some content",0. theAewCaragraph"append'hild/theText8fTheCaragraph0. doc1ment"getOlementSy5d/,someOlement5d,0"append'hild/theAewCaragraph0.

)e could also use insertBefore instead of appendChild or even manually add the new element to the end of the end of the childNodes collection. @sing replaceChild we could also overwrite e#isting nodes. It is also possible to copy a node using cloneAode/tr1e0. This returns a copy of the node but does not automatically add it into the childNodes collection. @sing element"remove'hild/referenceTo'hildAode0 we can remove e#isting nodes. Test it here$ create a new paragraph. -ow about something even more complicated. )hat about adding -T./ elements within the new element instead of 4ust plain te#t. -ere I will recreate the test sentence from above one piece at a time.
//three elements are reV1ired6 p2 b2 br var theAewCaragraph = doc1ment"createOlement/,p,0. var theSoldSit = doc1ment"createOlement/,b,0. var theSN = doc1ment"createOlement/,br,0.

//set 1p theAewCaragraph theAewCaragraph"set)ttrib1te/,title,2,The test paragraph,0.

//prepare the text nodes var theText9 = doc1ment"createTextAode/,This is a sample of some ,0. var theText4 = doc1ment"createTextAode/,-THR yo1 might,0. var theText; = doc1ment"createTextAode/,have,0. var theText? = doc1ment"createTextAode/, in yo1r doc1ment,0.

//p1t together the bold bit theSoldSit"append'hild/theText40. theSoldSit"append'hild/theSN0. theSoldSit"append'hild/theText;0.

//p1t together the whole paragraph theAewCaragraph"append'hild/theText90. theAewCaragraph"append'hild/theSoldSit0. theAewCaragraph"append'hild/theText?0.

//insert it into the doc1ment somewhere doc1ment"getOlementSy5d/,someOlement5d,0"append'hild/theAewCaragraph0.

Test it here$ recreate the test paragraph. In case you were wondering how I managed to ma!e those new paragraphs end up 4ust above the lin!s you clic!ed on this is how. The lin! you clic!ed on is in a paragraph. The paragraph is in a div 0although this techni%ue would wor! anywhere1. The script is run in the event handler for the lin!. Therefore in the handler function 'this' refers to the lin!. The parentNode of the lin! is the paragraph - this.parentNode - and the parentNode of the paragraph is the div - this.parentNode.parentNode. I want to get the div to import the new paragraph node I have created above the paragraph the lin! is in so I want to say this$
the(5+"insertSefore/theAewCaragraph2the'1rrentCaragraph0.

In JavaScript this would be$


this"parentAode"parentAode"insertSefore/theAewCaragraph2this"parentAode0.

As for ma!ing them disappear when you clic! on them when creating these paragraphs I also assign an onclic! event handler function that uses this.parentNode to reference the div and then usesremo"eChild to delete the paragraph$
theAewCaragraph"onclic! = f1nction /0 F this"parentAode"remove'hild/this0. G.

"ote that nodes belong to the document they were created in. So for e#ample if your page uses frames and you create a paragraph node in one frame then attempt to add it to the document in another frame it will not wor!. In theory you can use the document.importNode method to create a copy of it in the new document but that method does not e#ist in Internet 3#plorer. If a script in one frame needs to create a node and append it to a document in another frame it must use the document ob4ect for the destination frame when creating the node$
var newC = parent"frames&,leftfr,*"doc1ment"createOlement/,p,0. parent"frames&,leftfr,*"doc1ment"body"append'hild/newC0.

,sing ocument fragments



Internet 3#plorer H.# on )indows "etFront :.:- and T!html -v: do not support document fragments. Internet 3#plorer H on .ac cannot add te#t nodes to document fragments and cannot append the

fragment's contents to a document.

It is also possible to deal with multiple nodes at the same time. Say for e#ample that you want to create <G paragraphs and add them all to the document at the same time as each other instead of one at a time. This can be done using a document fragment. The benefit of using this is that it creates fewer document reflows and as a result it can improve performance for big changes. A document fragment is li!e a normal element 0such as a div1 e#cept that it cannot become a part of the document itself. If you try to append a document fragment to any part of a document instead of appending the fragment the browser will add the child nodes of the fragment. For e#ample you create <G paragraphs append them to a document fragment then append the document fragment to the body of a document. Instead of appending the fragment to the body it will add the <G paragraphs as children of the body.
var frag = doc1ment"create(oc1ment7ragment/0.

for/ var i = :2 p. i < 9:. i%% 0 F p = doc1ment"createOlement/,p,0. p"append'hild/doc1ment"createTextAode/,Caragraph ,%/i%9000. frag"append'hild/p0. G doc1ment"body"append'hild/frag0.

Test it here$ create and append a new document fragment. )hen you clic! on the lin! this is the output we get. 5aragraph < 5aragraph = 5aragraph : 5aragraph A 5aragraph H 5aragraph M 5aragraph I 5aragraph L 5aragraph D 5aragraph <G )hen we clic! again we get this. = times now since we clic!ed on it two times. 5aragraph < 5aragraph = 5aragraph : 5aragraph A 5aragraph H 5aragraph M

5aragraph I 5aragraph L 5aragraph D 5aragraph <G 5aragraph < 5aragraph = 5aragraph : 5aragraph A 5aragraph H 5aragraph M 5aragraph I 5aragraph L 5aragraph D 5aragraph <G
.OM tables

Uon%ueror Safari and 6mi)eb A.HJ get the cellInde# property wrong. T!html -v: only supports table"tSodies tSodies&*"rows rows&*"cells and childAodes but 5re-alpha versions of T!html -v: only support table"tSodies and childAodes but none of the other

none of the other properties shown here. properties shown here.

Assuming that you have a reference to the table element 0see the last section1 you can do some fairly in-depth manipulation of the table's structure. In order to do this you have to view tables as in the full -T./A specification. A table contains a caption a thead any number of tbodies and a tfoot. If you did not specify a tbody the ,6. will still have one tbody in the tSodies collection which will contain all of the rows. There are many methods associated with these but most of those designed to create parts of tables as well as the one to delete table captions are not implemented properly in some browsers so I will only tal! you through those that are the most reliable.

table
o

caption

c"ild2odes)*

tHead

rows)*

cells)*

c"ild2odes)*

t&oot

rows)*

cells)*

c"ild2odes)*

t-odies)*

rows)*

cells)*

c"ild2odes)*

As well as being able to wal! through the ,6. tree as before you can also wal! through the ,6. table tree. 3ach table has four e#tra properties that reference the various child"odes$
caption

;eferences the caption of the table


thead

;eferences the thead of the table if there is one


tfoot

;eferences the tfoot of the table if there is one


tbodies

A collection with one entry for each tbody 0usually 4ust table"tbodies&:*1 3ach thead tbody and tfoot also has a rows collection with an entry for each row in that thead tbody or tfoot. 3ach row has a cells collection containing every td or th cell in that row. 3ach cell then contains the usual ,6. references to its contents. 3ach table also has the deleteT-ead/0 and deleteT7oot/0 methods that do e#actly what they say. 3ach thead tbody and tfoot also have the deleteNow/row5ndex0 method to delete rows. 3ach row also has thedelete'ell/cell5ndex0 method to delete cells. The cells have the cell5ndex property the row5ndex property. 0e#cept in early Uon%ueror versions1 and rows have

ing a row to a table


Internet 3#plorer on .ac has very poor support for creating table elements using the dedicated methods - as

a result this tutorial avoids those and uses normal ,6. core instead.

The ,6. provides dedicated methods for creating and adding rows but these fail in Internet 3#plorer on .ac. It is easier to 4ust use normal ,6. methods since these wor! in everything$
var theTable = doc1ment"getOlementSy5d/,table5d,0. theTable"tSodies&:*"append'hild/doc1ment"createOlement/,tr,00.

ing one cell to ever! row in a table


Internet 3#plorer on .ac has very poor support for creating table elements using the dedicated methods - as

a result this tutorial avoids those and uses normal ,6. core instead.

This e#ample adds a new cell on the end of every row in a table. It assumes that table has both a thead and a tfoot. Again there are dedicated methods for this but these fail in Internet 3#plorer on .ac so they are not used here$
var theTable = doc1ment"getOlementSy5d/,table5d,0. for/ var x = :. x < theTable"t-ead"rows"length. x%% 0 F var y = doc1ment"createOlement/,td,0. y"append'hild/doc1ment"createTextAode/,Thead cell text,00. theTable"t-ead"rows&x*"append'hild/y0. G for/ var Y = :. Y < theTable"tSodies"length. Y%% 0 F for/ var x = :. x < theTable"tSodies&Y*"rows"length. x%% 0 F var y = doc1ment"createOlement/,td,0. y"append'hild/doc1ment"createTextAode/,Tbody cell text,00. theTable"tSodies&Y*"rows&x*"append'hild/y0.

G G for/ var x = :. x < theTable"t7oot"rows"length. x%% 0 F var y = doc1ment"createOlement/,td,0. y"append'hild/doc1ment"createTextAode/,Tfoot cell text,00. theTable"t7oot"rows&x*"append'hild/y0. G

.OM

SS

8n ivi ual element st!les



I+3browser and 3scape&3vo cannot read or write the float style. "etFront :.H beta fails throws errors when setting classAame.

As described in the section on ,-T./ ,6. compatible browsers support the style ob4ect. The style ob4ect was created by .icrosoft and although only became a standard in ,6. /evel = +SS there was nothing to replace it in browsers supporting earlier ,6. implementations so it has been universally adopted by all ,6. browsers. Through the style ob4ect ,6. browsers allow all styles the element accepts to be changed not 4ust those I described in the section on ,-T./. It is e%uivalent to reading and writing the value of the styleattribute so styles can only be read if they were set using that attribute. Styles are almost all read&write. The synta# is simple. Simply write element"style"styleAame. If the style name consists of two or more words separated by hyphens '-' remove the hyphen and capitalise the first letter of the word following it. For e#ample bac!ground-color becomes bac!ground+olor. )hen setting a value it should be set as a string. 6ther data types will be converted to strings before setting the value to that string. Although most browsers will allow you to delete a style by setting it to null a browser could legitimately set it to the string value ,n1ll, and that would have an unwanted effect. If you want to delete a style set it to an empty string and never set it to null. The only odd style is float which is a reserved word in many languages including JavaScript. As a result the float style must be set using css7loat in standards compliant browsers and style7loat in Internet 3#plorer 0some standards compliant browsers also provide this as well1. Simply set both of them. It will not cause any problems and will wor! in all possible browsers.

The ):+ ,6. does provide an alternative way to change the styles on individual elements. The class attribute of the element can be removed using this$
element"classAame = ,,.

And it can be changed using$


element"classAame = ,new'lassAame,.

&ea ing applie element st!les

get'omp1tedStyle and c1rrentStyle are not supported by Safari =- Uon%ueror :.A- or T!html -v:.

)hen +SS stylesheets are applied to a page elements may be targetted by several style rules and inherit various styles from their ancestors. They will also receive some default styling from the browser's internal stylesheet. The ,6. specification offers a way to wor! out what the result of those styles was using thewindow"get'omp1tedStyle method. This is supported by 6pera IJ .o7illa i+ab :J Uon%ueror :.HJ and Safari :J. Internet 3#plorer also offers an alternative2 the c1rrentStyle property of an element. This is supported by Internet 3#plorer on )indows and .ac 6pera DJ and i+ab :.
get'omp1tedStyle re%uires two parameters. The first is a reference to the element. The second is

either the name of a pseudo element 0'before' 'after' 'first-line'1 or null 4ust for the element itself. Sincec1rrentStyle only allows you to obtain the style for the element itself that is all I will show here. In most cases the values returned by these are the same but there are a few cases where they may be different. For e#ample a table may have a width set by the +SS but may be stretched wider to fit its contents. In this case c1rrentStyle will still return the width specified by the +SS but get+omputedStyle will return the new stretched width.
var oOlement = doc1ment"getOlementSy5d/,mydiv,02 o'olor. if/ window"get'omp1tedStyle 0 F o'olor = window"get'omp1tedStyle/oOlement2n1ll0"color. G else if/ oOlement"c1rrentStyle 0 F o'olor = oOlement"c1rrentStyle"color. G

As well as being an actual usable value the returned value for several styles may be their default values such as 'auto' 'normal' or 'inherit'. The browser may also choose to return values in any available unit. For e#ample even if the +SS specifies a length in 'em' units the browser may still return the e%uivalent value in 'p#' units. In cases where c1rrentStyle gives a different result to get'omp1tedStyle Internet 3#plorer offers an alternative2 r1ntimeStyle. This is an ob4ect almost e#actly li!e c1rrentStyle but it gives a computed value instead of a cascaded value. -owever it does not always give a usable value and often gives a different !ind of result to what would be e#pected from get'omp1tedStyle if it gives any value at all. It often computes a blan! string for unspecified values instead of their default values. @se this with care and only if you are sure it gives the result you need. It is also possible to obtain some details of an element using its offset client and scroll values. These are all available as properties of the element and give its current dimensions in pi#els not the styles that apply to it. This means that they also give real dimensions even if the +SS value is 'auto'. These are not reliable for inline elements and should only be used for elements that have bloc! or e%uivalent display. "ote that these properties are not standardised but they wor! fairly reliably cross browser.
offsetMidth and offset-eight

The dimensions of the element ta!en outside its border. 0The width inside the padding in I3's %uir!s mode.1
clientMidth and client-eight

The dimensions of the element ta!en inside its border and minus any scrollbar si7e.
scrollMidth and scroll-eight

The dimensions the element would be using if it did not have a scrollbar and was not constrained in si7e 0in other words the dimensions of its contents plus its padding1. 6nly usable and reliable if the element actually has a scrollbar.
scrollReft and scrollTop

The distance the element has been scrolled.

&ewriting st!lesheets The ,6. allows the stylesheets themselves to be changed. Some browsers allow stylesheets to be modified some also allow rules to be created or removed. This will be covered in the ne#t chapter of this tutorial.

)hanging the href of a linke st!lesheet The href of the stylesheet can be read in some browsers using the href property. 6pera IJ .o7illa Uon%ueror Safari and Internet 3#plorer HJ can set the href of the lin! element using set)ttrib1te on the lin! tag the styleSheets&index*. and Internet 3#plorer AJ can also set the href of

Switching st!lesheets

This is supported correctly by I3 AJ )in I3 HJ .ac 8ec!o 0.o7illa&Firefo#&"etscape MJ1 and 6pera DJ. This is supported incorrectly by U-T./&)ebUit 0Uon%ueror :J&Safari&6mni)eb A.HJ1 and I+3browser. This is supported almost correctly by I3 A .ac. This is supported correctly using a different synta# by 6pera IJ and i+ab :. This is supported correctly using a different synta# by U-T./&)ebUit. i+ab : fails to stop applying generated content and -T./ element color from the preferred stylesheet when

it is disabled.

The stylesheet can be disabled&enabled in some browsers using the boolean disabled property but some browsers will only allow you to change the disabled property if the title attribute is set. To create the most reliable cross browser effect the function I have written 0below1 will only try to enable & disable a stylesheet if its title attribute has been set. The best use of the disabled property is to allow your readers to change the loo! of the site to suit their personal tastes or accessibility re%uirements. This re%uires them to be able to switch between the different stylesheets that you provide. .ost often this techni%ue is used along with coo!ies storing the user's preference of stylesheet as they leave the page 0via the onunload event1 and then using it again ne#t time they view the page 0using the onload event1.

Setting up the HTML To do this set out your document as follows$

Firstly if you need one create a persistent stylesheet with all global styles using this$
<lin! rel="stylesheet" type="text/css" href="all"css">

As it has no title attribute it will never be disabled. *ou do not have to define this stylesheet if you do not want to but if you do remember that all styles you define in it will be used in all stylesheet modes and will be used along with any stylesheet you later use by stylesheet switching. The default switchable 0preferred1 stylesheet is set up using this$
<lin! rel="stylesheet" type="text/css" href="defa1lt"css" title="(efa1lt">

This will also be used by browsers that cannot disable&enable stylesheets and ensures that the default view will loo! good. *ou can then set up all alternative stylesheets using this$
<lin! rel="alternate stylesheet" type="text/css" href="extraCretty"css" title="Cretty"> <lin! rel="alternate stylesheet" type="text/css" href="big7ont"css" title="Sig 7ont"> <lin! rel="alternate stylesheet" type="text/css" href="contrast"css" title="-igh 'ontrast">

'ecause these stylesheets are set up using 'alternate stylesheet' for the 'rel' attribute lesser browsers will not use these stylesheets at all and in browsers that can switch stylesheets these stylesheets will be disabled by default.

)hanging the st!lesheets with the browsers1 view menu 6pera IJ .o7illa Internet 3#plorer LJ Uon%ueror :J and i+ab :J will allow users to choose from these alternative stylesheets in the 'view' menu. -owever this setting is not remembered by the browser 0e#cept by Uon%ueror1 so the user will have to choose this for every page they view on your site. Also other 'good' browsers li!e Internet 3#plorer I- and Safari do not allow the user to choose stylesheets in any menus so you will have to use the ,6. to change them manually. "ote that when using the view menu or the ,6. techni%ue stylesheets that share the same title will be treated as if they were the same stylesheet and will be switched together.

@sing the view menu only allows you to select stylesheets whose titles are identical. If you want to enable combinations you would either have to produce combined stylesheets or include the same sheet multiple times with different titles to allow all combinations. This is also a problem with most basic stylesheet switching scripts. The script I will show you allows you to choose a combination of stylesheet titles ma!ing it superior to most other scripts.

&eferencing the st!lesheet1s isable propert! an title propert!


document3styles"eets

.icrosoft first came up with the doc1ment"styleSheets collection. The ):+ decided this was a good idea and introduced it in ,6. /evel = +SS. All stylesheets are available in this collection even if the rel attribute is set to 'alternate stylesheet'. Setting the disabled property of the collection entry disables and enables the stylesheet and the title attribute is available here as a JavaScript property.

Internet 3#plorer AJ )in and HJ .ac correctly support doc1ment"styleSheets. Internet 3#plorer A .ac supports doc1ment"styleSheets but does not provide the title Instead the title of the style or lin! element must be

attribute.

used$ doc1ment"styleSheets&:*"owningOlement"title. 8ec!o 0.o7illa&Firefo#&"etscape MJ1 correctly supports doc1ment"styleSheets. 6pera DJ correctly supports doc1ment"styleSheets. Uon%ueror and Safari PU-T./&)ebUitQ incorrectly only populate

the doc1ment"styleSheets collection with stylesheets that are enabled at any particular instant. The stylesheets cannot be disabled from here and do not have the title property.

I+3browser populates the collection and allows the stylesheet to be enabled & disabled but

only if the rel attribute is set to 'stylesheet' and not 'alternate stylesheet' - this defies the purpose of switching stylesheets and goes against the ):+'s -T./ specification so I 4ust accept that it will not handle the script correctly. I+3browser users will have to 4ust stic! to the default stylesheet attepting to change it will leave them only with the persistent stylesheet.

"etFront provides the collection but it is always empty ... 6pera I-L and i+ab : do not provide the collection at all.

'e#erencing t"e tags

The e%uivalent to doc1ment"styleSheets can be produced by referencing the relevant /I"U and ST*/3 tags. The disabled property can be read and modified and the title attribute is available. *ou will need to ma!e sure that the lin! tags are being used to import stylesheets by chec!ing their 'rel' attribute as lin! tags have many uses.

Internet 3#plorer AJ )in supports this techni%ue but until the disabled property has been set

with JavaScript it will show as false even if the 'rel' attribute is set to 'alternate stylesheet' and hence the stylesheet is disabled.

Internet 3#plorer AJ .ac correctly supports this techni%ue. 8ec!o 0"etscape MJ .o7illa etc.1 correctly supports this techni%ue. 6pera DJ correctly supports this techni%ue. Uon%ueror and Safari PU-T./&)ebUitQ support this techni%ue but until the disabled property

has been set with JavaScript it will show as false even if the 'rel' attribute is set to 'alternate stylesheet' and hence the stylesheet is disabled.

6pera I-L and i+ab :J support this techni%ue but until the disabled property has been set

with JavaScript it will show as false even if the 'rel' attribute is set to 'alternate stylesheet' and hence the stylesheet is disabled. Also changes made using the view menu will not be reflected.

I+3browser does not support this techni%ue.

*ou can see that from these points the following is re%uired$

@se the lin! and style tag techni%ue in 6pera I-L and i+ab : and ma!e sure that you do not 3ither of$
o o

try to store the user's preference until they have chosen a stylesheet. @se the lin! and style tag techni%ue in 6pera DJ. @se the document.stylesheets collection in 6pera DJ.

@se the lin! and style tag techni%ue in U-T./&)ebUit and ma!e sure that you do not try to 3ither of$
o o

store the user's preference until they have chosen a stylesheet. @se the lin! and style tag techni%ue in 8ec!o. @se the document.stylesheets collection in 8ec!o. @se the lin! and style tag techni%ue in I3 using document.all.tags to reference them

3ither of$
o

in I3 A and ma!e sure that you do not try to store the user's preference until they have chosen a stylesheet.
o

@se the document.stylesheets collection in I3 as this ma!es it easier to include I3 A

as well - ma!e sure you use the title from the owning3lement if the title is not immediately available.

@se the document.stylesheets collection in I+3browser but only bother if you are not using

alternate stylesheets. The ):+ says the correct method is to use the styleSheets collection but since that would only wor! in three browsers and cause problems for others I will use the lin! and style tag techni%ue. I

will add support for I+3browser 4ust in case they ever fi# its handling or in case you only want to switch preferred stylesheets. The best way to chec! if the user has used the view menu is to chec! what stylesheets are enabled onload and onunload. If they are different the user has chosen something from their view menu 0this is not possible in 6pera I-L as the disabled property does not reflect changes made in the view menu1. 6f course you should also chec! if the changeStyle function has been run by ma!ing it store a variable to say so. *ou may want to use the correct techni%ue but if you do you will still need to do the lin! and style tag techni%ue for 6pera I-L and i+ab 0using if/#doc1ment"styleSheets0 etc.1 and you will need to do a browser detect to ma!e U-T./&)ebUit use the lin! and style tag techni%ue and you will still need to ma!e sure you do not store the preference in U-T./&)ebUit i+ab and 6pera I-L until the user has chosen and you will need to compensate for the lac! of title in I3 A .ac.

The script "ote because getOlementsSyTagAame returns and not a true an collection ob4ect we cannot with use

element ,index, and ,length, properties

the array"concat method to append the 'arrays' of lin! tags and style tags. Instead we must cycle through the collections and add each element in turn.
f1nction get)llSheets/0 F //if yo1 want 5'Obrowser,s limited s1pport2 do it this way if/ #window"ScriptOngine PP navigator"33ice3version 0 F //5O errors if it sees navigator"33ice3version when a window is closing //window"ScriptOngine hides it from that ret1rn doc1ment"styleSheets. G if/ doc1ment"getOlementsSyTagAame 0 F //(8H browsers $ get lin! and style tags var Rt = doc1ment"getOlementsSyTagAame/,lin!,0. var St = doc1ment"getOlementsSyTagAame/,style,0. G else if/ doc1ment"styleSheets PP doc1ment"all 0 F

//not all browsers that s1pply doc1ment"all s1pply doc1ment"all"tags //b1t those that do and can switch stylesheets will also provide //doc1ment"styleSheets /chec!ing for doc1ment"all"tags prod1ces errors //in 5O &M-KT#*2 even tho1gh it does act1ally s1pport it0 var Rt = doc1ment"all"tags/,R5AZ,02 St = doc1ment"all"tags/,STKRO,0. G else F ret1rn &*. G //lesser browser $ ret1rn a blan! array //for all lin! tags """ for/ var x = :2 os = &*. Rt&x*. x%% 0 F //chec! for the rel attrib1te to see if it contains ,style, if/ Rt&x*"rel 0 F var rel = Rt&x*"rel. G else if/ Rt&x*"get)ttrib1te 0 F var rel = Rt&x*"get)ttrib1te/,rel,0. G else F var rel = ,,. G if/ typeof/ rel 0 == ,string, PP rel"toRower'ase/0"index8f/,style,0 % 9 0 F //fill os with lin!ed stylesheets os&os"length* = Rt&x*. G G //incl1de all style tags too and ret1rn the array for/ var x = :. St&x*. x%% 0 F os&os"length* = St&x*. G ret1rn os. G f1nction changeStyle/0 F for/ var x = :2 ss = get)llSheets/0. ss&x*. x%% 0 F //for each stylesheet """ if/ ss&x*"title 0 F //disable the stylesheet if it is switchable

ss&x*"disabled = tr1e. G for/ var y = :. y < arg1ments"length. y%% 0 F //chec! each title """ if/ ss&x*"title == arg1ments&y* 0 F //and re$enable the stylesheet if it has a chosen title ss&x*"disabled = false. G G G if/ #ss"length 0 F alert/ ,Ko1r browser cannot change stylesheets, 0. G G

"""

eg" <body onload="changeStyle/,-igh 'ontrast,2,Sig 7ont,0.">

;educed that becomes this$


f1nction get)llSheets/0 F if/ #window"ScriptOngine PP navigator"33ice3version 0 F ret1rn doc1ment"styleSheets. G if/ doc1ment"getOlementsSyTagAame 0 F var Rt = doc1ment"getOlementsSyTagAame/,lin!,02 St = doc1ment"getOlementsSyTagAame/,style,0. G else if/ doc1ment"styleSheets PP doc1ment"all 0 F var Rt = doc1ment"all"tags/,R5AZ,02 St = doc1ment"all"tags/,STKRO,0. G else F ret1rn &*. G for/ var x = :2 os = &*. Rt&x*. x%% 0 F

var rel = Rt&x*"rel T Rt&x*"rel 6 Rt&x*"get)ttrib1te T Rt&x*"get)ttrib1te/,rel,0 6 ,,. if/ typeof/ rel 0 == ,string, PP rel"toRower'ase/0"index8f/,style,0 % 9 0 F os&os"length* = Rt&x*. G G for/ var x = :. St&x*. x%% 0 F os&os"length* = St&x*. G ret1rn os. G f1nction changeStyle/0 F for/ var x = :2 ss = get)llSheets/0. ss&x*. x%% 0 F if/ ss&x*"title 0 F ss&x*"disabled = tr1e. G for/ var y = :. y < arg1ments"length. y%% 0 F if/ ss&x*"title == arg1ments&y* 0 F ss&x*"disabled = false. G G G G

Test it using the stylesheet switcher demo page. See my stylesheet switching header file for a wor!ing e#ample that can store the user's choice of stylesheet even if they use the view menu in 8ec!o.
.OM Style S"eets

,6. Style Sheets allow you to step through the rules of each stylesheet change the selectors read and write styles and add new rules. This allows you to create or change +SS that affects several elements at the same time instead of 4ust one element as with traditional ,-T./. It allows you to ta!e advantage of +SS selectors to target the desired elements and enter rules into the +SS cascade. +urrently this is supported according to the ,6. standard by 6pera DJ and .o7illa&Firefo#. It is partially supported by Safari Uon%ueror and I+3browser but their support is so bad it is largely unusable. I will give details of what fails in these browsers for each operation. Supposedly you can use the hasFeature method to chec! if a browser supports ,6. = Style Sheets well enough but unfortunately Safari and I+3browser return true for the StyleSheets and +SS features. Their support is so poor that this is an insult to the spec. I suggest you ignore Safari Uon%ueror and I+3browser for now and hope that their support improves in the future. If you need compatibility with Safari Uon%ueror I+3browser or any browser that does not support ,6. Style Sheets 0li!e i+ab or 6pera L or below1 then you should ensure that your script does not

re%uredoc1ment"styleSheets to be supported and that if it uses it it does not produce errors when something fails in one of these browsers. Internet 3#plorer does not comply with the standard here so if you are testing use a browser that supports the standard correctly such as 6pera DJ or .o7illa. I will give details later on how to get support for Internet 3#plorer as well. Internet 3#plorer on .ac supports large parts of the Internet 3#plorer model but it also provides the cssN1les collection even though it does not use it according to the spec. I recommend you ignore I3 .ac for now and I will include it in the Internet 3#plorer section later on in this chapter. ,6. stylesheets does not provide an e#act copy of what you put in your stylesheet. It produces what the browser sees and what it interprets. ;ules that it does not understand are not included whitespace may be added or removed combined styles may be split into their components and split styles may be combined. Styles that are not understood will be ignored. +omments will not be included. ,o not e#pect to be able to recognise your own stylesheet. "ote that you should not try using ,6. = Style Sheets until you are certain that the stylesheet has completed loading 0typically this means waiting for the document's onload event to fire1. If you attempt to access it before then the cssN1les collection may be too short or may not e#ist.

The st!leSheets list

null. .o7illa gives ST*/3 element stylesheets the address of the current page as their href property instead of 6pera D.=- does not provide the href property for stylesheets added using 9./ processing instructions Safari and Uon%ueror only populate the list with stylesheets that are enabled at the specific time meaning

and they cannot be disabled. that if you use alternate stylesheets most of them will be missing from the list. Safari =- and Uon%ueror do not provide the title property and they do not let you modify the disabled property.

Safari :- Uon%ueror and I+3browser do not include stylesheets added using 9./ processing instructions Safari and Uon%ueror will populate the list with stylesheets that are added to the S8(K with ,6. but these I+3browser only populates the list with persistent&preferred stylesheets meaning that if you use alternate I+3browser does not add dynamically generated stylesheets into the collection. "etFront provides the collection but it is always empty.

0I+3browser does not understand 9./1. will have no styling effects on the document 0stylesheets are only allowed in the document -O)(1. stylesheets they will be missing from the list.

All stylesheets are available through the doc1ment"styleSheets collection. This includes stylesheets added using <style> and <lin!> tags including persistent preferred and alternate

stylesheets no matter if they are enabled or not. 3ven stylesheets added using style sheet processing instructions in 9./ based documents should be included. They are available in the collection in the order that they appear in the document source. Imported stylesheets are not included in the list 0as they are included through their parent stylesheet1 and will be dealt with later. The collection does not include the contents of <div style="etc">attributes2 they must be accessed through the style property of the element 0see the section on ,-T./ for more details1. This provides an easy way to chec! if a browser supports some amount of ,6. Style Sheets by chec!ing for the e#istence of the doc1ment"styleSheets collection$
if/ doc1ment"styleSheets 0 F //(8H stylesheets are available G

3ach stylesheet has a number of properties that give details of the stylesheet such as its @;/ 0href1 its title 0title1 its type 0type usually ,text/css,1 the media types it applies to 0media1 and if it is disabled or not 0disabled1. The disabled property can be set to tr1e or false to disable or enable the stylesheet but the other properties are all read-only. The properties will only be available if they actually apply to the stylesheet in %uestion. For e#ample if a lin! element does not have the title attribute set then its associated StyleSheet ob4ect will not have a title. Test it here$ see the properties of the first stylesheet in this document.

&elationships between the St!leSheet ob"ect an the HTML tags that create them

Safari =- and Uon%ueror do not provide the sheet property for lin!ed stylesheets. I+3browser does not provide the sheet property for any stylesheets.

If you have a reference to the /I"U or ST*/3 element you can reference the associated StyleSheet ob4ect using the sheet property of the element.
var theSheet = doc1ment"getOlementsSyTagAame/,style,0&:*"sheet.

Similarly if you have a reference to the StyleSheet ob4ect you can reference the associated /I"U or ST*/3 element by using the ownerAode property of the StyleSheet ob4ect.

var theOlement = doc1ment"styleSheets&:*"ownerAode.

Test it here$ chec! for these properties.

St!lesheet me ia

Safari =- and Uon%ueror sometimes put an e#tra comma on the end of the mediaText 0ma!ing it invalid1. Safari :- Uon%ueror and I+3browser do not allow media types to be added or removed. I+3browser ignores media attributes and treats mediaText as a blan! string.

The media property of the stylesheet references a .edia/ist ob4ect. This allows adding and removing of media types. It has a property mediaText that gives the full contents of the /I"U or ST*/3 element's mediaattribute. "ote that browsers are free to add or remove spaces as they decide is appropriate. They may also remove any media types they do not understand or may rename them 0typically to 'un!nown'1. If the te#t contains the same media type more than once the browser may remove the e#tra copies. It is possible to set this te#t to a new string if desired$
doc1ment"styleSheets&:*"media"mediaText = ,print2handheld,.

.odifying the media types that the stylesheet applies to is mostly useful if the browser supports multiple media types. 6f the browsers that support ,6. stylesheets only 6pera supports more than 4ust screen and print 06pera also supports pro4ection handheld speech and on some devices tv1. This means that currently this feature is most useful in 6pera but can also be useful in other browsers if you wish to change between 'all' 'screen' and 'print'. "ote that the browser may support media %ueries and the specification never too! these into account. +urrently this affects 6pera. 6pera normali7es media %ueries 0removing spaces and reformatting1 to ma!e sure that only one copy of each e%uivalent %uery 0with parameters in the same order1 e#ists. If you set the mediaTe#t to a value containing media types the browser does not recognise it will allow that and simply ignore un!nown media types. Setting the media te#t to a value that the browser does not recognise as valid synta# will throw an error so browsers that do not understand media %ueries will not allow you to set mediaTe#t containing a media %uery. *ou will need to use a try"""catch statement around the assignment. The media ob4ect also provides the appendHedi1m method to allow you to append one media type at a time and the deleteHedi1m method to delete one at a time. ,eleting a medium that is not in the list or that the browser does not understand will cause it to throw an error. "ote that a

stylesheet with no media is applied to all media types. Adding a medium to a stylesheet that has no specified media will cause it to be applied only to that media type. ,eleting all media types from the list will cause the media te#t to be empty so it will be applied to all media types.
doc1ment"styleSheets&:*"media"appendHedi1m/,handheld,0. doc1ment"styleSheets&:*"media"deleteHedi1m/,print,0.

*ou can also step through all the listed media types using the item method and chec! how many are in the list by chec!ing the length parameter.
for/ var i = :. i < doc1ment"styleSheets&:*"media"length. i%% 0 F alert/doc1ment"styleSheets&:*"media"item&i*0. G

Test it here$

Append the print media type to all stylesheets on this page. The page should appear to have lost all its styling information. *ou can then test if it wor!ed by using your browser's print preview feature. If you are using 6pera you can also append the handheld media type to all stylesheets on +hec! what media types the first stylesheet is using. *ou can then delete the print media type and delete the handheld media type.

this page and test it using (iew - Small screen.

St!lesheet css&ules collection



.o7illa does not provide this collection for alternate stylesheets that do not have a title attribute. Safari =- and Uon%ueror cannot add or remove rules. Safari Uon%ueror and I+3browser ignore some K rules that they do understand such as Echarset rules. I+3browser cannot add rules.

Stylesheets all have the cssN1les collection that contains all the rules of the stylesheet. This only includes rules that are in the root of the stylesheet and not for e#ample in a Emedia bloc! 0these will be dealt with later1. 'rowsers may choose not to include K rules that they do not recognise 0initially the spec said to include them but the authors of the spec have now said not to1. They will not

include any rules that they do not understand such as rules using a selector that they do not recognise as being in a valid format. This means that the cssN1les collection will almost certainly be a different length in different browsers and you cannot rely on it being a certain si7e if you use features that are not supported by all the browsers. "ote that although most browsers understand Enamespace rules they are not part of the specification. 6nly .o7illa adds these to the cssN1les collection as an un!nown rule. ;ules can be added to the collection using the insertN1le method of the stylesheet specifying the te#t to interpret as a new rule and the inde# specifying the rule number that the new rule should be added before. To add a rule at the end the inde# should be the number of rules currently in the stylesheet. ;ules can be removed using the deleteN1le method of the stylesheet specifying the inde# of the rule to remove. As always the inde# starts at G for the first rule.
doc1ment"styleSheets&:*"deleteN1le/90. //delete the second r1le doc1ment"styleSheets&:*"insertN1le/,html F color6 lime. G,2:0. //add a new r1le at the start var oRength = doc1ment"styleSheets&:*"cssN1les"length. doc1ment"styleSheets&:*"insertN1le/,body F bac!gro1nd6 W==U. G,2oRength0. //add a new r1le at the end var oN1le = doc1ment"styleSheets&:*"cssN1les&oRength*. //reference the new r1le we j1st added

This part of ,6. = Style Sheets is one of the most useful and important. Since adding and removing rules is not supported by Safari =- and Uon%ueror and only removing rules is supported by I+3browser they are generally useless for ,6. = Style Sheets. Test it here$ add the new rule ,p F color6 lime. G, and then delete it again. For security reasons 6pera and .o7illa will not allow you to access the css;ules collection of a stylesheet from another domain or protocol. Attempting to access it will throw a security violation error. If your script is li!ely to encounter a stylesheet li!e this you should use a try"""catch structure to prevent your script from halting.

The )SS rule



.o7illa Safari Uon%ueror and I+3browser cannot rewrite rules using cssText. Setting rule cssText will cause 6pera D-D.= to apply the old version of the rule as well as the new one.

Safari =- and Uon%ueror do not provide cssText for the +SS rule ob4ect. Safari =- Uon%ueror and I+3browser remove any namespace prefi# from the selector part of the rule Safari =- and I+3browser ma!e the selector part of the rule upper case so it is not valid for 9./ based Safari =- corrupts I, attribute and class selectors beyond recognition ma!ing them invalid and useless. I+3browser adds wildcards to the selector part of the rule where wildcards are assumed. I+3browser changes class selectors to &class[=attrib1te* selectors. The selector part of the rule only includes everything upto the first comma in I+3browser.

meaning that it appears to target elements that it does not. documents.

This is the most fundamental part of ,6. = Style Sheets2 viewing or changing the styles of each rule. 3ach entry in the stylesheet's cssN1les ob4ect is a +SS rule. There are several types of rule that may e#ist in a stylesheet and the properties they provide will depend on what type of rule they are. 3ach rule has a type property saying what type of rule it is. This will be < for normal style rules = forEcharset rules : for Eimport rules A for Emedia rules H for Efont$face rules and M for Epage rules. If the browser does not ignore un!nown K rules their type will be G. +SS rules will also have theparentStyleSheet property which is a reference to the stylesheet they are inside. Typically you would need to use the type property to wor! out what other properties you will be able to access. The rule also has a cssText property that gives a te#t representation of the rule. This may have whitespace added or removed and styles may be split or combined into component styles. .ultiple copies of the same style may be replaced with a single copy of the one that is actually used. In most cases it no longer loo!s li!e the rule that was in the original stylesheet but it should have the same effect in that browser 0though not necessarily in other browsers1 as the original rule.
var theN1le = doc1ment"styleSheets&:*"cssN1les&:*. alert/,Type6 ,%theN1le"type%,LnN1le6 ,%theN1le"cssText0.

Test it here$ alert the first rule in the first stylesheet of this page. In theory it is possible to set the cssText to a new value as long as the new value can be interpreted as the same type of rule as the original rule 0so it is not possible to convert a Eimport rule into a Emedia rule for e#ample1. @nfortunately browser support is not good enough to use this at the moment.
doc1ment"styleSheets&:*"cssN1les&:*"cssText = ,body F bac!gro1nd6 W==U. G,.

If the rule is a Echarset rule it will have an encoding property giving the encoding string which can be rewritten if desired. @n!nown K rules will have no other properties. All other rule types will be covered below$

Normal st!le# >page# an >font2face rules



.o7illa does not allow setting of rule selectorText. .o7illa splits some valid styles 0such as ,padding,1 into several invalid styles 0such as ,padding$left$ .o7illa adds a strange , Q, namespace prefi# to element selectors but only if there is at least

val1e, and,padding$left$ltr$so1rce6 physical.,1.

one Eimport rule in one of the document's stylesheets and if there are at least two /I"U elements in the document 0at least one of which must be a stylesheet1.

Safari =- corrupts I, attribute and class selectors in the selectorText beyond recognition ma!ing it Safari =- always returns null when using the item method on a rule. Safari =- and Uon%ueror cannot add remove or change styles from a rule using the methods of the style Safari =- Uon%ueror and I+3browser cannot rewrite rules using style"cssText. Safari =- Uon%ueror and I+3browser remove any namespace prefi# from the selectorText meaning that Safari =- and I+3browser ma!e selectorText upper case so it is not valid for 9./ based documents. I+3browser cannot change rule styles using "style"color synta#. selectorText only includes everything upto the first comma in I+3browser. I+3browser adds wildcards to the selectorText where wildcards are assumed. I+3browser changes class selectors to &class[=attrib1te* selectors. I+3browser cannot retrieve values of short form styles li!e ,margin, and can only retrieve values for the I+3browser returns all pi#el values with a decimal point ,:":px,. I+3browser ignores priorities when setting styles.

invalid and useless.

ob4ect.

it appears to target elements that it does not.

e#panded form,margin$left,.

These are the most common rule types and the ma4ority of stylesheets contain only normal style rules. The normal style rule and the Epage rule have the selectorText property which gives the selector te#t for the rule. This may have whitespace added or removed. In theory this can be rewritten if desired but unfortunately browser support is not good enough to use this at the moment.
doc1ment"styleSheets&:*"cssN1les&=*"selectorText = ,div > p,.

All three rule types also have a style property. This is the same in functionality as the style property of elements that is normally used for ,-T./. -owever browsers that support ,6. = Style Sheets usually implement more of the less well !nown methods associated with

the style ob4ect. As well as the usual"style"color synta# that is well !nown 0and even wor!s in Safari and Uon%ueror1 there are several other ways to access and modify the styles of the rule$ The cssText property gives the te#t representation of all the styles that the rule contains. This may be reformatted with altered whitespace may or may not have a final semicolon and styles may or may not be split or combined. It is possible to set this to a new value replacing all the original styles with a new set of styles.
doc1ment"styleSheets&:*"cssN1les&=*"style"cssText = ,color6 lime. font$weight6 bold.,.

The length property can be used to find how many styles the browser sees and the item method can be used to retrieve the style names one at a time. The getCroperty+al1e method retrieves the value of a named style. The getCropertyCriority method retrieves the priority of a named style 0typically 'important'1. The removeCroperty method removes a named style 0it will do nothing if the style is not being used1. /astly the setCroperty method creates or rewrites a style. It re%uires three parameters2 the style name the value and the priority.
var oStyle = doc1ment"styleSheets&:*"cssN1les&:*"style. oStyle"setCroperty/,color,2,lime,2,,0. oStyle"setCroperty/,font$weight,2,bold,2,important,0. for/ var i = :2 j2 s = ,,. i < oStyle"length. i%% 0 F j = oStyle"item/i0. s %= j % , = ,%oStyle"getCroperty+al1e/j0%, ,%oStyle"getCropertyCriority/j0%,Ln,. G alert/s0. oStyle"removeCroperty/,color,0. oStyle"removeCroperty/,font$weight,0. alert/,Aew content6 ,%oStyle"cssText0.

Test it here$ the last rule in the demo stylesheet is currently ,p F G,. Try running the script shown above on it.

>import rules an importe st!lesheets

it. Eimport rules are similar to a -T./ /I"U element in that they reference a new stylesheet. They Safari Uon%ueror and I+3browser actually get this one right. I felt it an important enough event to mention

have some e#tra properties that reflect that role. The href property gives the @;/ referred to by the import rule. This may be a complete address 0typically beginning with 'http$&&'1 or may be the e#act @;/ given by the Eimport rule 0such as 'imported.css'1 - this will depend on the browser.
Eimport rules can contain a list of media types as well although this feature is not very often used.

As a result

the rule ob4ect also has the media property

which behaves e#actly li!e

the media property of the StyleSheet. .ost importantly the rule ob4ect also has the styleSheet ob4ect. This references the StyleSheet ob4ect for the imported stylesheet and its rules can be referenced and modified in e#actly the same way as a normal stylesheet. The imported stylesheet also has the ownerN1le property that references the Kimport rule that imports it.
alert/doc1ment"styleSheets&:*"cssN1les&:*"styleSheet"cssN1les&:*"cssText0.

>me ia blocks

Safari and Uon%ueror do not provide the parentN1le property for rules in a Kmedia bloc!. I+3browser does not understand media %ueries but interprets them as a media bloc! with their to!ens

treated as separate media types. Emedia bloc!s allow you to target a selection of style rules to a specific set of media types.

The Emedia rule appears as a single rule in the stylesheet's cssN1les collection. The style rules inside it do not appear in the stylesheet's cssN1les collection at all. Instead the rule has its own cssN1les collection that contains all the styles within it. This collection behaves in e#actly the same way as the cssN1les collection for the StyleSheet ob4ect. The Emedia rule also has the insertN1le and deleteN1le methods which behave in the same way as those for the StyleSheet ob4ect. As the Emedia rule also has a list of media types it also has the mediaproperty which also functions li!e that of the StyleSheet ob4ect. All rules inside the Emedia bloc! also have the parentN1le property which references

the Emedia rule that they are inside. Emedia bloc!s may contain other Emedia bloc!s and these can

be nested as much as needed. If they are nested their rules must be accessed by going through the chain of cssN1les collections.
alert/doc1ment"styleSheets&:*"cssN1les&:*"cssN1les&:*"cssText0.

Test it here$ show the contents of the last recognised media bloc! in the first stylesheet.

+etting support for 8nternet 7xplorer Internet 3#plorer on )indows and .ac does not provide many of the ,6. = Style Sheets methods or properties but it has an alternative that is not as complete as the standard but can handle basic stylesheet manipulation. If you need Internet 3#plorer support you will have to accept the differences and limitations ma!e sure your code does not rely on the parts that Internet 3#plorer is missing and implement the branching code I will show you here.

The st!leSheets list



Internet 3#plorer on .ac does not populate the list with stylesheets that are added using ,6. after the The media property is read-only in Internet 3#plorer on .ac. Setting media to ,print, followed by ,, causes Internet 3#plorer on )indows to start using print media page has loaded.

instead of screen media for normal )eb page viewing.

Internet 3#plorer provides the same collection as the other browsers and to a large e#tent it wor!s the same way. The type disabled href and title properties all wor! the same way. The media property is different. Instead of being a media ob4ect it is a string. As a result there are no methods to add remove or list media types. If you want to change it you will need to treat it as a string. Trying to set it will throw an error in I3 .ac so it will need a try"""catch statement.
var oSheet = doc1ment"styleSheets&:*. if/ typeof/oSheet"media0 == ,string, 0 F try F oSheet"media = ,screen,. G catch/e0 FG G else F oSheet"media"mediaText = ,screen,.

Test it here$ set the media type on all stylesheets on this page to ,print, 0the page should appear unstyled when viewed normally1 use print preview to chec! if it wor!ed then return it to normal. 3ach stylesheet can reference the element that creates it using owningOlement in the same way as standards compliant browsers use ownerAode.
var oSheet = doc1ment"styleSheets&:*. var oOlement = oSheet"ownerAode T oSheet"ownerAode 6 oSheet"owningOlement.

Although I3 on )indows provides the styleSheet property of the /I"U or ST*/3 element in the same way as standards compliant browsers use sheet this property is not available in I3 on .ac.
var oOlement = doc1ment"getOlementsSyTagAame/,style,0&:*. var oSheet = oOlement"sheet T oOlement"sheet 6 oOlement"styleSheet.

Test it here$ chec! for these properties.

St!lesheet css&ules collection

Internet 3#plorer on .ac cannot add or remove rules.

Internet 3#plorer provides the r1les collection in the same way as standards compliant browsers usecssN1les. -owever its behaviour is sufficiently different and incompatible so it is not possible to simply inde# the same rule in each collection. Epage Emedia Eimport Echarset and Efont$
face rules are not included in the collection. In I3 on )indows all rules inside a Emedia bloc! are

included in the r1lescollection of the stylesheet. In I3 .ac they are ignored completely and are not available to the ,6.. In both browsers it is not possible to modify the Emedia rule itself. Adding new rules into a Emedia bloc! is not possible in I3 on )indows. "ote that the stylesheet itself has a cssText property in I3 which gives all the +SS in the stylesheet. 6n )indows this includes any Emedia bloc!s. -owever it is not much fun to edit the stylesheet using pattern matching which is all that this can provide.

I3 on .ac provides both the r1les and cssN1les collections but treats them both the I3 way 0so thecssN1les collection is too short1. For this reason it is important to chec! for the r1les collection first and use that if it is available then use the standard cssN1les collection if not.
var oSheet = doc1ment"styleSheets&:*. var oN1le = oSheet"r1les T oSheet"r1les&;* 6 oSheet"cssN1les&=*.

Adding

and

removing

rules

in

Internet of

3#plorer that

0on the

)indows1 inde# will

is

done be

using

the addN1le and removeN1lemethods. The removeN1le method is e#actly the same as the standard deleteN1le method 0e#cept course different1. The addN1le method however is very different to the standard insertN1le method. Firstly it re%uires two different parameters2 the selector string and the rule string. Secondly it can only add a rule at the end of the stylesheet.
var oSheet = doc1ment"styleSheets&:*. if/ oSheet"deleteN1le 0 F oSheet"deleteN1le/=0. G else if/ oSheet"removeN1le 0 F oSheet"removeN1le/;0. G if/ oSheet"insertN1le 0 F oSheet"insertN1le/,body F bac!gro1nd6 W==U. G,2oSheet"cssN1les"length0. G else if/ oSheet"addN1le 0 F oSheet"addN1le/,body,2,bac!gro1nd6 W==U.,0. G

Test it here$ add the new rule ,p F color6 lime. G, and then delete it again.

The )SS rule



selectorText only includes everything upto the first comma in I3. selectorText adds wildcards for selectors where wildcards are assumed in I3.

cssText contains the FG braces in I3 mac 0it also includes them for Olement"style"cssText1. The style"item/:0 method returns ,G, in I3 mac if the rule does not have any styles that it recognises. 3lements and style names in selectorText and cssText are upper case in I3 0meaning that they are not selectorText is read-only in I3 .ac.

valid for 9./ based documents1.

Since the r1les collection only contains normal style rules the rules do not have a type property. In I3 on )indows they also do not have cssText. They do have a selectorText property though and 0apart from a few bugs1 it behaves e#actly the same as with standards compliant browsers. Similarly they also have theparentStyleSheet property. They also have the all important style property. -owever here there are some significant differences. Theitem method does not e#ist in I3 on )indows. *ou can try using for/i in
styleobject0 but that does not return what you specify in the stylesheet. Instead it steps through all

possible styles that I3 recognises whether you actually used them or not. It is actually a fairly short list 0since I3 does not actually support very many styles1 but it ma!es recognising your own styles very hard. .ore importantly however I3 does not provide most of the other methods of the style ob4ect. To read or change styles you will have to stic! to the "style"color synta#. Since this wor!s in all browsers that is not too difficult to wor! with. "ote that I3 will throw errors if you set styles to values that it does not support 0such as setting display to ,table,1. "ote that the "style"cssText property is available but I3 .ac ma!es a bit of a mess of it.
var oSheet = doc1ment"styleSheets&:*. var oN1le = oSheet"r1les T oSheet"r1les&;* 6 oSheet"cssN1les&=*. oN1le"style"color = ,lime,.

Test it here$ the last rule in the demo stylesheet is currently ,p F G,. Set its color property to ,lime, then set it bac! to ,,. There is also a StyleSheet"pages collection that gives all Epage rules but it does not give any useful information about the styles in that rule.

>import rules an importe st!lesheets


Eimport rules are listed in their own StyleSheet"imports collection in I3. 3ach entry in this

collection is a StyleSheet ob4ect that is the same as the styleSheet property of the Eimport rule in standards compliant browsers. It has the same properties as a normal stylesheet.
var oSheet = doc1ment"styleSheets&:*2 o5mportedSheet. if/ oSheet"imports 0 F o5mportedSheet = oSheet"imports&:*. G else F o5mportedSheet = oSheet"cssN1les&:*"styleSheet. G

.OM events

This is currently supported by 6pera IJ .o7illa&Firefo# Uon%ueror :.GJ Safari and "etFront :.:J. It is also partially supported by i+ab : I+3'rowser HJ and T!html -v:. 3spial claim that 3scape&3vo H supports this but it does not support even the basics. "ote$ Internet 3#plorer on )indows does not comply with the standard here so if you are testing use a browser that supports the standard correctly such as 6pera. I will give details later on how to get support for Internet 3#plorer on )indows as well. Internet 3#plorer on .ac does not support either the ,6. or I3 events models.

0roblems with the tra itional event mo els Traditionally browsers had a simple way to listen for events and run scripts when that happened. The script could be held inside an appropriate event handler attribute such as onclic!="alert/,here,0.". Internally function that a script could override$
referenceToOlement"onclic! = f1nction /0 F alert/,here,0. G.

the browser would register this as an anonymous

;eturning false from any event handler function would prevent the normal action from happening such as preventing the browser following a lin! when it detected the clic! event.

In many basic applications this was ade%uate. -owever it has limits. If an event handler already e#ists and you want to add functionality to it part way through your script you would have to rewrite the function with both the new and old functionality. Then if you wanted to remove some functionality you would have to rewrite it again. *ou might even have to write your own handler function management system with one event handler that runs the appropriate functions in turn. Another problem with the traditional model was that it never coped well with the possibility that two elements may detect the same event. Imagine that a lin! is inside a div and both the lin! and the div are set up to detect the clic! event. )hen you clic! the lin! should the lin! see the clic!T 6r should the div see itT 6r should bothT If both should detect it in what order should they see it2 div first or lin! firstT Initially when "etscape introduced events their answer was simple2 the lin! should see it. "othing more. /ater they allowed the div to see it as well but only if you told it to capture the event. The div would then see the clic! and after that the lin! would see it 0in "etscape's original implementation the event would only be seen by the lin! if you e#plicitly told it to continue after the initial capture this is not necessary in ,6. = events1. At the same time Internet 3#plorer introduced an alternative version. 'y default both the lin! and the div would see the clic! and unli!e in "etscape the lin! would see it first. This was called bubbling.

ing D*M event listeners


I+3browser sometimes fails to detect the page's load event. I+3browser will forget to remove listeners if you reload so the effect is cumulative. T!html -v: versions before September =GGI fire events only in the bubbling order but fire both the bubbling

and capturing listeners 0in that order1.

The ,6. = events module was designed to cope with all possibilities so not only could you add multiple event handlers to a single event but you could also say in what order they should see the event. The ,6. refers to these event handler functions as event listeners. The way to add an event listener is li!e this$
referenceToOlement"addOventRistener/,name8fOvent,2referenceTo71nction2phase0

*ou can add as many listeners for the same event on the same element as you want but note that there is no way to guarantee in what order they will be run. 0Trying to add the same event function and phase to the same element multiple times will result in it being added 4ust once.1 "ote that unli!e with the traditional events models it is not possible to obtain a reference to the event handler

functions 0this could previously done withreferenceToElement.one"entname but ,6. = events does not provide any e%uivalent to list all the event handlers1. The name of the event is written li!e this$ )clic$) )mouseo"er) or )$eyup). The referenced function will be run in much the same way as with the traditional model. According to the spec the)referenceTo%unction) parameter should actually be a reference to an ob4ect that has a method called)handleE"ent) and that method will be called instead. -owever in practice 6pera LJ .o7illa&Firefo# Uon%ueror :.=J Safari and i+ab implement this correctly but the others do not. Aditionally most authors are not even aware that this functionality e#ists. In most cases it is easiest to 4ust use a direct function reference. The phase says in what order the event should be detected. False means the bubbling phase and is usually the one you want to use. True means the capturing phase. Any event handlers added using the traditional techni%ues are treated as a bubbling event listener. The phase is actually very important to get right since its behaviour is not straightforward. +apturing is special. According to the specification if an element is set up to capture a clic! event 0for e#ample1 and you clic! it the event handler should not be run. It should only be run if you clic! on a child element inside the element. In other words the capture phase is only used on ancestors of the target element. In our earlier lin! and div e#ample assume that both elements are set up to detect the clic! event using both the capturing and bubbling phase. If you clic! the lin! the specification says that the event listeners should be run in this order$ <. +apture listeners for the div =. 'ubbling listeners for the lin! :. 'ubbling listeners for the div This progression from listener to listener is !nown as propagation. *ou can chec! what stage the propagation is at by chec!ing the e"ent*b+ect.e"ent,hase property. It should be < during the capture phase = during the bubble phase on the target element itself 0in this case the lin!1 and : during the bubbling phase on the target's ancestors. It can also be G if it is a manually created event ob4ect that has not yet been fired. See below for further details. "ote that some events 0such as the load event1 do not bubble up to ancestors but they will still capture so capture phase listeners will always see the events of their children 0with load events detected in the capture phase on the document this means they should see an event every time any image plugin or many other embedded file types load1. Also note that in the above e#ample only 6pera D.=- Safari <.<- "etFront and I+3'rowser follow the specification. .o7illa&Firefo# 6pera D.HJ Uon%ueror Safari <.=J and i+ab will fire the capture

listeners on the lin!. .o7illa <.I-&Firefo# <.G will fire it before point :. 6pera D.HJ Uon%ueror Safari i+ab and .o7illa <.LJ&Firefo# <.HJ before point = giving this 0commonly supported1 event propagation$ <. +apture listeners for the div =. +apture listeners for the lin! :. 'ubbling listeners for the lin! A. 'ubbling listeners for the div That behaviour is wrong according to ,6. = 3vents but it is relied on by many )eb pages so it it unli!ely that the browsers will follow the ,6. = 3vents specification. It may be changed to be correct in ,6. : 0though it currently is not1 in which case the other browsers can be e#pected to implement it that way as well. -owever you should be aware that browsers may behave either way. ,o not rely on capturing phase firing on the target since it is currently incompatible and may well be changed at some point. So now to put this e#ample into practice$
<div id="thediv"><a href="/" id="thelin!">test</a></div> """ var o(iv = doc1ment"getOlementSy5d/,thediv,0. var oRin! = doc1ment"getOlementSy5d/,thelin!,0. o(iv"addOventRistener/,clic!,2f1nction /e0 F alert/,9" (iv capt1re ran,0. G2tr1e0. o(iv"addOventRistener/,clic!,2f1nction /e0 F alert/,;" (iv b1bble ran,0. G2false0. oRin!"addOventRistener/,clic!,2f1nction /e0 F alert/,Rin! capt1re ran $ browser does not follow the specification,0. G2tr1e0. oRin!"addOventRistener/,clic!,2f1nction /e0 F

alert/,4" Rin! b1bble ran /first listener0,0. G2false0. oRin!"addOventRistener/,clic!,2f1nction /e0 F alert/,4" Rin! b1bble ran /second listener0,0. G2false0.

Test it here$ clic! this lin! to activate the event listeners. "ote that some browsers will run the first lin! bubble listener before the second and some will run the second before the first - the standard does not say in which order they should be run and it even allows them to be run at the same time - you should not rely on any specific behaviour here1.

&emoving event listeners ;emoving event listeners is as easy as adding them$


referenceToOlement"removeOventRistener/,name8fOvent,2referenceTo71nction2phase0

"ote that you can remove event listeners at any time and you must remove them using the e#act same parameters as you added them with. This can be difficult if you used anonymous functions as I did in the e#ample above. If you use anonymous functions you can use the arguments.callee property provided by JavaScript to reference the function and remove the listener. This reference can only be done from inside the listener itself. So for e#ample to add an event listener that removes itself after it has fired once you can use$
oRin!"addOventRistener/,clic!,2f1nction /e0 F alert/,Rin! b1bble fired,0. this"removeOventRistener/,clic!,2arg1ments"callee2false0. G2false0.

Test it here$ fire the event listener and see if it can remove itself 0you should get an alert the first time you clic! the lin!1.

&eferencing the elements that etect the event *ou may notice that I use the )this) !eyword in the last e#ample. Inside an event listener function the)this) !eyword is a reference to the element that is currently detecting the event. In the first e#ample that could be the div or the lin! depending on which one the event listener is attached to. *ou may also notice that the functions accept a parameter 0I called it )e) but you could call it whatever you want1. That parameter as with the original "etscape event model is the event ob4ect and contains a lot of information about the event. For now I will stic! with the basics.

e"ent*b+ect.currentTarget is the same as )this) - it refers to the element that the listener function is
attached to 0if the same function is attached as a listener to several elements it will be a reference to the listener that is currently being run1.

e"ent*b+ect.target is the element that the event actually happened to. In the case of the earlier
e#ample this would be the lin!. If there was a span inside the lin! and you clic!ed that then e"ent*b+ect.targetwould be a reference to the span even if the span itself did not have any listeners attached directly to it. "ote that Safari and Uon%ueror sometimes ma!e the target point to the te#t"ode inside the element. That is incorrect behaviour and should be fi#ed at some point. If this is li!ely to cause problems chec! the nodeType of the target. If it is a te#t or +,ATA node then you will need to use its parent node instead.
var theTarget = e"target. if/ theTarget PP / e"target"nodeType == ; QQ e"target"nodeType == ? 0 0 F theTarget = theTarget"parentAode. G

Test it here$ clic! anyw"ere within this sentence to see what element you clic!ed. Some events 0such as mouseover1 will also provide e"ent*b+ect.relatedTarget. This will be a reference to the element the mouse was over before it was moved over the current element. )ith mutation events it is typically 0but not always1 the parent node of the node being manipulated.

*btaining other information from the event Information such as mouse button and position $eyCode ctrl-ey alt-ey shift-ey

and detail 0such as clic! count1 are available in the same way as with the older model 0see the -T./ events section of this tutorial for more details1. They are available as properties of the

event

ob4ect.

.utation

events 0see

can the ,6. =

also events

provide pre".alue new.alue attrName and attrChange values specification for more details1.

0reventing the efault action In the e#ample above clic!ing the lin!s will activate the listeners but the lin! will be followed anyway. ;eturning false from a listener function does not wor! li!e it used to in the traditional models. Instead you must use event8bject"prevent(efa1lt/0 - only one event listener needs to run this method for the default action to be prevented. "ot all event types can be cancelled 0the load event for e#ample has no default action and cannot be cancelled1. If an event is of a type that can be cancelled the e"ent*b+ect.cancelable property will be true.
oRin!"addOventRistener/,clic!,2f1nction /e0 F alert/,Rin! detected a clic!" 'ancellable6 ,%e"cancellable0. e"prevent(efa1lt/0. G2false0.

Test it here$ if you clic! this lin! you should remain on this page.

0reventing other listeners from seeing the event

T!html -v: does this correctly but because versions before September =GGI activate the listeners in the

wrong order they appear to fail here.

)hen an event is being processed by the event listeners it is possible for any event listener to prevent any more event listeners in the propagation chain from seeing the event. In the e#ample above the div's capture phase clic! event listener could prevent the other event listeners from seeing the clic! event by using the event8bject"stopCropagation/0 method. "ote that you can chec! if the event is a type that can bubble by chec!ing the e"ent*b+ect.bubbles property. The stop,ropagation method only prevents listeners further along the propagation chain from seeing the event. For e#ample I added two event listeners to the lin! in the bubble phase. If one of these

uses thestop,ropagation method the other one will always run no matter in what order the browser ran them. The method would only stop the event listener that was added to the div in the bubble phase.
<div id="thediv"><a href="/" id="thelin!">test</a></div> """ var o(iv = doc1ment"getOlementSy5d/,thediv,0. var oRin! = doc1ment"getOlementSy5d/,thelin!,0. o(iv"addOventRistener/,clic!,2f1nction /e0 F alert/,(iv capt1re ran" Aow stopping propagation",0. e"stopCropagation/0. G2tr1e0. oRin!"addOventRistener/,clic!,2f1nction /e0 F alert/,This alert sho1ld never appear,0. G2false0.

Test it here$ clic! this lin! to activate the event listeners.

More than basic events As well as the basic events defined in -T./ ,6. = provides aditional event types that can be detected. A useful e#ample of these are the mutation events. These fire when elements or descendant nodes are added modified or removed by a script 0I will not go into more detail here see the ,6. = events specification for more details1. They are partially supported by 6pera .o7illa&Firefo# Uon%ueror and Safari. "ote that browser support for )/*0NodeInsertedInto/ocument) )/*0Node1emo"ed%rom/ocument) and)/*0!ubtree0odified) events is currently very poor so these events should not be used. Safari A- also does not wor! with the )/*0#ttr0odified) event. "ote that 6pera I.< Safari <.= and Uon%ueror :.=-:.: will crash if you attempt to use any mutation events. 6pera I.=J Safari <.:J and Uon%ueror :.AJ will wor! correctly. Uon%ueror A.=.= seems to have lost all support for all mutation events.

The ,6. does not provide any way to wor! out if the event will fire or not. If a browser does not support an event it will still allow you to add the event listener but it will not fire the event. It is possible to chec! if a browser supports the re%uired events model using has%eature but this is not a perfect indication since a browser will only claim to support the feature if its support is relatively complete. 'rowsers may support a large amount of the feature 0enough for what you need1 but still not claim to support it. Assuming you want a relatively complete implementation instead of support for 4ust one or two event types chec!ing for mutation events is as simple as this$
if/ doc1ment"implementation"has7eat1re/,H1tationOvents,2,4":,0 0

"ote that this will e#clude .o7illa&Firefo# even though it does support many of the common mutation events. *ou could alternatively chec! for the interface as well since .o7illa&Firefo# 0and 6pera but not Uon%ueror or Safari1 should provide this$
if/ doc1ment"implementation"has7eat1re/,H1tationOvents,2,4":,0 QQ window"H1tationOvent 0

Some other types of event may also cause problems not because the browsers do not support them but because the browsers support them only on the wrong ob4ect. The load event is the worst behaved in this respect. According to the ,6. = events specification the load event should be detected on the documentob4ect. @nfortunately the traditional models used the body tag and mapped it to the window ob4ect. As a result when browsers added support for it via ,6. most of them initially chose to detect it only on thewindow ob4ect. So far 6pera and new versions of Uon%ueror Safari and "etFront correctly detect it on the document ob4ect 0as well as on the window ob4ect for compatibility reasons1. In theory .o7illa&Firefo# will fi# this at some point and although it can be detected on the window ob4ect in all current implementations new implementations may choose to do things right first time and only detect it on the document ob4ect. For this reason you should chec! if the window and document ob4ects can detect events before adding listeners to them. If the browser allows you to attach event listeners to the window you can assume that it can detect the load event there. This is true for all current implementations. "ote also that as described above you should always use the bubble phase when detecting load events or they will repeatedly fire when other embedded content loads. -owever note that .o7illa&Firefo# and i+ab : cannot capture load events 6pera D.HJ Safari and Uon%ueror only capture load events when the listener is attached to the document 0not the window1 and only 6pera D.=- and I+3'rowser correctly always capture load events. @nless you really !now what you

are doing and you have wor!ed around all the incompatibilities you should only ever detect load events in the bubbling phase. .ost importantly do not rely on the implementations of browsers that do not capture load events2 they are wrong and the same code will not wor! the same way in other browsers.
if/ window"addOventRistener 0 F window"addOventRistener/,load,2handler71nction2false0. G else if/ doc1ment"addOventRistener 0 F doc1ment"addOventRistener/,load,2handler71nction2false0. G

+ongratulations2 your browser detected the load event using this script. The situation is similar for several other events such as scroll and resi7e. They will also re%uire you to use the window and document branches.

Manuall! firing events



Safari ma!es the key8ode and char8ode properties read-only so it is not possible to simulate specific .o7illa&Firefo# incorrectly generates the default action for mouse and printable character !eyboard events i+ab : I+3browser "etFront :.:- and T!html -v: cannot manually fire events 0I+3browser "etFront :.:-

!eys when manually firing events. when they are dispatched on form elements. and T!html -v: provide the methods but they do not wor! correctly1.

)ith

the

old

events

model

it

was

easy

to

fire

event

handlers

manually

usingreferenceToOlement"oneventname/0 - since there was only one possible handler and it was treated as a method it could be run as easily as any other method. )ith the ,6. = events model this is not possible since there may be multiple handlers for the same event. The ,6. provides a few methods that can be used to create and prepare a fa!e event ob4ect then use it to fire the event on any target. The element you fire an event on does not have to be listening for that event since potentially the parent element may also be listening for that event. "ote that manually firing an event does not generate the default action associated with that event. For e#ample manually firing a focus event does not cause the element to receive focus 0you must

use its focusmethod for that1 manually firing a submit event does not submit a form 0use the submit method1 manually firing a !ey event does not cause that letter to appear in a focused te#t input and manually firing a clic! event on a lin! does not cause the lin! to be activated etc. In the case of @I events this is important for security reasons as it prevents scripts from simulating user actions that interact with the browser itself. There are five ,6. = event modules and they map directly to the names of the ,6. features2 3vents +overs all event types. -T./3vents +overs ;abort; ;blur; ;change; ;error; ;focus; ;load; ;reset; ;resi<e; ;scroll; ;sele

ct; ;submit; and ;unload;.


@I3vents +overs ;"#) ctivate; ;"#)=ocus>n; ;"#)=ocus#ut; and 0since they do not have their own !ey events module in ,6. =1 it also covers ;keydown; ;keypress; and ;keyup;. Also indirectly covers .ouse3vents. .ouse3vents +overs ;click; ;mousedown; ;mousemove; ;mouseout; ;mouseover; and ;mouseup;. .utation3vents +overs ;"#) ttr)odified; ;"#)!ode>nserted; ;"#)!ode$emoved; ;"#)8har

acter"ata)odified; ;"#)!ode>nserted>nto"ocument; ;"#)!ode$emoved=ro m"ocument; and ;"#)Subtree)odified;.


6ther events 0such as )dblclic$)1 are not part of the specification and browsers are not re%uired to support them. 'rowsers that do support them will either choose an appropriate event module to class them as - dblclic$ would fit very well into .ouse3vents - or they will create a new module. *ou will need to !now what module the browser has put the events into when you create these events. Fa!e event ob4ects are created using the document.createE"ent method and the appropriate event module should be specified when creating it. They are then prepared using the appropriate method and finally they are then fired on the desired target element using the element.dispatchE"ent method. If you use the more specific event type instead of the generic

event type you can provide more information when preparing it. dispatchE"ent will return false if the detault action was prevented. The event ob4ect methods for preparing the event ob4ect properties for the various event modules are$ -T./3vents and generic 3vents
initOvent/ ,type,2 b1bbles2 cancelable 0

@I3vents
initI5Ovent/ ,type,2 b1bbles2 cancelable2 window8bject2 detail 0

.ouse3vents
initHo1seOvent/ ,type,2 b1bbles2 cancelable2 window8bject2 detail2 screenX2 screenK2 clientX2 clientK2 ctrlZey2 altZey2 shiftZey2 metaZey2 b1tton2 relatedTarget 0

.utation3vents
initH1tationOvent/ ,type,2 b1bbles2 cancelable2 relatedAode2 prev+al1e2 new+al1e2 attrAame2 attr'hange 0

"ote although prev(alue new(alue and attr"ame can all be null attr+hange must always be provided even if the event is not a ,6.Attr.odified event 0set it to < = or :1 .ouse3vents are a subclass of @I3vents and all event modules are a subclass of 3vents so if you create a mouse event ob4ect it will also inherit the init2IE"ent and initE"ent methods from the more generic @I3vents and 3vents interfaces. *ou can choose which init3E"ent method you want to use when preparing the event. The following is an e#ample of firing a clic! event$
var fire8nThis = doc1ment"getOlementSy5d/,some5(,0. var ev8bj = doc1ment"createOvent/,Ho1seOvents,0.

ev8bj"initHo1seOvent/ ,clic!,2 tr1e2 tr1e2 window2 92 942 ;?@2 =2 44:2 false2 false2 tr1e2 false2 :2 n1ll 0. fire8nThis"dispatchOvent/ev8bj0.

Test it here$ move your mouse over here and I will manually fire a mouseup event instead. The following is another e#ample of firing a clic! event this time using the generic init3vent method and leaving undefined properties at their default values 0even when using the generic init3vent or init@I3vent you should still use the e#act module name and not a generic module or it will not wor! in .o7illa&Firefo# Uon%ueror or Safari1$
var fire8nThis = doc1ment"getOlementSy5d/,some5(,0. var ev8bj = doc1ment"createOvent/,Ho1seOvents,0. ev8bj"initOvent/ ,clic!,2 tr1e2 tr1e 0. fire8nThis"dispatchOvent/ev8bj0.

Uey events are a little harder because .o7illa&Firefo# does not implement the standard correctly and does not allow you to create !ey events using generic @I3vents 0it may 4ust crash1. Instead it provides a proprietary module 'Uey3vents' proprietary init-eyE"entmethod and initialisation method )init-eyE"ent). The e#pects the following

parameters$ )type) bubbles cancelable window*b+ect ctrl-ey alt-ey shift-ey meta-ey $eyC

ode charCode. *ou can use if/window"ZeyOvent0 to detect support for the Uey3vents module.
'rowsers that e#pect you to use @I3vents do not have a specific initialisation function for !ey events so some properties must be added manually$
var fire8nThis = doc1ment"getOlementSy5d/,some5(,0. if/ window"ZeyOvent 0 F var ev8bj = doc1ment"createOvent/,ZeyOvents,0. ev8bj"initZeyOvent/ ,!ey1p,2 tr1e2 tr1e2 window2 false2 false2 false2 false2 9;2 : 0. G else F var ev8bj = doc1ment"createOvent/,I5Ovents,0. ev8bj"initI5Ovent/ ,!ey1p,2 tr1e2 tr1e2 window2 9 0.

ev8bj"!ey'ode = 9;. G fire8nThis"dispatchOvent/ev8bj0.

+etting support for 8nternet 7xplorer on 'in ows Internet 3#plorer on )indows does not provide any of the ,6. = 3vents methods and provides very few of the properties of the event ob4ect. (ersion H.GJ does provide a similar system that is much more limited in its capabilities but if you need Internet 3#plorer support you will have to accept the differences and limitations ma!e sure your code does not rely on the parts that Internet 3#plorer is missing and implement the branching code I will show you here.

ing an removing listeners

Adding and removing event listeners is done using these methods$


referenceToOlement"attachOvent/,onAame8fOvent,2referenceTo71nction0. referenceToOlement"detachOvent/,onAame8fOvent,2referenceTo71nction0.

These are almost synonymous with the addE"ent4istener and remo"eE"ent4istener methods but they are unable to specify a phase. Internet 3#plorer only detects events in the bubbling phase not capture. It also re%uires 'on' to be included at the start of the eventname so for the clic! event you should use)onclic$) in I3 and not )clic$). 0"ote also that I3 only supports the basic event types - it does not support any of the advanced types such as mutation events.1 If you need Internet 3#plorer support as well you should use this code$
f1nction event-andler/e0 F alert/,(iv b1bble ran,0. G var o(iv = doc1ment"getOlementSy5d/,thediv,0. if/ o(iv"addOventRistener 0 F

o(iv"addOventRistener/,clic!,2event-andler2false0. G else if/ o(iv"attachOvent 0 F o(iv"attachOvent/,onclic!,2event-andler0. G

Test it here$ this te#t has been set up to detect clic! events and should alert a message when clic!ed.

&eferencing the elements that etect the event Internet 3#plorer's model is more annoying here. The )this) !eyword is a reference to the window ob4ect. There is no e%uivalent to the e"ent*b+ect.currentTarget property. Internet 3#plorer's model ma!es it impossible to see what element is currently processing the event. It is possible to reference the actual target of the event using the e"ent*b+ect.srcElement property which is e%uivalent to the e"ent*b+ect.target property provided by ,6. = 3vents. @nli!e the way it wor!s with traditional event models I3 does correctly provide the event ob4ect as an argument to the handler function when you use attachE"ent. There is no need to chec! if window.e"ent is needed instead because it is not needed. -owever it is important to note that in I3 the event ob4ect only e#ists for as long as the initial event propagation thread. It cannot be stored and reference later or used in timeout threads. To use srcElement simply detect what you need 0ma!e sure the standards compliant chec! is made first1$
var theTarget = e"target T e"target 6 e"srcOlement. if/ theTarget PP / theTarget"nodeType == ; QQ theTarget"nodeType == ? 0 0 F theTarget = theTarget"parentAode. G

Test it here$ clic! anyw"ere within this sentence to see what element you clic!ed. *ou can also do the same to get the e%uivalent to e"ent*b+ect.relatedTarget - which is !nown ase"ent*b+ect.fromElement in I3. It is available for mouseover and mouseout events.
var relTarget = e"relatedTarget T e"relatedTarget 6 e"fromOlement.

0reventing the efault action I3 does not provide e"ent*b+ect.pre"ent/efault'( but provides an alternative. The event ob4ect has a property called )return.alue) that will perform the e%uivalent functionality if it is set to false. Setting this value in other browsers will not cause any problems so the easiest way to support I3 as well is li!e this$
if/ e"prevent(efa1lt 0 F e"prevent(efa1lt/0. G e"ret1rn+al1e = false.

Test it here$ if you clic! this lin! you should remain on this page. It is not possible to chec! if the event is a type that can be cancelled in I3.

0reventing other listeners from seeing the event I3 does not provide the stop,ropagation method 0probably because I3 only supports bubbling1. Instead it uses a property called )cancelBubble) which must be set to true to prevent propagation. It is not possible to chec! if the event is a type that can bubble in I3.
if/ e"stopCropagation 0 F e"stopCropagation/0. G e"cancelS1bble = tr1e.

Test it here$ clic! this lin! to activate the event listeners.

Detecting the loa event Internet 3#plorer detects the load event on the window ob4ect using the usual attachE"ent method. This ma!es the load event listener 0shown above1 re%uire one more branch$
if/ window"addOventRistener 0 F window"addOventRistener/,load,2handler71nction2false0. G else if/ doc1ment"addOventRistener 0 F doc1ment"addOventRistener/,load,2handler71nction2false0. G else if/ window"attachOvent 0 F

window"attachOvent/,onload,2handler71nction0. G

+ongratulations2 your browser detected the load event using this script.

Manuall! firing events This is a little more messy than the other event handling since the initialisation is considerably different. Internet 3#plorer has a method for manually firing events called fireE"ent and it is available in I3 H.HJ 0there is no e%uivalent in I3 H.G1. In its simplest form this is similar to the ,6. version but the bubbles andcancelable properties are not available. The fireE"ent method e#pects to be passed either one or two parameters. The first should be the name of the event 0for e#ample2 )onchange)1 and the optional second parameter should be an event ob4ect to be passed to the handler. "ote that even though the window ob4ect can detect several events in I3 0such

as load unload scroll and resi&e - all of which should according to the spec be detected by the document ob4ect not window1 it is not possible to use fireE"ent on the window ob4ect.
var fire8nThis = doc1ment"getOlementSy5d/,some5(,0. if/ doc1ment"createOvent 0 F var ev8bj = doc1ment"createOvent/,Ho1seOvents,0. ev8bj"initOvent/ ,mo1semove,2 tr1e2 false 0. fire8nThis"dispatchOvent/ev8bj0. G else if/ doc1ment"createOvent8bject 0 F fire8nThis"fireOvent/,onmo1semove,0. G

If you want to specify more details you will need to use the createE"ent*b+ect method in I3 to replicate thecreateE"ent and init3E"ent methods of the ,6.. The createE"ent*b+ect method normally returns a blan! event ob4ect and you will need to define parameters yourself. *ou can optionally pass an e#isting event ob4ect to createE"ent*b+ect and it will use that as a template when preparing the new event ob4ect. @sually you will not need to pass it any arguments.

var fire8nThis = doc1ment"getOlementSy5d/,some5(,0. if/ doc1ment"createOvent 0 F var ev8bj = doc1ment"createOvent/,Ho1seOvents,0. ev8bj"initHo1seOvent/ ,mo1semove,2 tr1e2 false2 window2 :2 942 ;?@2 =2 44:2 false2 false2 tr1e2 false2 :2 n1ll 0. fire8nThis"dispatchOvent/ev8bj0. G else if/ doc1ment"createOvent8bject 0 F var ev8bj = doc1ment"createOvent8bject/0. ev8bj"detail = :. ev8bj"screenX = 94. ev8bj"screenK = ;?@. ev8bj"clientX = =. ev8bj"clientK = 44:. ev8bj"ctrlZey = false. ev8bj"altZey = false. ev8bj"shiftZey = tr1e. ev8bj"metaZey = false. ev8bj"b1tton = :. ev8bj"relatedTarget = n1ll. fire8nThis"fireOvent/,onmo1semove,2ev8bj0. G

Test it here$ move your mouse over here and I will manually fire a mouseup event instead.
.OM objects and met"ods

This gives all properties collections and methods of the ):+ ,6. that can be reliably used in all ma4or ,6. browsers as well as doc1ment"styleSheets which is much less reliable but useful if it is available.

6e!

(arent object
o o o o o

"ild object "ild property "ild object being accessed t"roug" a collection)* Event Met"od+,

3ach can be clic!ed for more information. +ollections will also have the length property giving the number of entries in that collection.

The ocument no e

)reating no es

document
o o o

create.ocument&ragment+, createElement+Delement;nameD, create$ext2ode+Dtext contentD,

To walk the D*M tree

document
o o o o

body documentElement getElement-yId+Delement idD, getElements-y$ag2ame+Delement;nameD,

D*M support

document
o

implementation

"as&eature+stringJ #eature<stringJ domVersion,

$ll no es

To walk the D*M tree



I3 incorrectly provides element methods li!e getOlementsSyTagAame on comment nodes.

node
o o o o o o o o

c"ild2odes)* parent2ode #irst "ild getElements-y$ag2ame+Delement;nameD, last "ild nextSibling o##set(arent previousSibling

$ttaching# cop!ing or removing no es

node
o o o o o o o

append "ild+node'e#erence, clone2ode+boolJ copy "ildren$oo, innerH$M/ insert-e#ore+node'e#erence><node'e#erence5, remove "ild+node'e#erence, replace "ild+node'e#erence><node'e#erence5, split$ext+index,

No e information

I3 incorrectly provides element properties li!e tagAame on comment nodes.

node
o o o o o o o o o

data "as "ild2odes+, id node2ame node$ype nodeValue speci#ied tag2ame title

7lement no e attributes

node
o o o o

attributes)* getAttribute+Dattribute2ameD, removeAttribute+Dattribute2ameD, setAttribute+Dattribute;nameD<Dattribute;valueD,

7lement no e st!le

node
o o o

class2ame currentStyle

style2ame style2ame

style

window
o

get omputedStyle+node'e#erence<stringJ pseudoElement,

style2ame

7lement no e si<e an position .not stan ar ise /

node
o o o o o o o o o o o

clientHeig"t client!idt" o##setHeig"t o##set/e#t o##set(arent o##set$op o##set!idt" scrollHeig"t scroll/e#t scroll$op scroll!idt"

Table an associate no es In addition to the normal node functionality nodes belonging to tables have e#tra functionality specially designed to wor! with the layouts of tables.

To walk the D*M tree

node
o o o o o o

caption cells)* rows)* t-odies)* t#oot t"ead

$ttaching# cop!ing or removing no es

node
o o o o

delete ell+cellIndex, delete'ow+rowIndex, delete$&oot+, delete$Head+,

No e information

node
o o

cellIndex rowIndex

St!lesheets .if supporte /

document
o

styleS"eets)*

add'ule+string selectors<string styles, css'ules)*


css'ules)* css$ext delete'ule+int index,

encoding "re# insert'ule+string rule<int index, media parent'ule parentStyleS"eet selector$ext style

css$ext item+int index, lengt" get(ropertyValue+string styleMname, set(roperty+string styleMname<string styleValue<string priority, get(roperty(riority+string styleMname, remove(roperty+string styleMname, nameO#Style

styleS"eet type

delete'ule+int index, disabled "re# imports)* insert'ule+string rule<int index, media media

appendMedium+string media$ype, deleteMedium+string media$ype, item+int index, lengt" media$ext s"eet

owner2ode

owner'ule owningElement

styleS"eet

remove'ule+int index,

rules)*

parentStyleS"eet selector$ext style


css$ext nameO#Style

title type

7vents

ing an removing event listeners

node
o o o o

addEvent/istener+stringJ event<#unction<boolJ p"ase, attac"Event+stringJ onevent<#unction, detac"Event+stringJ onevent<#unction, removeEvent/istener+stringJ event<#unction<boolJ p"ase,

)reating event ob"ects

document
o o

createEvent+stringJ EventModule, createEventObject+optional templateObject,

0reparing event ob"ects

eventObject
o o o o o

initEvent+DtypeD< bubbles< cancelable, init4eyEvent+DtypeD< bubbles< cancelable< window< ctrl4ey< alt4ey< s"i#t4ey< meta4ey< 0ey ode< c"ar ode, initMouseEvent+DtypeD< bubbles< cancelable< window< detail< screen>< screen5< client>< client5< ctrl4ey< alt4ey< s"i#t4ey< meta4ey< button< related$arget, initMutationEvent+DtypeD< bubbles< cancelable< related2ode< prevValue< newValue< attr2ame< attr "ange, init%IEvent+DtypeD< bubbles< cancelable< window< detail,

:iring events

node
o o

dispatc"Event+eventObject, #ireEvent+DontypeD<eventObject,

itional event ob"ect metho s an properties

As well as the traditional event ob4ect properties some more are provided by ,6. events 0or I3 events1 capable browsers.

eventObject
o o o o o o o o o o o o o o o o o o o

attr "ange attr2ame bubbles cancelable cancel-ubble c"ar ode current$arget detail event("ase #romElement meta4ey newValue prevent.e#ault+, prevValue related2ode related$arget returnValue stop(ropagation+, toElement

Вам также может понравиться