Annotation of books/www/chapters/ch05.html, revision 1.23

1.13      petejc      1:     <link rel="prev" href="http://books.mozdev.org/chapters/ch04.html" />
                      2:     <link rel="next" href="http://books.mozdev.org/chapters/ch06.html" />
                      3: 
1.12      petejc      4:     <style type="text/css">
                      5:       div.c15 {font-weight: bold; text-align: center}
                      6:       div.c14 {text-align: center}
                      7:     </style>
                      8: 
                      9:     <h2>Chapter 5</h2>
                     10:     <h1><a name="77037"></a> Scripting Mozilla</h1>
                     11:     <p>In Mozilla, scripting plays important roles in the XPFE.
                     12:     Whether developers refer to script access and security, user
                     13:     interface logic, XPCOM object invocation, or script execution
                     14:     in element event handlers, scripting is so integral to
                     15:     application development that Mozilla, as a development
                     16:     platform, would be inconceivable without it.</p>
                     17:     <p>The core scripting language used in Mozilla is JavaScript.
                     18:     Although it has had a reputation as an unsophisticated language
                     19:     used mostly in web pages, JavaScript is more like a first-tier
                     20:     programming language. Modularity, good exception handing,
                     21:     regular expression enhancement, and number formatting are just
                     22:     some features of the new JavaScript 1.5,<a name="b260"></a><a
                     23:     href="#260">[*]</a> which is based on the ECMA-262 standard.<a
                     24:     name="b261"></a><a href="#261">[*]</a> JavaScript 2.0, due
                     25:     sometime late in 2002, promises to be an even bigger promotion
                     26:     of the language.</p>
                     27:     <p>Three distinct levels of JavaScript are identified in this
                     28:     chapter. A user interface level manipulates content through the
                     29:     DOM, a client layer calls on the services provided by XPCOM,
                     30:     and, finally, an application layer is available in which
                     31:     JavaScript can create an XPCOM component. The following section
                     32:     describes these levels in detail.</p>
                     33:     <h2><a name="77038"></a> Faces of JavaScript in Mozilla</h2>
                     34:     <p>As you have already 
                     35:     <!--INDEX scripting:JavaScript, overview --> 
                     36:     <!--INDEX JavaScript:overview --> seen in some examples in this
                     37:     book, the user interface uses JavaScript extensively to create
                     38:     behavior and to glue various widgets together into a coherent
                     39:     whole. When you add code to the event handler of one element to
                     40:     manipulate another-for example, when you update the value of a
                     41:     textbox using a XUL button-you take advantage of this first
                     42:     "level" of scriptability. In this role, JavaScript uses the
                     43:     Document Object Model (DOM) to access parts of the user
                     44:     interface as a hierarchical collection of objects. The section
                     45:     <a href="#77054">"Adding Scripts to the UI</a>," later in this
                     46:     chapter, discusses this highest level of scripting.</p>
                     47:     <p>At a second level, JavaScript glues the entire user
                     48:     interface to the XPCOM libraries beneath, which create the
                     49:     application core. At this level, XPConnect (see the section <a
                     50:     href="#77066">"What Is XPConnect?</a>" later in this chapter)
                     51:     provides a bridge that makes these components "scriptable,"
                     52:     which means that they can be invoked from JavaScript and used
                     53:     from the user interface layer. When JavaScript calls methods
                     54:     and gets data from scriptable components, it uses this second
                     55:     layer of scriptability.</p>
                     56:     <p>Finally, at the third and ultimate level of Mozilla
                     57:     scripting, JavaScript can be used as a "first-order" language
                     58:     for creating the application core itself, for writing software
                     59:     components or libraries whose services are called. We discuss
                     60:     this third level of scripting and provide a long example in the
                     61:     section <a href="ch08.html#77065">"Creating a JavaScript XPCOM
                     62:     Component</a>" in <a href="ch08.html#77048">Chapter 8</a>.</p>
                     63:     <p>When you use JavaScript in these contexts, the application
                     64:     architecture looks something like <a href="#77002">Figure
                     65:     5-1</a>, in which scripting binds the user interface to the
                     66:     application core through XPConnect and can reside as a software
                     67:     component using such technologies as XPIDL and XPCOM.</p>
                     68:     <div class="c14">
                     69:       <img src="foo.gif">
                     70:     </div>
                     71:     <p><i>Figure 5-1: <a name="77002"></a></i> <i>Scripting in
                     72:     Mozilla</i></p>
                     73:     <h2><a name="77039"></a> JavaScript and the DOM</h2>
                     74:     <p>In the application 
                     75:     <!--INDEX DOM (Document Object Model):overview --> layer of
                     76:     Mozilla, there is little distinction between a web page and the
                     77:     graphical user interface. Mozilla's implementation of the DOM
                     78:     is fundamentally the same for both XUL and HTML. In both cases,
                     79:     state changes and events are propagated through various DOM
                     80:     calls, meaning that the UI itself is content-not unlike that of
                     81:     a web page. In application development, where the difference
                     82:     between application "chrome" and rendered content is typically
                     83:     big, this uniformity is a significant step forward.</p>
                     84:     <h3><a name="77040"></a> What Is the DOM?</h3>
                     85:     <p>The DOM is an API used to access HTML and XML documents. It
                     86:     does two things for web developers: provides a structural
                     87:     representation of the document and defines the way the
                     88:     structure should be accessed from script. In the Mozilla XPFE
                     89:     framework, this functionality allows you to manipulate the user
                     90:     interface as a structured group of nodes, create new UI and
                     91:     content, and remove elements as needed.</p>
                     92:     <p>Because it is designed to access arbitrary HTML and XML, the
                     93:     DOM applies not only to XUL, but also to MathML, SVG, and other
                     94:     XML markup. By connecting web pages and XML documents to
                     95:     scripts or programming languages, the DOM is not a particular
                     96:     application, product, or proprietary ordering of web pages.
                     97:     Rather, it is an <i>API-</i>an interface that vendors must
                     98:     implement if their products are to conform to the W3C DOM
                     99:     standard. Mozilla's commitment to standards ensures that its
                    100:     applications and tools do just that.</p>
                    101:     <p>When you use JavaScript to create new elements in an HTML
                    102:     file or change the attributes of a XUL <tt>button</tt>, you
                    103:     access an object model in which these structures are organized.
                    104:     This model is the DOM for that document or data. The DOM
                    105:     provides a context for the scripting language to operate in.
                    106:     The specific context for web and XML documents-the top-level
                    107:     <tt>window</tt> object, the elements that make up a web
                    108:     document, and the data stored in those elements as children-is
                    109:     standardized in several different specifications, the most
                    110:     recent of which is the upcoming DOM Level 3 standard.</p>
                    111:     <h3><a name="77041"></a> The DOM Standards and Mozilla</h3>
                    112:     <p>The DOM <!--INDEX DOM (Document Object Model):levels --> 
                    113:     <!--INDEX standards, DOM levels --> specifications are split
                    114:     into different levels overseen by the W3C. Each level provides
                    115:     its own features and Mozilla has varying, but nearly complete,
                    116:     levels of support for each. Currently, Mozilla's support for
                    117:     the DOM can be summarized as follows:</p>
                    118:     <ul>
                    119:       <li>DOM Level 1: Excellent</li>
                    120:       <li>DOM Level 2: Good</li>
                    121:       <li>DOM Level 3: Poor; under construction</li>
                    122:     </ul>
                    123:     <p>Mozilla strives to be standards-compliant, but typically
                    124:     reaches full support only when those standards have become
                    125:     recommendations rather than working drafts. Currently, Level 1
                    126:     and Level 2 are recommendations and Level 3 is a working
                    127:     draft.</p>
                    128:     <p>Standards like the DOM make Mozilla an especially attractive
                    129:     software development kit (SDK) for web developers. The same
                    130:     layout engine that renders web content also draws the GUI and
                    131:     pushes web development out of the web page into the application
                    132:     chrome. The DOM provides a consistent, unified interface for
                    133:     accessing all the documents you develop, making the content and
                    134:     chrome accessible for easy cross-platform development and
                    135:     deployment.</p>
                    136:     <h3><a name="77042"></a> DOM Methods and Properties</h3>
                    137:     <p>Methods in <!--INDEX DOM (Document Object Model):methods -->
                    138:     <!--INDEX methods:DOM --> the DOM allow you to access and
                    139:     manipulate any element in the user interface or in the content
                    140:     of a web page. Getting and setting attributes, creating
                    141:     elements, hiding elements, and appending children all involve
                    142:     direct manipulation of the DOM. The DOM mediates all
                    143:     interaction between scripts and the interface itself, so even
                    144:     when you do something as simple as changing an image when the
                    145:     user clicks a button, you use the DOM to register an event
                    146:     handler with the <tt>button</tt> and DOM attributes on the
                    147:     <tt>image</tt> element to change its source.</p>
                    148:     <p>The DOM Level 1 and Level 2 Core specifications contain
                    149:     multiple interfaces, including <i>Node</i>, <i>NodeList</i>,
                    150:     <i>Element</i>, and <i>Document</i>. The following sections
                    151:     describe some interface methods used to manipulate the object
                    152:     model of application chrome, documents, or metadata in Mozilla.
                    153:     The <i>Document</i> and <i>Element</i> interfaces, in
                    154:     particular, contain useful methods for XUL developers.</p>
                    155:     <h4><a name="77043"></a> Using dump( ) to print to STDOUT</h4>
                    156:     <p>The code <!--INDEX STDOUT, printing and --> 
                    157:     <!--INDEX printing, STDOUT --> <!--INDEX dump( ) method --> 
                    158:     <!--INDEX DOM (Document Object Model):methods:printing STDOUT -->
                    159:     <!--INDEX methods:DOM:printing STDOUT --> samples in this
                    160:     chapter use a method called <tt>dump( )</tt> to print data to
                    161:     STDOUT. This method is primarily used for debugging your code
                    162:     and is turned on using a <tt>PREF</tt>. You can turn this
                    163:     <tt>PREF</tt> on using the following code:</p>
                    164: <pre>
                    165: const PREFS_CID      = "@mozilla.org/preferences;1";
1.1       david     166: const PREFS_I_PREF   = "nsIPref";
                    167: const PREF_STRING    = "browser.dom.window.dump.enabled";
                    168: try {
                    169: var Pref        = new Components.Constructor(PREFS_CID, PREFS_I_PREF);
                    170: var pref        = new Pref( );
                    171: pref.SetBoolPref(PREF_STRING, true);
1.12      petejc    172: } catch(e) {}
                    173: </pre>
                    174:     <p>This code is necessary only if you are doing development
                    175:     with a release distribution build of Mozilla. If you are using
                    176:     a debug or nightly build, this <tt>PREF</tt> can be set from
                    177:     the preferences panel by selecting Edit &gt; Preferences &gt;
                    178:     Debug &gt; Enable JavaScript dump( ) output.</p>
                    179:     <h4><a name="77044"></a> getElementById</h4>
                    180:     <p><tt>getElementById(aId)</tt> is 
                    181:     <!--INDEX elements:referencing --> 
                    182:     <!--INDEX referencing:elements --> 
                    183:     <!--INDEX getElementById( ) method --> 
                    184:     <!--INDEX DOM (Document Object Model):methods:referencing elements -->
                    185:     <!--INDEX methods:DOM:referencing elements --> perhaps the most
                    186:     commonly used DOM method in any programming domain. This is a
                    187:     convenient way to get a reference to an element object by
                    188:     passing that element's <tt>id</tt> as an argument, where the
                    189:     <tt>id</tt> acts as a unique identifier for that element.</p>
                    190:     <p>DOM calls like this are at the heart of Mozilla UI
                    191:     functionality. <tt>getElementById</tt> is the main programmatic
                    192:     entry point into the chrome and is essential for any dynamic
                    193:     manipulation of XUL elements. For example, to get a box element
                    194:     in script (i.e., to get a reference to it so you can call its
                    195:     methods or read data from it), you must refer to it by using
                    196:     the box <tt>id</tt>:</p>
                    197: <pre>
                    198: &lt;box id="my-id" /&gt;
                    199: </pre>
                    200:     <p>Since the return value of <tt>getElementById</tt> is a
                    201:     reference to the specified element object, you usually assign
                    202:     it to a variable like this:</p>
                    203: <pre>
                    204: var boxEl = document.getElementById('my-id');
1.1       david     205: dump("boxEl="+boxEl+"\n");
1.12      petejc    206: console output: boxEl=[object XULElement]
                    207: </pre>
                    208:     <p>Once you have the box element available as <tt>boxEl</tt>,
                    209:     you can use other DOM methods like <tt>getAttribute</tt> and
                    210:     <tt>setAttribute</tt> to change its layout, its position, its
                    211:     state, or other features.</p>
                    212:     <h4><a name="77045"></a> getAttribute</h4>
                    213:     <p>Attributes <!--INDEX attributes:referencing --> 
                    214:     <!--INDEX referencing:attributes --> 
                    215:     <!--INDEX getAttribute( ) method --> 
                    216:     <!--INDEX DOM (Document Object Model):methods:referencing attributes -->
                    217:     <!--INDEX methods:DOM:referencing attributes --> are properties
                    218:     that are defined directly on an element. XUL elements have
                    219:     attributes such as <tt>disabled</tt>, <tt>height</tt>,
                    220:     <tt>style</tt>, <tt>orient</tt>, and <tt>label</tt>.</p>
                    221: <pre>
                    222: &lt;box id="my-id" foo="hello 1" bar="hello 2" /&gt;
                    223: </pre>
                    224:     <p>In the snippet above, the strings "my-id," "hello 1," and
                    225:     "hello 2" are values of the box element attributes. Note that
                    226:     Gecko does not enforce a set of attributes for XUL elements.
                    227:     XUL documents must be well-formed, but they are not validated
                    228:     against any particular XUL DTD or schema. This lack of
                    229:     enforcement means that attributes can be placed on elements ad
                    230:     hoc. Although this placement can be confusing, particularly
                    231:     when you look at the source code for the Mozilla browser
                    232:     itself, it can be very helpful when you create your own
                    233:     applications and want to track the data that interests you.</p>
                    234:     <p>Once you have an object assigned to a variable, you can use
                    235:     the DOM method <tt>getAttribute</tt> to get a reference to any
                    236:     attribute in that object. The <tt>getAttribute</tt> method
                    237:     takes the name of the desired attribute as a string. For
                    238:     example, if you add an attribute called <tt>foo</tt> to a box
                    239:     element, you can access that attribute's value and assign it to
                    240:     a variable:</p>
                    241: <pre>
                    242: &lt;box id="my-id" foo="this is the foo attribute" /&gt;
1.1       david     243: &lt;script&gt;
                    244: var boxEl = document.getElementById('my-id');
1.12      petejc    245:  var foo   = boxEl.getAttribute('foo');
                    246:  dump(foo+'\n');
                    247: &lt;/script&gt;
                    248: </pre>
                    249:     <p>The <tt>dump</tt> method outputs the string "this is the foo
                    250:     attribute," which is the value of the attribute <tt>foo</tt>.
                    251:     You can also add or change existing attributes with the
                    252:     <tt>setAttribute</tt> DOM method.</p>
                    253:     <h4><a name="77046"></a> setAttribute</h4>
                    254:     <p>The <tt>setAttribute</tt> 
                    255:     <!--INDEX attributes:changing values --> 
                    256:     <!--INDEX setAttribute( ) method --> 
                    257:     <!--INDEX DOM (Document Object Model):methods:changing attribute values -->
                    258:     <!--INDEX methods:DOM:changing attribute values --> method
                    259:     changes an existing attribute value. This method is useful for
                    260:     changing the state of an element-its visibility, size, order
                    261:     within a parent, layout and position, style, etc. It takes two
                    262:     arguments: the attribute name and the new value.</p>
                    263: <pre>
                    264: &lt;box id="my-id" foo="this is the foo attribute" /&gt;
1.1       david     265: &lt;script&gt;
                    266: boxEl=document.getElementById('my-id');
                    267: boxEl.setAttribute('foo', 'this is the foo attribute changed');
                    268: var foo = boxEl.getAttribute('foo');
                    269: dump(foo+'\n');
1.12      petejc    270: &lt;/script&gt;
                    271: </pre>
                    272:     <p>The script above outputs the string "this is the foo
                    273:     attribute changed" to the console. You can also use
                    274:     <tt>setAttribute</tt> to create a new attribute if it does not
                    275:     already exist:</p>
                    276: <pre>
                    277: &lt;box id="my-id" /&gt;
1.1       david     278: &lt;script&gt;
                    279: boxEl=document.getElementById('my-id');
                    280: boxEl.setAttribute('bar', 'this is the new attribute bar');
1.12      petejc    281: &lt;/script&gt;
                    282: </pre>
                    283:     <p>By setting an attribute that doesn't already exist, you
                    284:     create it dynamically, adding a value to the hierarchical
                    285:     representation of nodes that form the current document object.
                    286:     After this code is executed, the <tt>boxEl</tt> element is the
                    287:     same as an element whose <tt>bar</tt> attribute was hardcoded
                    288:     into the XUL:</p>
                    289: <pre>
                    290: &lt;box id="my-id" bar="this is the new attribute bar" /&gt;
                    291: </pre>
                    292:     <p>These sorts of ad hoc changes give you complete control over
                    293:     the state of the application interface.</p>
                    294:     <h4><a name="77047"></a> createElement</h4>
                    295:     <p>If you <!--INDEX elements:creating --> 
                    296:     <!--INDEX createElement( ) method --> 
                    297:     <!--INDEX DOM (Document Object Model):methods:creating elements -->
                    298:     <!--INDEX methods:DOM:creating elements --> need to dynamically
                    299:     create an element that doesn't already exist-for example, to
                    300:     add a new row to a table displaying rows of information, you
                    301:     can use the method <tt>createElement</tt>. To create and add a
                    302:     text element to your box example, for example, you can use the
                    303:     following code:</p>
                    304: <pre>
                    305: &lt;box id="my-id" /&gt;
1.1       david     306: &lt;script&gt;
                    307: boxEl = document.getElementById('my-id');
                    308: var textEl  = document.createElement('description');
                    309: boxEl.appendChild(textEl);
1.12      petejc    310: &lt;/script&gt;
                    311: </pre>
                    312:     <p>Once you create the new element and assign it to the
                    313:     <tt>textEl</tt> variable, you can use <tt>appendChild</tt> to
                    314:     insert it into the object tree. In this case, it is appended to
                    315:     <tt>boxEl</tt>, which becomes the insertion point.</p>
                    316:     <blockquote>
                    317:       <div class="c15">
                    318:         NOTE
                    319:       </div>
                    320:       <p>For mixed namespace documents like XUL and HTML, you can
                    321:       use a variation of <tt>createElement</tt> called
                    322:       <tt>createElementNS</tt>. To create a mixed namespace
                    323:       element, use this code:</p>
                    324:     </blockquote>
                    325:     var node = document.createElementNS('<a href=
                    326:     "http://www.w3.org/1999.xhtml">http://www.w3.org/1999.xhtml</a>',
                    327:     'html:div'); 
                    328:     <blockquote>
                    329:       <p>Namespace variations for other functions include
                    330:       <tt>setAttributeNS</tt>, <tt>getElementsByTagNameNS</tt>, and
                    331:       <tt>hasAttributeNS</tt>.</p>
                    332:     </blockquote>
                    333:     <h4><a name="77048"></a> createTextNode</h4>
                    334:     <p>In <!--INDEX text nodes, creating --> 
                    335:     <!--INDEX createTextNode( ) method --> 
                    336:     <!--INDEX DOM (Document Object Model):methods:creating text nodes -->
                    337:     <!--INDEX methods:DOM:creating text nodes --> addition to
                    338:     setting the <tt>label</tt> attribute on an element, you can
                    339:     create new text in the interface by using the DOM method
                    340:     <tt>createTextNode</tt>, as shown in the following example:</p>
                    341: <pre>
                    342: &lt;description id="explain" /&gt;
1.1       david     343: &lt;script&gt;
                    344: var description = document.getElementById("explain");
                    345: if (description) {
                    346: if (!description.childNodes.length) {
                    347: var textNode = document.createTextNode("Newly text");
                    348: description.appendChild(textNode);
                    349: }
                    350: else if (description.childNodes.length == 1 ) {
                    351: description.childNodes[0].nodeValue = "Replacement text";
                    352: }
                    353: }
1.12      petejc    354: &lt;/script&gt;
                    355: </pre>
                    356:     <p>Notice the use of <tt>appendChild</tt>. This method,
                    357:     discussed next, is used to insert the new element or text node
                    358:     into the DOM tree after it is created. Create-and-append is a
                    359:     common two-step process for adding new elements to the object
                    360:     model.</p>
                    361:     <h4><a name="77049"></a> appendChild</h4>
                    362:     <p>To dynamically <!--INDEX elements:adding dynamically --> 
                    363:     <!--INDEX appendChild( ) method --> 
                    364:     <!--INDEX DOM (Document Object Model):methods:adding elements dynamically -->
                    365:     <!--INDEX methods:DOM:adding elements dynamically --> add an
                    366:     element to a document, you need to use the method
                    367:     <tt>appendChild( )</tt>. This method adds a newly created
                    368:     element to an existing parent node by appending to it. If a
                    369:     visible widget is added, this change is visible in the
                    370:     interface immediately.</p>
                    371: <pre>
                    372: &lt;groupbox id="my-id" /&gt;
1.1       david     373: &lt;script&gt;
                    374: var existingEl  = document.getElementById('my-id');
                    375: var captionEl   = document.createElement('caption');
                    376: existingEl.appendChild(captionEl);
                    377: captionEl.setAttribute('label', 'This is a new caption');
                    378: captionEl.setAttribute('style', 'color: blue;');
1.12      petejc    379: &lt;/script&gt;
                    380: </pre>
                    381:     <p>This example creates a new element, gets an existing parent
                    382:     element from the document, and then uses <tt>appendChild(
                    383:     )</tt> to insert that new element into the document. It also
                    384:     uses <tt>setAttribute</tt> to add an attribute value and some
                    385:     CSS style rules, which can highlight the new element in the
                    386:     existing interface.</p>
                    387:     <h4><a name="77050"></a> cloneNode</h4>
                    388:     <p>For <!--INDEX nodes:copying --> 
                    389:     <!--INDEX cloneNode( ) method --> 
                    390:     <!--INDEX DOM (Document Object Model):methods:copying nodes -->
                    391:     <!--INDEX methods:DOM:copying nodes --> elements that already
                    392:     exist, a copy method allows you to duplicate elements to avoid
                    393:     having to recreate them from scratch. <tt>cloneNode</tt>, which
                    394:     is a method on the <tt>element</tt> object rather than the
                    395:     <tt>document</tt>, returns a copy of the given node.</p>
                    396: <pre>
                    397: &lt;script&gt;
1.1       david     398: // this is untested --pete
                    399: var element = document.getElementById('my-id');
                    400: var clone = element.cloneNode(false);
                    401: dump(`element='+element+'\n');
                    402: dump(`clone='+clone+'\n');
1.12      petejc    403: &lt;/script&gt;
                    404: </pre>
                    405:     <p>The method takes a Boolean-optional parameter that specifies
                    406:     whether the copy is "deep." Deep copies duplicate all
                    407:     descendants of a node as well as the node itself.</p>
                    408:     <h4><a name="77051"></a> getElementsByTagName</h4>
                    409:     <p>Another <!--INDEX elements:arrays, returning --> 
                    410:     <!--INDEX getElementsByTagName( ) method --> 
                    411:     <!--INDEX DOM (Document Object Model):methods:returning element arrays -->
                    412:     <!--INDEX methods:DOM:returning element arrays --> very useful
                    413:     method is <tt>getElementsByTagName</tt>. This method returns an
                    414:     array of elements of the specified type. The argument used is
                    415:     the string <i>element type</i>. "box," for example, could be
                    416:     used to obtain an array of all boxes in a document. The array
                    417:     is zero-based, so the elements start at 0 and end with the last
                    418:     occurrence of the element in the document. If you have three
                    419:     boxes in a document and want to reference each box, you can do
                    420:     it as follows:</p>
                    421: <pre>
                    422: &lt;box id="box-one" /&gt;
1.1       david     423: &lt;box id="box-two" /&gt;
                    424: &lt;box id="box-three" /&gt;
                    425: &lt;script&gt;
                    426: document.getElementsByTagName('box')[0];
                    427: document.getElementsByTagName('box')[1];
                    428: document.getElementsByTagName('box')[2];
1.12      petejc    429: &lt;/script&gt;
                    430: </pre>
                    431:     <p>Or you can get the array and index into it like this:</p>
                    432: <pre>
                    433: var box = document.getElementsByTagName('box');
                    434: </pre>
                    435:     <p>box[0], the first object in the returned array, is a XUL
                    436:     box.</p>
                    437:     <p>To see the number of boxes on a page, you can use the
                    438:     <tt>length</tt> property of an array:</p>
                    439: <pre>
                    440: var len = document.getElementsByTagName('box').length;
1.5       petejc    441: dump(len+'\n');
1.12      petejc    442: console output: 3
                    443: </pre>
                    444:     <p>To output the <tt>id</tt> of the box:</p>
                    445: <pre>
                    446: &lt;box id="box-one" /&gt;
1.1       david     447: &lt;box id="box-two" /&gt;
                    448: &lt;box id="box-three" /&gt;
                    449: &lt;script&gt;
                    450: var el      = document.getElementsByTagName('box');
                    451: var tagId   = el[0].id;
                    452: dump(tagId+"\n");
                    453: &lt;/script&gt;
1.12      petejc    454: console output: box-one
                    455: </pre>
                    456:     <p>To get to an attribute of the second box:</p>
                    457: <pre>
                    458: &lt;box id="box-one" /&gt;
1.1       david     459: &lt;box id="box-two" foo="some attribute for the second box" /&gt;
                    460: &lt;box id="box-three" /&gt;
                    461: &lt;script&gt;
                    462: var el        = document.getElementsByTagName('box');
                    463: var att       = el[1].getAttribute('foo');
                    464: dump(att      +"\n");
                    465: &lt;/script&gt;
1.12      petejc    466: console output: some attribute for the second box
                    467: </pre>
                    468:     <p><tt>getElementsByTagName</tt> is a handy way to obtain DOM
                    469:     elements without using <tt>getElementById</tt>. Not all
                    470:     elements have <tt>id</tt> attributes, so other means of getting
                    471:     at the elements must be used occasionally.<a name="b262"></a><a
                    472:     href="#262">[*]</a></p>
                    473:     <h4><a name="77052"></a> Getting an element object and its
                    474:     properties</h4>
                    475:     <p>In addition <!--INDEX properties:elements:viewing --> 
                    476:     <!--INDEX elements:properties:viewing --> to a basic set of
                    477:     attributes, an element may have many properties. These
                    478:     properties don't typically appear in the markup for the
                    479:     element, so they can be harder to learn and remember. To see
                    480:     the properties of an element object node, however, you can use
                    481:     a JavaScript <tt>for</tt> <tt>in</tt> loop to iterate through
                    482:     the list, as shown in <a href="#77012">Example 5-1</a>.</p>
                    483:     <p><i>Example 5-1: <a name="77012"></a></i> <i>Printing element
                    484:     properties to the console</i></p>
                    485: <pre>
                    486:  &lt;box id="my-id" /&gt;
1.1       david     487:  &lt;script&gt;
                    488:    var el = document.getElementById('my-id');
                    489:    for (var list in el)
                    490:      dump("property  = "+list+"\n");
                    491:  &lt;/script&gt;
                    492:  console output(subset):
                    493:  property = id
                    494:  property = className
                    495:  property = style
                    496:  property = boxObject
                    497:  property = tagName
                    498:  property = nodeName
1.12      petejc    499:  . . .
                    500: </pre>
                    501:     <p>Note the implicit functionality in the <tt>el</tt> object
                    502:     itself: when you iterate over the object reference, you ask for
                    503:     all members of the class of which that object is an instance.
                    504:     This simple example "spells" the object out to the console.
                    505:     Since the DOM recognizes the window as another element (albeit
                    506:     the root element) in the Document Object Model, you can use a
                    507:     similar script in <a href="#77014">Example 5-2</a> to get the
                    508:     properties of the window itself.</p>
                    509:     <p><i>Example 5-2: <a name="77014"></a></i> <i>Printing the
                    510:     window properties</i></p>
                    511: <pre>
                    512:  &lt;script&gt;
1.1       david     513:    var el        = document.getElementById('test-win');
                    514:    for(var list in el)
                    515:      dump("property  = "+list+"\n");
                    516:  &lt;/script&gt;
1.12      petejc    517:  &lt;/td&gt;console output(subset):
1.1       david     518:  property = nodeName
                    519:  property = nodeValue
                    520:  property = nodeType
                    521:  property = parentNode
                    522:  property = childNodes
                    523:  property = firstChild
1.12      petejc    524:  . . .
                    525: </pre>
                    526:     <p>The output in <a href="#77014">Example 5-2</a> is a small
                    527:     subset of all the DOM properties associated with a XUL window
                    528:     and the other XUL elements, but you can see all of them if you
                    529:     run the example. Analyzing output like this can familiarize you
                    530:     with the interfaces available from <tt>window</tt> and other
                    531:     DOM objects.</p>
                    532:     <h4><a name="77053"></a> Retrieving elements by property</h4>
                    533:     <p>You can also use a 
                    534:     <!--INDEX properties:elements:returning --> 
                    535:     <!--INDEX elements:properties:returning --> DOM method to
                    536:     access elements with specific properties by using
                    537:     <tt>getElementsByAttribute</tt>. This method takes the name and
                    538:     value of the attribute as arguments and returns an array of
                    539:     nodes that contain these attribute values:</p>
                    540: <pre>
                    541: &lt;checkbox id="box-one" /&gt;
1.1       david     542: &lt;checkbox id="box-two" checked="true"/&gt;
                    543: &lt;checkbox id="box-three" checked="true"/&gt;
                    544: &lt;script&gt;
                    545: var chcks = document.getElementsByAttribute("checked", "true");
                    546: var count = chcks.length;
                    547: dump(count + " items checked \n");
1.12      petejc    548: &lt;/script&gt;
                    549: </pre>
                    550:     <p>One interesting use of this method is to toggle the state of
                    551:     elements in an interface, as when you get all menu items whose
                    552:     <tt>disabled</tt> attribute is set to true and set them to
                    553:     false. In the xFly sample, you can add this functionality with
                    554:     a few simple updates. In the <i>xfly.js</i> file in the xFly
                    555:     package, add the function defined in <a href="#77016">Example
                    556:     5-3</a>.</p>
                    557:     <p><i>Example 5-3: <a name="77016"></a></i> <i>Adding toggle
                    558:     functionality to xFly</i></p>
                    559: <pre>
                    560:  function toggleCheck( ) {
1.1       david     561:    // get the elements before you make any changes
                    562:    var chex   = document.getElementsByAttribute("disabled", "true");
                    563:    var unchex = document.getElementsByAttribute("disabled", "false");
                    564:    for (var i=0; i&lt;chex.length; i++)
1.22      brian     565:        chex[i].setAttribute("disabled", "false");
1.1       david     566:    for (var i=0; i&lt;unchex.length; i++)
1.22      brian     567:        unchex[i].setAttribute("disabled", "true");
1.12      petejc    568:  }
                    569: </pre>
                    570:     <p>Although this example doesn't update elements whose
                    571:     <tt>disabled</tt> attribute is not specified, you can call this
                    572:     function from a new menu item and have it update all menus
                    573:     whose checked state you do monitor, as shown in <a href=
                    574:     "#77018">Example 5-4</a>.</p>
                    575:     <p><i>Example 5-4: <a name="77018"></a></i> <i>Adding Toggle
                    576:     menus to xFly</i></p>
                    577: <pre>
                    578:  &lt;menubar id="appbar"&gt;
1.1       david     579:    &lt;menu label="File"&gt;
                    580:       &lt;menupopup&gt;
                    581:         &lt;menuitem label="New"/&gt;
                    582:         &lt;menuitem label="Open"/&gt;
                    583:       &lt;/menupopup&gt;
                    584:    &lt;/menu&gt;
                    585:    &lt;menu label="Edit"&gt;
                    586:       &lt;menupopup&gt;
                    587:         &lt;menuitem label="Toggle" oncommand="toggleCheck( );" /&gt;
                    588:       &lt;/menupopup&gt;
                    589:    &lt;/menu&gt;
                    590:    &lt;menu label="Fly Types"&gt;
                    591:       &lt;menupopup&gt;
                    592:         &lt;menuitem label="House" disabled="true" /&gt;
                    593:         &lt;menuitem label="Horse" disabled="true" /&gt;
                    594:         &lt;menuitem label="Fruit" disabled="false" /&gt;
                    595:       &lt;/menupopup&gt;
                    596:    &lt;/menu&gt;
1.12      petejc    597:  &lt;/menubar&gt;
                    598: </pre>
                    599:     <p>When you add this to the xFly application window (from <a
                    600:     href="ch02.html#77034">Example 2-10</a>, for example, above the
                    601:     basic <tt>vbox</tt> structure), you get an application menu bar
                    602:     with a menu item, Toggle, that reverses the checked state of
                    603:     the three items in the "Fly Types" menu, as seen in <a href=
                    604:     "#77004">Figure 5-2</a>.</p>
                    605:     <div class="c14">
                    606:       <img src="foo.gif">
                    607:     </div>
                    608:     <p><i>Figure 5-2: <a name="77004"></a></i> <i>Toggling the
                    609:     state of menu items in xFly</i></p>
                    610:     <p>The following section explains more about hooking scripts up
                    611:     to the interface. Needless to say, when you use a method like
                    612:     <tt>getElementsByAttribute</tt> that operates on all elements
                    613:     with a particular attribute value, you must be careful not to
                    614:     grab elements you didn't intend (like a button elsewhere in the
                    615:     application that gets disabled for other purpose).</p>
                    616:     <h2><a name="77054"></a> Adding Scripts to the UI</h2>
                    617:     <p>Once you are comfortable with how JavaScript works in the
                    618:     context of the user interface layer and are familiar with some
                    619:     of the primary DOM methods used to manipulate the various
                    620:     elements and attributes, you can add your own scripts to your
                    621:     application. Though you can use other techniques to get scripts
                    622:     into the UI, one of the most common methods is to use Mozilla's
                    623:     event model, which is described in the next few sections.</p>
                    624:     <h3><a name="77055"></a> Handling Events from a XUL
                    625:     Element</h3>
                    626:     <p><i>Events</i> are input 
                    627:     <!--INDEX scripts:adding to UI, event handling and --> 
                    628:     <!--INDEX event handling:adding scripts to UI --> messages 
                    629:     <!--INDEX XUL (XML-based User-interface Language):elements:event handling -->
                    630:     that pass information from the user interface to the
                    631:     application code. Capturing this information, or <i>event
                    632:     handling</i>, is how you usually tell scripts when to start and
                    633:     stop.</p>
                    634:     <p>When the user clicks a XUL button, for instance, the button
                    635:     "listens" for the click event, and may also handle that event.
                    636:     If the button itself does not handle the event (e.g., by
                    637:     supplying executable JavaScript in an event handler attribute),
                    638:     then the event "bubbles," or travels further up into the
                    639:     hierarchy of elements above the button. The event handlers in
                    640:     <a href="#77016">Example 5-3</a> use simple inline JavaScript
                    641:     to show that the given event (e.g., the window loading in the
                    642:     first example, the button getting clicked in the second, and so
                    643:     on) was fired and handled.</p>
                    644:     <p>As in HTML, predefined event handlers are available as
                    645:     attributes on a XUL element. These attributes are entry points
                    646:     where you can hook in your JavaScript code, as these examples
                    647:     show. Note that event handler attributes are technically a
                    648:     shortcut, for which the alternative is to register event
                    649:     listeners explicitly to specified elements. The value of these
                    650:     on[event] event handler attributes is the inline JavaScript
                    651:     that should be executed when that event is triggered. <a href=
                    652:     "#77020">Example 5-5</a> shows some basic button activation
                    653:     events.</p>
                    654:     <p><i>Example 5-5: <a name="77020"></a></i> <i>Basic event
                    655:     handler attributes</i></p>
                    656: <pre>
                    657:  &lt;window onload="dump('this window has loaded\n');" /&gt;
1.1       david     658:  &lt;button label="onclick-test"
                    659:     onclick="dump('The event handler onclick has just been used\n');" /&gt;
                    660:  &lt;button label="oncommand-test"
                    661:     oncommand="dump('The event handler oncommand has just been used\n');" /&gt;
                    662:  &lt;menulist id="custom"
1.12      petejc    663:     onchange="doMyCustomFunction( );" /&gt;
                    664: </pre>
                    665:     <p>While the window and button events in <a href=
                    666:     "#77020">Example 5-5</a> carry out some inline script, there is
                    667:     a variation with the <tt>onchange</tt> handler attached to the
                    668:     <tt>menulist</tt> element. <tt>onchange</tt> contains a
                    669:     JavaScript function call whose definition may live in the XUL
                    670:     document itself or in an external file that is included by
                    671:     using the <tt>src</tt> attribute on a <tt>script</tt>
                    672:     element:</p>
                    673: <pre>
                    674: &lt;script type="application/x-javascript" src="chrome://mypackage/content/myfile.js" /&gt;
                    675: </pre>
                    676:     <p>A large basic set of event handler attributes is available
                    677:     for use on XUL elements (and HTML elements). <a href=
                    678:     "appc.html#77003">Appendix C</a> has a full listing of these
                    679:     events along with explanations. The following subset 
                    680:     <!--INDEX attributes:event handling:XUL elements --> shows the
                    681:     potential for script interaction when the UI uses event
                    682:     handlers:</p>
                    683: <pre>
                    684: onabort
1.1       david     685: onblur
                    686: onerror
                    687: onfocus
                    688: onchange
                    689: onclick
                    690: oncontextmenu
                    691: ondestroy
                    692: onload
                    693: onpaint
                    694: onkeydown
                    695: onkeypress
                    696: onkeyup
                    697: onunload
                    698: onmousemove
                    699: onmouseout
                    700: onmouseover
                    701: onmouseup
                    702: onmousedown
                    703: onrest
                    704: onresize
                    705: onscroll
                    706: onselect
1.12      petejc    707: onsubmit
                    708: </pre>
                    709:     <p>Some of these event handlers work only on particular
                    710:     elements, such as <tt>window</tt>, which listens for the
                    711:     <tt>load</tt> event, the <tt>paint</tt> event, and other
                    712:     special events.</p>
                    713:     <p>To see all event handler attributes on a particular element,
                    714:     you can execute the short script in <a href="#77022">Example
                    715:     5-6</a>, which uses the <tt>for</tt> <tt>in</tt> loop in
                    716:     JavaScript to iterate over the members of an object-in this 
                    717:     <!--INDEX attributes:event handling:viewing for elements -->
                    718:     case, a XUL element.</p>
                    719:     <p><i>Example 5-6: <a name="77022"></a></i> <i>Getting event
                    720:     handler attributes from an element</i></p>
                    721: <pre>
                    722:  &lt;script type="application/x-javascript"&gt;
1.1       david     723:    function listElementHandlers(aObj)
                    724:    {
                    725:      if(!aObj)
                    726:        return null;
                    727:      for(var list in aObj)
                    728:        if(list.match(/^on/))
                    729:          dump(list+'\n');
                    730:    }
                    731:  &lt;/script&gt;
1.12      petejc    732:  &lt;button label="oncommand" oncommand="listElementHandlers(this);" /&gt;
                    733: </pre>
                    734:     <p>The function you added in <a href="#77018">Example 5-4</a>
                    735:     is also an example of event handler code in an application's
                    736:     interface.</p>
                    737:     <h3><a name="77056"></a> Events and the Mozilla Event
                    738:     Model</h3>
                    739:     <p>The event model in Mozilla is the general framework for how
                    740:     events work and move around in the user interface. As you've
                    741:     already seen, events tend to rise up through the DOM
                    742:     hierarchy-a natural process referred to as event propagation or
                    743:     event bubbling. The next two sections describe event
                    744:     propagation and its complement, event capturing.</p>
                    745:     <h4><a name="77057"></a> Event propagation and event
                    746:     bubbling</h4>
                    747:     <p>This availability of events in 
                    748:     <!--INDEX event handling:bubbling --> 
                    749:     <!--INDEX bubbling (event handling) --> 
                    750:     <!--INDEX hierarchy:event bubbling --> 
                    751:     <!--INDEX elements:event handling, bubbling --> nodes above the
                    752:     element of origin is known as event propagation or event
                    753:     bubbling. Event bubbling means you can handle events anywhere
                    754:     above the event-raising element in the hierarchy. When events
                    755:     are handled by elements that did not initiate those events, you
                    756:     must determine which element below actually raised the event.
                    757:     For example, if an event handler in a menu element handles an
                    758:     event raised by one of the menu items, then the menu should be
                    759:     able to identify the raising element and take the appropriate
                    760:     action, as shown in <a href="#77024">Example 5-7</a>. In this
                    761:     example, a JavaScript function determines which
                    762:     <tt>menuitem</tt> was selected and responds appropriately.</p>
                    763:     <p><i>Example 5-7: <a name="77024"></a></i> <i>Event
                    764:     propagation</i></p>
                    765: <pre>
                    766:  &lt;script type="application/x-javascript"&gt;
1.1       david     767:  function doCMD(el) {
                    768:      v = el.getAttribute("label")
                    769:      switch (v) {
                    770:        case "New":
                    771:          alert('New clicked');
                    772:           break;
                    773:        case "Open":
                    774:          alert('Open clicked');
                    775:          break;
                    776:        case "Close":
                    777:          alert('Close clicked');
                    778:          break;
                    779:      }
                    780:  }
                    781:  &lt;/script&gt;
                    782:  ...
                    783:  &lt;menu class="menu" label="File" oncommand="doCMD(event.target)"&gt;
                    784:    &lt;menupopup&gt;
                    785:      &lt;menuitem label="New" /&gt;
                    786:      &lt;menuitem label="Open" /&gt;
                    787:      &lt;menuitem label="Close" /&gt;
                    788:    &lt;/menupopup&gt;
1.12      petejc    789:  &lt;/menu&gt;
                    790: </pre>
                    791:     <p>The event handler in the parent node menu finds out which
                    792:     child <tt>menuitem</tt> was actually clicked by using
                    793:     <tt>event.target</tt> and takes action accordingly. Let's walk
                    794:     through another possible scenario. If a user of an application
                    795:     selects an item from a menu list, you could get the node of
                    796:     that item by using <tt>event.target</tt>. Your script could
                    797:     then abstract that item's value or other information, if
                    798:     necessary.</p>
                    799:     <h5><a name="77058"></a> Trapping events</h5>
                    800:     <p>When an <!--INDEX event handling:trapping --> 
                    801:     <!--INDEX trapping events --> event is raised, it is typically
                    802:     handled by any node interested in it as it continues its way up
                    803:     the DOM hierarchy. In some cases, you may want to handle an
                    804:     event and then prevent it from bubbling further up, which is
                    805:     where the DOM Event 
                    806:     <!--INDEX DOM (Document Object Model):event handling, trapping events -->
                    807:     <!--INDEX stopPropagation( ) method --> method
                    808:     <tt>stopPropagation( )</tt> comes in handy.</p>
                    809:     <p><a href="#77026">Example 5-8</a> demonstrates how event
                    810:     bubbling can be arrested very simply. When the XUL document in
                    811:     <a href="#77026">Example 5-8</a> loads, an event listener is
                    812:     registered with a <tt>row</tt> in the tree. The event listener
                    813:     handles the event by executing the function <tt>stopEvent(
                    814:     )</tt>. This function calls an event object method,
                    815:     <tt>stopPropagation</tt>, which keeps the event from bubbling
                    816:     further up into the DOM. Note that the tree itself has an
                    817:     <tt>onclick</tt> event handler that should display a message
                    818:     when clicked. However, the <!--INDEX stopEvent( ) method -->
                    819:     <tt>stopEvent( )</tt> method has stopped propagation, so after
                    820:     the data in the table is updated, the event phase is
                    821:     effectively ended. In this case, the function was used to trap
                    822:     the event and handle it only there.</p>
                    823:     <p><i>Example 5-8: <a name="77026"></a></i> <i>stopPropagation(
                    824:     ) event function</i></p>
                    825: <pre>
                    826:  &lt;?xml version="1.0"?&gt;
1.1       david     827:  &lt;!DOCTYPE  window&gt;
                    828:  &lt;window id="test-win"
1.12      petejc    829:    xmlns="<a href=
                    830: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul</a>"
1.1       david     831:    orient="vertical"
                    832:    onload="load( );"&gt;
                    833:  &lt;script type="application/x-javascript"&gt;
                    834:    function load( ) {
                    835:      el = document.getElementById("t");
                    836:      el.addEventListener("click", stopEvent, false);
                    837:    }
1.12      petejc    838:    &lt;/td&gt;function stopEvent(e) {
1.1       david     839:      // this ought to keep t-daddy from getting the click.
                    840:      e.stopPropagation( );
                    841:    }
                    842:  &lt;/script&gt;
                    843:  &lt;tree&gt;
                    844:    &lt;!-- tree columns definition omitted --&gt;
                    845:    &lt;treechildren flex="1" &gt;
                    846:      &lt;treeitem id="t-daddy"
1.12      petejc    847:        &lt;/td&gt;onclick="alert('t-daddy');"  // this event is never fired
1.1       david     848:        container="true" parent="true"&gt;
                    849:        &lt;treerow id="t"&gt;
                    850:          &lt;treecell label="O'Reilly" id="t1" /&gt;
1.12      petejc    851:          &lt;treecell label="<a href=
                    852: "http://www.oreilly.com">http://www.oreilly.com</a>" id="t2" /&gt;
1.1       david     853:        &lt;/treerow&gt;
                    854:       &lt;/treeitem&gt;
                    855:    &lt;/treechildren&gt;
                    856:  &lt;/tree&gt;
1.12      petejc    857:  &lt;/window&gt;
                    858: </pre>
                    859:     <h4><a name="77059"></a> Capturing events</h4>
                    860:     <p>Event <!--INDEX event handling:capturing events --> 
                    861:     <!--INDEX capturing events --> capturing is the complement of
                    862:     event bubbling. The DOM provides the <tt>addEventListener</tt>
                    863:     method for creating event listeners on nodes that do not
                    864:     otherwise supply them. When you register an event listener on
                    865:     an ancestor of the event target (i.e., any node above the
                    866:     event-raising element in the node hierarchy), you can use event
                    867:     capturing to handle the event in the ancestor before it is
                    868:     heard in the target itself or any intervening nodes.</p>
                    869:     <p>To take advantage of event capturing (or event bubbling with
                    870:     elements that do not already have event listeners), you must
                    871:     add an event listener to the element that wants to capture
                    872:     events occurring below it. Any XUL element may use the DOM
                    873:     <tt>addEventListener</tt> 
                    874:     <!--INDEX addEventListener( ) method --> 
                    875:     <!--INDEX registering:elements, event capturing --> 
                    876:     <!--INDEX elements:registering, event capturing --> 
                    877:     <!--INDEX listeners, event capturing --> method to register
                    878:     itself to capture events. The syntax for using this method in
                    879:     XUL is shown here:</p>
                    880: <pre>
                    881: XULelement = document.getElementById("id of XULelement");
1.1       david     882: XULelement.addEventListener("event name", "event handler code",
1.12      petejc    883: useCapture bool);
                    884: </pre>
                    885:     <p>The event handler code argument can be inline code or the
                    886:     name of a function. The <tt><!--INDEX useCapture parameter -->
                    887:     useCapture</tt> parameter specifies whether the event listener
                    888:     wants to use event capturing or be registered to listen for
                    889:     events that bubble up the hierarchy normally. In <a href=
                    890:     "#77006">Figure 5-3</a>, the alert dialog invoked by the
                    891:     <tt>menuitem</tt> itself is not displayed, since the root
                    892:     <tt>window</tt> element used event capture to handle the event
                    893:     itself.</p>
                    894:     <div class="c14">
                    895:       <img src="foo.gif">
                    896:     </div>
                    897:     <p><i>Figure 5-3: <a name="77006"></a></i> <i>Event
                    898:     capturing</i></p>
                    899:     <p>An <tt><!--INDEX onload event handler --> onload</tt> 
                    900:     <!--INDEX event handling:onload handler --> event handler for a
                    901:     XUL window can also register a <tt>box</tt> element to capture
                    902:     all click events that are raised from its child elements:</p>
                    903: <pre>
                    904: var bbox = document.getElementById("bigbox");
1.1       david     905: if (bbox) {
                    906: bbox.addEventListener("click", "alert('captured')", true);
                    907: }
                    908: ...
                    909: &lt;box id="bigbox"&gt;
                    910: &lt;menu label="File"&gt;
                    911: &lt;menupopup&gt;
                    912: &lt;menuitem label="New" onclick="alert('not captured')" /&gt;
                    913: ...
                    914: &lt;menupopup&gt;
                    915: &lt;/menu&gt;
1.12      petejc    916: &lt;/box&gt;
                    917: </pre>
                    918:     <h3><a name="77060"></a> Changing an Element's CSS Style Using
                    919:     JavaScript</h3>
                    920:     <p>Much of 
                    921:     <!--INDEX CSS (Cascading Style Sheets):styles, changing with JavaScript -->
                    922:     <!--INDEX styles:CSS, changing with JavaScript --> 
                    923:     <!--INDEX JavaScript:Cascading Style Sheets and:changing styles -->
                    924:     <!--INDEX scripting:CSS styles, changing --> what makes the
                    925:     Mozilla UI both flexible and programmable is its ability to
                    926:     dynamically alter the CSS style rules for elements at runtime.
                    927:     For example, if you have a button, you can toggle its
                    928:     visibility by using a simple combination of JavaScript and CSS.
                    929:     Given a basic set of buttons like this:</p>
                    930: <pre>
                    931: &lt;button id="somebutton" class="testButton" label="foo" /&gt;
1.1       david     932: &lt;spacer flex="1" /&gt;
                    933: &lt;button id="ctlbutton"
                    934: class="testButton"
                    935: label="make disappear"
1.12      petejc    936: oncommand="disappear( );" /&gt;
                    937: </pre>
                    938:     <p>as well as a stylesheet import statement at the top of the
                    939:     XUL like this:</p>
                    940: <pre>
                    941: &lt;?xml-stylesheet href="test.css" type="text/css"?&gt;
                    942: </pre>
                    943:     <p>and a simple CSS file in your <i>chrome/xfly/content</i>
                    944:     directory called <i>test.css</i> that contains the following
                    945:     style rule:</p>
                    946: <pre>
                    947: #somebutton[hidden="true"]{ display: none; }
1.1       david     948: .testButton{
                    949: border            : 1px outset #cccccc;
                    950: background-color  : #cccccc;
                    951: padding           : 4px;
                    952: margin            : 50px;
1.12      petejc    953: }
                    954: </pre>
                    955:     <p>You can call <tt>
                    956:     <!--INDEX setAttribute( ) method:calling at runtime -->
                    957:     setAttribute</tt> in your script to hide the button at
                    958:     runtime.</p>
                    959: <pre>
                    960: &lt;script&gt;
1.1       david     961: function disappear( ){
                    962: return document.getElementById('somebutton').setAttribute('hidden', true);
                    963: }
1.12      petejc    964: &lt;/script&gt;
                    965: </pre>
                    966:     <p>The previous code snippet makes a visible button disappear
                    967:     by setting its <tt>hidden</tt> attribute to true. Adding a few
                    968:     more lines, you can toggle the visibility of the button, also
                    969:     making it appear if it is hidden:</p>
                    970: <pre>
                    971: &lt;script&gt;
1.1       david     972: function disappear( ){
                    973: const defaultLabel  = "make disappear";
                    974: const newLabel      = "make reappear";
                    975: var button          = document.getElementById('somebutton');
                    976: var ctlButton       = document.getElementById('ctlbutton');
                    977: if(!button.getAttribute('hidden')) {
                    978: button.setAttribute('hidden', true);
                    979: ctlButton.setAttribute('label', newLabel);
                    980: } else  {
                    981: button.removeAttribute('hidden');
                    982: ctlButton.setAttribute('label', defaultLabel);
                    983: }
                    984: return;
                    985: }
1.12      petejc    986: &lt;/script&gt;
                    987: </pre>
                    988:     <p>Another useful application of this functionality is to
                    989:     collapse elements such as toolbars, boxes, and iframes in your
                    990:     application.</p>
                    991:     <p>The <tt>setAttribute</tt> method can also be used to update
                    992:     the element's <tt>class</tt> attribute with which style rules
                    993:     are so often associated. <tt>toolbarbutton-1</tt> and
                    994:     <tt>button-toolbar</tt> are two different classes of button.
                    995:     You can change a button from a <tt>toolbarbutton-1-</tt>the
                    996:     large button used in the browser-to a standard toolbar button
                    997:     using the following DOM code:</p>
                    998: <pre>
                    999: // get the Back button in the browser
1.1       david    1000: b1 = document.getElementById("back-button");\
1.12      petejc   1001: b1.setAttribute("class", "button-toolbar");
                   1002: </pre>
                   1003:     <p>This dynamically demotes the Back button to an ordinary
                   1004:     toolbar button. Code such as this assumes, of course, that you
                   1005:     know the classes that are used to style the various widgets in
                   1006:     the interface.</p>
                   1007:     <p>You can also set the <tt>style</tt> attribute directly using
                   1008:     the DOM:</p>
                   1009: <pre>
                   1010: el = document.getElementById("some-element");
                   1011: el.setAttribute("style", "background-color:darkblue;");
                   1012: </pre>
                   1013:     <p>Be aware, however, that when you set the <tt>style</tt>
                   1014:     attribute in this way, you are overwriting whatever style
                   1015:     properties may already have been defined in the <tt>style</tt>
                   1016:     attribute. If the document referenced in the snippet above by
                   1017:     the ID <tt>some-element</tt> has a <tt>style</tt> attribute in
                   1018:     which the font size is set to 18pc, for example, that
                   1019:     information is erased when the style attribute is manipulated
                   1020:     in this way.</p>
                   1021:     <h3><a name="77061"></a> Creating Elements Dynamically</h3>
                   1022:     <p>Using the <!--INDEX elements:creating dynamically --> 
                   1023:     <!--INDEX XUL (XML-based User-interface Language):elements:creating dynamically -->
                   1024:     <tt>createElement</tt> method in XUL lets you accomplish things
                   1025:     similar to <tt>document.write</tt> in HTML, with which you can
                   1026:     create new pages and parts of a web page. In <a href=
                   1027:     "#77028">Example 5-9</a>, <tt>
                   1028:     <!--INDEX createElement( ) method:dynamic element creation -->
                   1029:     createElement</tt> is used to generate a menu dynamically.</p>
                   1030:     <p><i>Example 5-9: <a name="77028"></a></i> <i>Dynamic menu
                   1031:     generation</i></p>
                   1032: <pre>
                   1033:  &lt;?xml version="1.0"?&gt;
1.1       david    1034:  &lt;?xml-stylesheet href="test.css" type="text/css"?&gt;
                   1035:  &lt;!DOCTYPE  window&gt;
                   1036:  &lt;window id="test-win"
1.12      petejc   1037:          xmlns="<a href=
                   1038: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul</a>"
1.1       david    1039:          title="test"
                   1040:          style="
                   1041:          min-width : 200px;
                   1042:          min-height: 200px;"&gt;
                   1043:  &lt;script&gt;
1.12      petejc   1044:  &lt;!&lt;/td&gt;[CDATA[
1.1       david    1045:  function generate( ){
                   1046:    var d           = document;
                   1047:    var popup       = d.getElementById('menupopup');
                   1048:    var menuitems   = new Array('menuitem_1',
                   1049:                       'menuitem_2', 'menuitem_3',
                   1050:                       'menuitem_4', 'menuitem_5');
                   1051:    var l           = menuitems.length;
                   1052:    var newElement;
                   1053:    for(var i=0; i&lt;l; i++)
                   1054:    {
                   1055:      newElement = d.createElement('menuitem');
1.12      petejc   1056:      newElement.setAttribute('id', menuitems&lt;/td&gt;[i]);
                   1057:      newElement.setAttribute('label', menuitems&lt;/td&gt;[i]);
1.1       david    1058:      popup.appendChild(newElement);
                   1059:    }
                   1060:    return true;
                   1061:  }
                   1062:  ]]&gt;
                   1063:  &lt;/script&gt;
                   1064:  &lt;menu label="a menu"&gt;
                   1065:    &lt;menupopup id="menupopup"&gt;
                   1066:    &lt;/menupopup&gt;
                   1067:  &lt;/menu&gt;
                   1068:  &lt;spacer flex="1" /&gt;
                   1069:  &lt;button id="ctlbutton" class="testButton" label="generate" oncommand="generate( );" /&gt;
1.12      petejc   1070:  &lt;/window&gt;
                   1071: </pre>
                   1072:     <p>The JavaScript function <tt>
                   1073:     <!--INDEX generate( ) function --> generate( )</tt> in <a href=
                   1074:     "#77028">Example 5-9</a> gets the <tt>menupopup</tt> as the
                   1075:     parent element for the new elements, creates five
                   1076:     <tt>menuitems</tt> in an array called <tt>menuitems</tt>, and
                   1077:     stores five string ID names for those <tt>menuitems</tt>.</p>
                   1078:     <p>The variable <i>l</i> is the length of the array. The
                   1079:     variable <tt>newElement</tt> is a placeholder for elements
                   1080:     created by using the <tt>createElement</tt> method inside of
                   1081:     the <tt>for</tt> loop. <tt>generate( )</tt> assigns
                   1082:     <tt>newElement</tt> on each iteration of the loop and creates a
                   1083:     new <tt>menuitem</tt> each time, providing a way to dynamically
                   1084:     generate a list of menu choices based on input data or user
                   1085:     feedback. Try this example and experiment with different
                   1086:     sources of data, such as a menu of different auto
                   1087:     manufacturers, different styles on group of boxes that come
                   1088:     from user selection, or tabular data in a tree.</p>
                   1089:     <h3><a name="77062"></a> Sharing Data Between Documents</h3>
                   1090:     <p>As the scale of your application development increases and
                   1091:     your applications grow new windows and components, you may
                   1092:     become interested in passing data around and ensuring that the
                   1093:     data remains in scope. Misunderstanding that scope often leads
                   1094:     to problems when beginning Mozilla applications.</p>
                   1095:     <h4><a name="77063"></a> Scope in Mozilla</h4>
                   1096:     <p>The general <!--INDEX documents:sharing data:scope --> 
                   1097:     <!--INDEX sharing data, scope --> 
                   1098:     <!--INDEX scope, sharing data between documents --> rule is
                   1099:     that all scripts pulled in by the base XUL document and scripts
                   1100:     included in overlays of this document are in the same scope.
                   1101:     Therefore, any global variables you declare in any of these
                   1102:     scripts can be used by any other scripts in the same scope. The
                   1103:     decision to put a class structure or more sophisticated design
                   1104:     in place is up to you.</p>
                   1105:     <p>The relationship of a parent and child window indicates the
                   1106:     importance of storing data in language constructs that can be
                   1107:     passed around. This code shows a common way for a parent to
                   1108:     pass data to a window it spawns:</p>
                   1109: <pre>
                   1110: var obj = new Object ( );
1.1       david    1111: obj.res = "";
                   1112: window.openDialog("chrome://xfly/content/foo.xul", 'foo_main',
                   1113: "chrome,resizable,scrollbars,dialog=yes,close,modal=yes",
1.12      petejc   1114: obj);
                   1115: </pre>
                   1116:     <h4><a name="77064"></a> Using the window.arguments array</h4>
                   1117:     <p>The previous <!--INDEX window.arguments array --> 
                   1118:     <!--INDEX arrays, sharing data between documents;window.arguments array -->
                   1119:     <!--INDEX documents:sharing data:window.arguments array -->
                   1120:     code snippet creates a new JavaScript object, <tt>obj</tt>, and
                   1121:     assigns the value of an empty string to that object's
                   1122:     <tt>res</tt> property. The object is then passed by reference
                   1123:     to the new window as the last parameter of the <tt>openDialog(
                   1124:     )</tt> method so it can be manipulated in the scope of the
                   1125:     child window:</p>
                   1126: <pre>
                   1127: function onOk( ) {
1.1       david    1128: window.arguments[0].res  = "ok";
                   1129: return;
                   1130: }
                   1131: function onCancel( ) {
                   1132: window.arguments[0].res  = "cancel";
                   1133: return;
1.12      petejc   1134: }
                   1135: </pre>
                   1136:     <p>In that child window, the object is available as an indexed
                   1137:     item in the special <tt>window.arguments</tt> array. This array
                   1138:     holds a list of the arguments passed to a window when it is
                   1139:     created. window.arguments[0] is a reference to the first
                   1140:     argument in the <tt>openDialog( )</tt> parameter list that is
                   1141:     not a part of the input parameters for that method,
                   1142:     window.arguments[1] is the second argument, and so on. Using
                   1143:     <tt>window.arguments</tt> is the most common way to pass
                   1144:     objects and other data around between documents.</p>
                   1145:     <p>When the user clicks a button in the displayed dialog (i.e.,
                   1146:     the OK or Cancel button), one of the functions sets a value to
                   1147:     the <tt>res</tt> property of the passed-in object. The object
                   1148:     is in the scope of the newly created window. When control is
                   1149:     passed back to the script that launched the window, the return
                   1150:     value can be checked:</p>
                   1151: <pre>
                   1152: if (obj.res != "ok") {
1.1       david    1153: dump("User has cancelled the dialog");
                   1154: return;
1.12      petejc   1155: }
                   1156: </pre>
                   1157:     <p>In this case, a simple dump statement prints the result, but
                   1158:     you can also test the result in your application code and fork
                   1159:     accordingly.</p>
                   1160:     <h2><a name="77065"></a> XPConnect and Scriptable
                   1161:     Components</h2>
                   1162:     <p>At the second level of scripting, XPConnect binds JavaScript
                   1163:     and the user interface to the application core. Here,
                   1164:     JavaScript can access all XPCOM components that implement
                   1165:     scriptable libraries and services through a special global
                   1166:     object whose methods and properties can be used in JavaScript.
                   1167:     Consider these JavaScript snippets from the Mozilla source
                   1168:     code:</p>
                   1169: <pre>
                   1170: // add filters to the file picker
1.1       david    1171: fp.appendFilters( nsIFilePicker.HTML );
                   1172: // display a directory in the file picker
                   1173: fp.displayDirectory ( dir );
                   1174: // read a line from an open file
                   1175: file.readLine(tmpBuf, 1024, didTruncate);
                   1176: // create a new directory
                   1177: this.fileInst.create( DIRECTORY, parseInt(permissions) );
1.12      petejc   1178: retval=OK;
                   1179: </pre>
                   1180:     <p>The <tt>filepicker</tt>, <tt>file</tt>, and
                   1181:     <tt>localfile</tt> components that these JavaScript objects
                   1182:     represent are a tiny fraction of the components available via
                   1183:     XPConnect to programmers in Mozilla. This section describes how
                   1184:     to find these components, create the corresponding JavaScript
                   1185:     objects, and use them in your application programming.</p>
                   1186:     <h3><a name="77066"></a> What Is XPConnect?</h3>
                   1187:     <p>Until now, <!--INDEX XPConnect:overview --> 
                   1188:     <!--INDEX scripting:XPConnect, overview --> scripting has
                   1189:     referred to scripting the DOM, manipulating various elements in
                   1190:     the interface, and using methods available in Mozilla
                   1191:     JavaScript files. However, for real applications like the
                   1192:     Mozilla browser itself, this may be only the beginning. The UI
                   1193:     must be hooked up to the application code and services (i.e.,
                   1194:     the application's actual functionality) to be more than just a
                   1195:     visual interface. This is where XPConnect and XPCOM come
                   1196:     in.</p>
                   1197:     <p>Browsing the Web, reading email, and parsing XML files are
                   1198:     examples of application-level services in Mozilla. They are
                   1199:     part of Mozilla's lower-level functionality. This functionality
                   1200:     is usually written and compiled in platform-native code and
                   1201:     typically written in C++. This functionality is also most often
                   1202:     organized into modules, which take advantage of Mozilla's
                   1203:     cross-platform component object model (XPCOM), and are known as
                   1204:     <i><!--INDEX XPCOM components --> XPCOM components</i>. The
                   1205:     relationship of these components and the application services
                   1206:     they provide to the interface is shown in <a href=
                   1207:     "#77008">Figure 5-4</a>.</p>
                   1208:     <div class="c14">
                   1209:       <img src="foo.gif">
                   1210:     </div>
                   1211:     <p><i>Figure 5-4: <a name="77008"></a></i> <i>How XPConnect
                   1212:     fits into the application model</i></p>
                   1213:     <p>In Mozilla, XPConnect is the bridge between JavaScript and
                   1214:     XPCOM components. The XPConnect technology wraps natively
                   1215:     compiled components with JavaScript objects. XPCOM, Mozilla's
                   1216:     own cross-platform component technology, is the framework on
                   1217:     top of which these scriptable components are built. Using
                   1218:     JavaScript and XPConnect, you can create instances of these
                   1219:     components and use their methods and properties as you do any
                   1220:     regular JavaScript object, as described here. You can access
                   1221:     any or all of the functionality in Mozilla in this way.</p>
                   1222:     <p><a href="ch08.html#77048">Chapter 8</a> describes more about
                   1223:     the XPConnect technology and how it connects components to the
                   1224:     interface. It also describes the components themselves and
                   1225:     their interfaces, the XPCOM technology, and how you can create
                   1226:     your own XPCOM components.</p>
                   1227:     <h4><a name="77067"></a> Creating XPCOM objects in script</h4>
                   1228:     <p><a href="#77030">Example 5-10</a> demonstrates 
                   1229:     <!--INDEX XPCOM:methods:JavaScript implementation --> 
                   1230:     <!--INDEX JavaScript:XPCOM objects, 
                   1231:     creating --> the creation and use of an 
                   1232:     <!--INDEX XPCOM:components --> XPCOM component in JavaScript.
                   1233:     In this example, the script instantiates the
                   1234:     <tt>filepicker</tt> object and then uses it to display a file
                   1235:     picker dialog with all of the file filters selected. To run
                   1236:     this example, add the function to your <i>xfly.js</i> file and
                   1237:     call it from an event handler on the "New" menu item you added
                   1238:     in <a href="ch03.html#77042">Example 3-5</a>. Example 5-10<a
                   1239:     name="77030"></a> <i>Scriptable component example</i></p>
                   1240: <pre>
                   1241:  // chooseApp:  Open file picker and prompt user for application.
1.1       david    1242:  chooseApp: function( ) {
                   1243:    var nsIFilePicker = Components.interfaces.nsIFilePicker;
                   1244:    var fp =
1.12      petejc   1245:       Components.classes&lt;/td&gt;["@mozilla.org/filepicker;1"].
1.1       david    1246:           createInstance( nsIFilePicker );
                   1247:    fp.init( this.mDialog,
                   1248:       this.getString( "chooseAppFilePickerTitle" ),
                   1249:       nsIFilePicker.modeOpen );
                   1250:    fp.appendFilters( nsIFilePicker.filterAll );
                   1251:    if ( fp.show( ) == nsIFilePicker.returnOK &amp;&amp; fp.file ) {
                   1252:    this.choseApp   = true;
                   1253:    this.chosenApp  = fp.file;
                   1254:    // Update dialog.
                   1255:    this.updateApplicationName(this.chosenApp.unicodePath);
1.12      petejc   1256:  }
                   1257: </pre>
                   1258:     <p>Note the first two lines in the function and the way they
                   1259:     work together to create the <tt>fp</tt> <tt>filepicker</tt>
                   1260:     object. The first line in the function assigns the name of the
                   1261:     <i>nsFile-picker</i> interface to the <tt>nsIFilePicker</tt>
                   1262:     variable in JavaScript. This variable is used in the second
                   1263:     line, where the instance is created from the component to
                   1264:     specify which interface on that component should be used.
                   1265:     Discovering and using library interfaces is an important aspect
                   1266:     of XPCOM, where components always implement at least two
                   1267:     interfaces.</p>
                   1268:     <p>In <a href="#77032">Example 5-11</a>, an HTML file (stored
                   1269:     locally, since it wouldn't have the required XPConnect access
                   1270:     as a remote file because of security boundaries) loaded in
                   1271:     Mozilla instantiates a Mozilla sound component and plays a
1.22      brian    1272:     sound with it. Go ahead and try it. 
                   1273:     </p>
                   1274:     
                   1275:     <p>
                   1276:     Example 5-11<a name= "77032"></a> <i>Scripting components from HTML</i></p>
1.14      petejc   1277: <xmp>
                   1278: <html>
1.17      petejc   1279:   <head>
                   1280:     <title>Sound Service Play Example</title>
                   1281:     <script>
                   1282:       function play() {
                   1283:         netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
                   1284:         var sample = Components.classes["@mozilla.org/sound;1"].createInstance();
                   1285:         sample = sample.QueryInterface(Components.interfaces.nsISound);
                   1286:         const SND_NETWORK_STD_CID = "@mozilla.org/network/standard-url;1";
                   1287:         const SND_I_URL           = "nsIURL";
                   1288:         const SND_URL             = new  C.Constructor(SND_NETWORK_STD_CID, SND_I_URL);
                   1289:         var url                   = new SND_URL();
                   1290:         url.spec                  = 'http://jslib.mozdev.org/test.wav';
                   1291:         sample.play(url);
                   1292:       }
                   1293:     </script>
                   1294:   </head>
                   1295:   <body>
                   1296:     <form name="form">
                   1297:       <input type="button" value="Play Sound" onclick="play();">
1.19      petejc   1298:     </form>
1.17      petejc   1299:   </body>
1.18      petejc   1300: </html>
1.14      petejc   1301: </xmp>
1.12      petejc   1302:     <p>As in <a href="#77030">Example 5-10</a>, the classes[ ]
                   1303:     array on the special Mozilla <tt>Components</tt> object refers
                   1304:     to a particular component-in this case, the <tt>sound</tt>
                   1305:     component-by contract ID. All XPCOM objects must have a
                   1306:     contract ID that uniquely identifies them with the domain, the
                   1307:     component name, and a version number ["@mozilla.org/sound;1"],
                   1308:     respectively. See the <a href="ch08.html#77058">"XPCOM
                   1309:     Identifiers</a>" section in <a href="ch08.html#77048">Chapter
                   1310:     8</a> for more information about this.</p>
                   1311:     <h4><a name="77068"></a> Finding components and interfaces</h4>
                   1312:     <p>Most <!--INDEX XPCOM:components:locating and viewing -->
                   1313:     components are scripted in Mozilla. In fact, the challenge is
                   1314:     not to find cases when this scripting occurs (which you can
                   1315:     learn by searching LXR for the <tt>Components</tt>), but to
                   1316:     find Mozilla components that don't use scriptable components.
                   1317:     Finding components and interfaces in Mozilla and seeing how
                   1318:     they are used can be useful when writing your own
                   1319:     application.</p>
                   1320:     <p>The Mozilla <!--INDEX Component Viewer development tool -->
                   1321:     Component Viewer is a great tool for discovering components and
                   1322:     provides a convenient UI for seeing components and looking at
                   1323:     their interfaces from within Mozilla. The Component Viewer can
                   1324:     be built as an extension to Mozilla (see "cview" in the
                   1325:     extensions directory of the Mozilla source), or it can be
                   1326:     downloaded and installed as a separate 
                   1327:     <!--INDEX web sites:Component Viewer --> XPI from <i><a href=
                   1328:     "http://www.hacksrus.com/~ginda/cview/">http://www.hacksrus.com/~ginda/cview/</a></i>.
                   1329:     <a href="appb.html#77021">Appendix B</a> describes the
                   1330:     Component Viewer in more detail.</p>
                   1331:     <p>Commonly used XPCOM objects in the browser and other Mozilla
                   1332:     applications include file objects, RDF services, URL objects,
                   1333:     and category managers.</p>
                   1334:     <h4><a name="77069"></a> Selecting the appropriate interface
                   1335:     from the component</h4>
                   1336:     <p>In all cases, 
                   1337:     <!--INDEX XPCOM:components:interfaces, selecting --> 
                   1338:     <!--INDEX interfaces:XPCOM:components, selecting --> the way to
                   1339:     get the object into script is to instantiate it with the
                   1340:     special <tt>classes</tt> object and use the <tt>createInstance(
                   1341:     )</tt> method on the class to select the interface you want to
                   1342:     use. These two steps are often done together, as in the
                   1343:     following example, which gets the component with the contract
                   1344:     ID <tt>ldap-connection;1</tt>, instantiates an object from the
                   1345:     <i>nsILDAPConnection</i> interface, and then calls a method on
                   1346:     that object:</p>
                   1347: <pre>
                   1348: var connection = Components.classes
1.1       david    1349: ["@mozilla.org/network/ldap-connection;1"].
                   1350: createInstance(Components.interfaces.nsILDAPConnection);
                   1351: connection.init(queryURL.host, queryURL.port, null,
1.12      petejc   1352: generateGetTargetsBoundCallback( ));
                   1353: </pre>
                   1354:     <p>These two common processes-getting a component and selecting
                   1355:     one of its interfaces to assign to an object-can also be
                   1356:     separated into two different statements:</p>
                   1357: <pre>
                   1358: // get the ldap connection component
1.1       david    1359: var connection = Components.classes
1.5       petejc   1360: ["@mozilla.org/network/ldap-connection;1"];
1.1       david    1361: // create an object from the nsILDAPConnection interface;
                   1362: connection.createInstance(Components.interfaces.nsILDAPConnection);
                   1363: // call the init( ) method on that object
                   1364: connection.init(queryURL.host, queryURL.port, null,
1.12      petejc   1365: generateGetTargetsBoundCallback( ));
                   1366: </pre>
                   1367:     <p>Mozilla constantly uses these processes. Wherever
                   1368:     functionality is organized into XPCOM objects (and most of it
                   1369:     is), these two statements bring that functionality into
                   1370:     JavaScript as high-level and user-friendly JavaScript
                   1371:     objects.</p>
                   1372:     <h2><a name="77070"></a> JavaScript Application Code</h2>
                   1373:     <p>There are 
                   1374:     <!--INDEX JavaScript:application programming:overview --> 
                   1375:     <!--INDEX application programming, JavaScript:overview --> two
                   1376:     ways to use JavaScript in the third, deepest level of
                   1377:     application programming. The first is to organize your
                   1378:     JavaScript into libraries so your functions can be reused,
                   1379:     distributed, and perhaps collaborated upon.</p>
                   1380:     <p>The second way is to write a JavaScript component, create a
                   1381:     separate interface for that component, and compile it as an
                   1382:     XPCOM component whose methods and data can be accessed from
                   1383:     XPConnect (using JavaScript). This kind of application
                   1384:     programming is described in <a href="ch08.html#77048">Chapter
                   1385:     8</a>, which includes examples of creating new interfaces,
                   1386:     implementing them in JavaScript or C++, and compiling, testing,
                   1387:     and using the resulting component in the Mozilla interface.</p>
                   1388:     <p>This section introduces the library organization method of
                   1389:     JavaScript application programming. The JSLib code discussed
                   1390:     here is a group of JavaScript libraries currently being
                   1391:     developed by Mozilla contributors and is especially useful for
                   1392:     working with the XPFE and other aspects of the Mozilla
                   1393:     application/package programming model. When you include the
                   1394:     right source files at the top of your JavaScript and/or XUL
                   1395:     file, you can use the functions defined in JSLib libraries as
                   1396:     you would use any third-party library or built-in functions.
                   1397:     You may even want to contribute to the JSLib project yourself
                   1398:     if you think functionality is missing and as your Mozilla
                   1399:     programming skills grow.</p>
                   1400:     <h3><a name="77071"></a> JavaScript Libraries</h3>
                   1401:     <p>The open <!--INDEX JSLib libraries --> 
                   1402:     <!--INDEX JavaScript:application programming:JSLib --> 
                   1403:     <!--INDEX application programming, JavaScript:JSLib --> source
                   1404:     JSLib project makes life easier for developers. The JSLib
                   1405:     package implements some of the key XPCOM components just
                   1406:     discussed and wraps them in simpler, JavaScript interfaces,
                   1407:     which means that you can use the services of common XPCOM
                   1408:     components without having to do any of the instantiation,
                   1409:     interface selection, or glue code yourself. Collectively, these
                   1410:     interfaces are intended to provide a general-purpose library
                   1411:     for Mozilla application developers. To understand what JSLib
                   1412:     does, consider the following short snippet from the JSLib
                   1413:     source file <i>jslib/io/file.js</i>, which implements a
                   1414:     <tt>close( )</tt> function for open file objects and provides a
                   1415:     handy way to clean up things when you finish editing a file in
                   1416:     the filesystem.</p>
                   1417: <pre>
                   1418: /********************* CLOSE ********************************
1.1       david    1419: * void close( )                                              *
                   1420: *                                                           *
                   1421: * void file close                                           *
                   1422: * return type void(null)                                    *
                   1423: * takes no arguments closes an open file stream and         *
                   1424: * deletes member var instances of objects                   *
                   1425: *   Ex:                                                     *
                   1426: *     var p='/tmp/foo.dat';                                 *
                   1427: *     var f=new File(p);                                    *
                   1428: *     fopen( );                                              *
                   1429: *     f.close( );                                            *
                   1430: *                                                           *
                   1431: *   outputs: void(null)                                     *
                   1432: ************************************************************/
                   1433: File.prototype.close = function( )
                   1434: {
                   1435: /***************** Destroy Instances *********************/
                   1436: if(this.mFileChannel)   delete this.mFileChannel;
                   1437: if(this.mInputStream)   delete this.mInputStream;
                   1438: if(this.mTransport)     delete this.mTransport;
                   1439: if(this.mMode)          this.mMode=null;
                   1440: if(this.mOutStream) {
                   1441: this.mOutStream.close( );
                   1442: delete this.mOutStream;
                   1443: }
                   1444: if(this.mLineBuffer)     this.mLineBuffer=null;
                   1445: this.mPosition           = 0;
                   1446: /***************** Destroy Instances *********************/
                   1447: return;
1.12      petejc   1448: }
                   1449: </pre>
                   1450:     <p>To use the <tt>close</tt> method as it's defined here,
                   1451:     import the <i>file.js</i> source file into your JavaScript,
                   1452:     create a file object (as shown in the examples below), and call
                   1453:     its <tt>close( )</tt> method.</p>
                   1454:     <blockquote>
                   1455:       <hr>
                   1456:       <b>xpcshell</b> 
                   1457:       <p>Most <!--INDEX xpcshell --> <!--INDEX shells:xpcshell --> 
                   1458:       <!--INDEX JavaScript:xpcshell --> examples in this section
                   1459:       are in <i>xpcshell</i>, but using these libraries in your
                   1460:       user interface JavaScript is just as easy. You can access
                   1461:       these libraries from a XUL file, as the section <a href=
                   1462:       "#77077">"Using the DirUtils class</a>," later in this
                   1463:       chapter, demonstrates.</p>
                   1464:       <p>xpcshell is the command-line interpreter to JavaScript and
                   1465:       XPConnect. This shell that uses XPConnect to call and
                   1466:       instantiate scriptable XPCOM interfaces. It is used primarily
                   1467:       for debugging and testing scripts.</p>
                   1468:       <p>To run xpcshell, you need to go to the Mozilla <i>bin</i>
                   1469:       directory or have that folder in your PATH. For each
                   1470:       platform, enter:</p>
                   1471:       <p>Windows:</p>
                   1472: <pre>
                   1473: xpcshell.exe
                   1474: </pre>
                   1475:       Unix: 
                   1476: <pre>
                   1477: ./run-mozilla.sh ./xpcshell
                   1478: </pre>
                   1479:       To run xpcshell on Unix, you need to supply environment
                   1480:       variables that the interpreter needs. You can use the
                   1481:       <i>run-mozilla.sh</i> shell script that resides in the
                   1482:       Mozilla <i>bin</i> directory. 
                   1483: <pre>
                   1484: $ ./run-mozilla.sh ./xpcshell
                   1485: </pre>
                   1486:       To see the available options for xpcshell, type this:
                   1487:       <hr>
                   1488:     </blockquote>
                   1489:     $ ./run-mozilla.sh ./xpcshell --help JavaScript-C 1.5
                   1490:     pre-release 4a 2002-03-21 usage: xpcshell [-s] [-w] [-W] [-v
                   1491:     version] [-f scriptfile] [scriptfile] [scriptarg...]  The two
                   1492:     most important parameters here are -w, which enables warnings
                   1493:     output, and -s, which turns on strict mode.
                   1494:     <hr>
                   1495:     <p>The source files for JSLib are well annotated and easy to
                   1496:     read. JSLib provide easy-to-use interfaces for creating
                   1497:     instances of components (e.g., File objects), performing
                   1498:     necessary error checking, and ensuring proper usage. To use a
                   1499:     function like the one just shown, simply include the source
                   1500:     file you need in your XUL:</p>
                   1501: <pre>
                   1502: &lt;script type="application/x-JavaScript"
                   1503: src="chrome://jslib/content/jslib.js" /&gt;
                   1504: </pre>
                   1505:     <p>Then you can include the specific library files you need in
                   1506:     your JavaScript code by using the include method:</p>
                   1507: <pre>
                   1508: include("chrome://jslib/content/io/file.js");
                   1509: include("chrome://jslib/content/zip/zip.js");
                   1510: </pre>
                   1511:     <h4><a name="77072"></a> Installing JSLib</h4>
                   1512:     <p>To use the <!--INDEX installation:JSLib --> 
                   1513:     <!--INDEX JSLib libraries:installing --> 
                   1514:     <!--INDEX JavaScript:application programming:installing 
                   1515:     JSLib --> 
                   1516:     <!--INDEX application programming, JavaScript:installing JSLib -->
                   1517:     JavaScript libraries, install the JSLib package in Mozilla. The
                   1518:     package is available as a tarball, a zip file, or as CVS
                   1519:     sources. The easiest way to obtain it is to install it from the
                   1520:     Web using Mozilla's XPInstall technology, described in <a href=
                   1521:     "ch06.html#77063">Chapter 6</a>.</p>
                   1522:     <p>Using your Mozilla browser, go to <i><a href=
                   1523:     "http://jslib.mozdev.org/installation.html">http://jslib.mozdev.org/installation.html</a></i>
                   1524:     and click the installation hyperlink. The link uses XPInstall
                   1525:     to install JSLIB and make it available to you in Mozilla. To
                   1526:     test whether it is installed properly, type the following code
                   1527:     in your shell:</p>
                   1528: <pre>
                   1529: ./mozilla -chrome chrome://jslib/content/
                   1530: </pre>
                   1531:     <p>You should see a simple window that says "welcome to
                   1532:     jslib."</p>
                   1533:     <h4><a name="77073"></a> The JSLib libraries</h4>
                   1534:     <p>Currently <!--INDEX classes:JSLib --> 
                   1535:     <!--INDEX JSLib libraries:classes --> 
                   1536:     <!--INDEX JavaScript:application programming:JSLib classes --> 
                   1537:     <!--INDEX application programming, JavaScript:JSLib classes -->
                   1538:     available JavaScript functions in the JSLib package are divided
                   1539:     into different modules that, in turn, are divided into
                   1540:     different classes defined in source files such as
                   1541:     <i>file.js</i>, <i>dir.js</i>, and <i>fileUtils.js</i>. <a
                   1542:     href="#77010">Table 5-1</a> describes the basic classes in the
                   1543:     JSLib package's I/O module and describes how they are used.</p>
                   1544:     <p><i>Table 5-1: <a name="77010"></a></i><i>JSLib
                   1545:     classes</i></p>
                   1546:     <table width="100%" border="1">
                   1547:       <tbody>
                   1548:         <tr>
                   1549:           <td><b>Class / (filename)</b></td>
                   1550:           <td><b>Description</b></td>
                   1551:         </tr>
                   1552:         <tr>
                   1553:           <td>File / (<i>file.js</i>)</td>
                   1554:           <td>Contains most routines associated with the File
                   1555:           object (implementing <tt>nsIFile</tt>). The library is
                   1556:           part of the jslib I/O module.</td>
                   1557:         </tr>
                   1558:         <tr>
                   1559:           <td>FileUtils / (<i>fileUtils.js</i>)</td>
                   1560:           <td>The chrome registry to local file path conversion,
                   1561:           file metadata, etc.</td>
                   1562:         </tr>
                   1563:         <tr>
                   1564:           <td>Dir / (<i>dir.js</i>)</td>
                   1565:           <td>Directory creation; variations of directory
                   1566:           listings.</td>
                   1567:         </tr>
                   1568:         <tr>
                   1569:           <td>DirUtils / (<i>dirUtils.js</i>)</td>
                   1570:           <td>Paths to useful Mozilla directories and files such as
                   1571:           <i>chrome</i>, <i>prefs</i>, <i>bookmarks</i>,
                   1572:           <i>localstore</i>, etc.</td>
                   1573:         </tr>
                   1574:       </tbody>
                   1575:     </table>
                   1576:     <br>
                   1577:     <br>
                   1578:      
                   1579:     <h4><a name="77074"></a> Using the File class</h4>
                   1580:     <p>The JSLib <tt>File</tt> <!--INDEX classes:JSLib:File --> 
                   1581:     <!--INDEX File class, JSLib --> 
                   1582:     <!--INDEX JSLib libraries:File class --> 
                   1583:     <!--INDEX JavaScript:application programming:JSLib File class -->
                   1584:     <!--INDEX application programming, JavaScript:JSLib File class -->
                   1585:     class exposes most local file routines from the <i>nsIFile</i>
                   1586:     interface. The <tt>File</tt> class is part of the JSLib I/O
                   1587:     module, and is defined in <i>jslib/io/file.js</i>. Here is how
                   1588:     you load the library from xpcshell:</p>
                   1589: <pre>
                   1590: $ ./run-mozilla.sh ./xpcshell -w -s
1.5       petejc   1591: js&gt; load('chrome/jslib/jslib.js');
1.1       david    1592: *********************
                   1593: JS_LIB DEBUG IS ON
                   1594: *********************
1.12      petejc   1595: js&gt;
                   1596: </pre>
                   1597:     <p>Once JSLib is loaded, you can load the <tt>File</tt> module
                   1598:     with an <tt>include</tt> statement:</p>
                   1599: <pre>
                   1600: js&gt; include(`chrome://jslib/content/io/file.js');
1.1       david    1601: *** Chrome Registration of package: Checking for contents.rdf at
                   1602: resource:/chrome/jslib/
                   1603: *** load: filesystem.js OK
                   1604: *** load: file.js OK
                   1605: true
1.12      petejc   1606: js&gt;
                   1607: </pre>
                   1608:     <p>Note that <i>file.js</i> loads <i>filesystem.js</i> in turn.
                   1609:     The class <tt>FileSystem</tt> in <i>filesystem.js</i> is the
                   1610:     base class for the <tt>File</tt> object. You can also load
                   1611:     <i>file.js</i> by using the top-level construct
                   1612:     <tt>JS_LIB_PATH</tt>:</p>
                   1613: <pre>
                   1614: js&gt; include(JS_LIB_PATH+'io/file.js');
                   1615: </pre>
                   1616:     <p>Once you have the <i>file.js</i> module loaded, you can
                   1617:     create an instance of a <tt>File</tt> object and call methods
                   1618:     on it to manipulate the file and path it represents:</p>
                   1619: <pre>
                   1620: js&gt; var f = new File('/tmp/foo');
1.1       david    1621: js&gt; f;
                   1622: [object Object]
                   1623: js&gt; f.help; // listing of everything available to the object
                   1624: . . .
                   1625: js&gt; f.path;
                   1626: /tmp/foo
                   1627: js&gt; f.exists( );   // see if /tmp/foo exists
                   1628: false
                   1629: js&gt; f.create( );   // it doesn't, so create it.
                   1630: js&gt; f.exists( );
                   1631: true
                   1632: js&gt; f.isFile( );   // is it a file?
                   1633: true
                   1634: js&gt; f.open('w');  // open the file for writing
                   1635: true
                   1636: js&gt; f.write('this is line #1\n');
                   1637: true
                   1638: js&gt; f.close( );
                   1639: js&gt; f.open( );     // open the file again and
                   1640: js&gt; f.read( );     // read back the data
                   1641: // you can also use default flag 'r' for reading
                   1642: this is line #1
1.12      petejc   1643: js&gt; f.close( );
                   1644: </pre>
                   1645:     <p>You can also assign the contents of the file to a variable
                   1646:     for later use, iterative loops through the file contents, or
                   1647:     updates to the data:</p>
                   1648: <pre>
                   1649: js&gt; f.open( );
1.1       david    1650: true
                   1651: js&gt; var contents = f.read( );
                   1652: js&gt; f.close( );
                   1653: js&gt; print(contents);
                   1654: this is line #1
                   1655: js&gt;
                   1656: // rename the file
                   1657: js&gt; f.move(`/tmp/foo.dat');
                   1658: foo.dat
                   1659: filesystem.js:move successful!
                   1660: js&gt; f.path;
1.12      petejc   1661: /tmp/foo.dat
                   1662: </pre>
                   1663:     <p>These examples show some ways the JSLib <tt>File</tt> object
                   1664:     can manipulate local files. Using these interfaces can make
                   1665:     life a lot easier by letting you focus on creating your Mozilla
                   1666:     application without having to implement XPCOM <tt>nsIFile</tt>
                   1667:     objects manually from your script.</p>
                   1668:     <h4><a name="77075"></a> Using the FileUtils class</h4>
                   1669:     <p>To create an <!--INDEX classes:JSLib:FileUtils --> 
                   1670:     <!--INDEX FileUtils class, JSLib --> 
                   1671:     <!--INDEX JSLib libraries:FileUtils class --> 
                   1672:     <!--INDEX JavaScript:application programming:JSLib FileUtils class -->
                   1673:     <!--INDEX application programming, JavaScript:JSLib FileUtils class -->
                   1674:     instance of the <tt>FileUtils</tt> class, use the
                   1675:     <tt>FileUtils</tt> constructor:</p>
                   1676: <pre>
                   1677: js&gt; var fu = new FileUtils( );
1.1       david    1678: js&gt; fu;
1.12      petejc   1679: [object Object]
                   1680: </pre>
                   1681:     <p>Then look at the object by calling its <tt>help</tt>
                   1682:     method:</p>
                   1683: <pre>
                   1684: js&gt; fu.help;
                   1685: </pre>
                   1686:     <p>The difference between using the <i>File</i> and
                   1687:     <i>FileUtils</i> interfaces is that methods and properties on
                   1688:     the latter are <i>singleton</i> and require a path argument,
                   1689:     while the <i>FileUtils</i> utilities are general purpose and
                   1690:     not bound to any particular file. The <i>FileUtils</i>
                   1691:     interface has several handy I/O utilities for converting,
                   1692:     testing, and using URLs, of which this example shows a few:</p>
                   1693: <pre>
                   1694: js&gt; fu.exists('/tmp');
1.1       david    1695: true
                   1696: // convert a chrome path to a url
                   1697: js&gt; fu.chromeToPath('chrome://jslib/content/');
                   1698: /usr/src/mozilla/dist/bin/chrome/jslib/jslib.xul
                   1699: // convert a file URL path to a local file path
                   1700: js&gt; fu.urlToPath('file:///tmp/foo.dat');
1.12      petejc   1701: /tmp/foo.dat
                   1702: </pre>
                   1703:     <p>Most methods on the <tt>FileUtils</tt> objects are identical
                   1704:     to the methods found in <i>file.js</i>, except they require a
                   1705:     path argument. Another handy method in the <tt>FileUtils</tt>
                   1706:     class is <tt>spawn</tt>, which spawns an external executable
                   1707:     from the operating system. It's used as follows:</p>
                   1708: <pre>
                   1709: js&gt; fu.spawn('/usr/X11R6/bin/Eterm');
                   1710: </pre>
                   1711:     <p>This command spawns a new Eterm with no argument. To open an
                   1712:     Eterm with vi, you could also use this code:</p>
                   1713: <pre>
                   1714: js&gt; fu.spawn('/usr/X11R6/bin/Eterm', ['-e/usr/bin/vi']);
                   1715: </pre>
                   1716:     <p>Checking to see if three different files exist would take
                   1717:     several lines when using the File class, but the
                   1718:     <tt>FileUtils</tt> class is optimized for this type of check,
                   1719:     as the following listing shows:</p>
                   1720: <pre>
                   1721: js&gt; var fu=new FileUtils( );
1.1       david    1722: js&gt; fu.exists('/tmp');
                   1723: true
                   1724: js&gt; fu.exists('/tmp/foo.dat');
                   1725: true
                   1726: js&gt; fu.exists('/tmp/foo.baz');
1.12      petejc   1727: false
                   1728: </pre>
                   1729:     <p>You need to initialize the <tt>FileUtils</tt> class only
                   1730:     once to use its members and handle local files robustly.</p>
                   1731:     <h4><a name="77076"></a> Using the Dir class</h4>
                   1732:     <p>The <tt>Dir</tt> <!--INDEX classes:JSLib:Dir --> 
                   1733:     <!--INDEX Dir class, JSLib --> 
                   1734:     <!--INDEX JSLib libraries:Dir class --> 
                   1735:     <!--INDEX JavaScript:application programming:JSLib Dir class -->
                   1736:     <!--INDEX application programming, JavaScript:JSLib Dir class -->
                   1737:     class is custom-made for working with directory structures on a
                   1738:     local filesystem. To create an instance of the <tt>Dir</tt>
                   1739:     class, call its constructor and then its <tt>help</tt> method
                   1740:     to see the class properties:</p>
                   1741: <pre>
                   1742: js&gt; var d = new Dir('/tmp');
                   1743: js&gt; d.help;
                   1744: </pre>
                   1745:     <p><tt>Dir</tt> inherits from the same base class as
                   1746:     <tt>File</tt>, which is why it looks similar, but it implements
                   1747:     methods used specifically for directory manipulation:</p>
                   1748: <pre>
                   1749: js&gt; d.path;
1.1       david    1750: /tmp
                   1751: js&gt; d.exists( );
                   1752: true
                   1753: js&gt; d.isDir( );
1.12      petejc   1754: true
                   1755: </pre>
                   1756:     <p>The methods all work like those in the <tt>File</tt> and
                   1757:     <tt>FileUtils</tt> classes, so you can append a new directory
                   1758:     name to the object, see if it exists, and create it if (it does
                   1759:     not) by entering:</p>
                   1760: <pre>
                   1761: js&gt; d.append('newDir');
1.1       david    1762: /tmp/newDir
                   1763: js&gt; d.path;
                   1764: /tmp/newDir
                   1765: js&gt; d.exists( );
                   1766: false
                   1767: js&gt; d.create( );
                   1768: js&gt; d.exists( );
1.12      petejc   1769: true
                   1770: </pre>
                   1771:     <h4><a name="77077"></a> Using the DirUtils class</h4>
                   1772:     <p>Note that <!--INDEX classes:JSLib:DirUtils --> 
                   1773:     <!--INDEX DirUtils class, JSLib --> 
                   1774:     <!--INDEX JSLib libraries:DirUtils class --> 
                   1775:     <!--INDEX JavaScript:application programming:JSLib DirUtils class -->
                   1776:     <!--INDEX application programming, JavaScript:JSLib DirUtils class -->
                   1777:     some methods in the <tt>DirUtils</tt> class cannot be called
                   1778:     from xpcshell and instead must be called from a XUL window into
                   1779:     which the proper JSLib source file was imported. The following
                   1780:     XUL file provides two buttons that display information in
                   1781:     textboxes about the system directories:</p>
                   1782: <pre>
                   1783: &lt;?xml version="1.0"?&gt;
1.1       david    1784: &lt;?xml-stylesheet href="chrome://global/skin" type="text/css"?&gt;
1.12      petejc   1785: &lt;window xmlns="<a href=
                   1786: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul</a>"
                   1787: xmlns:html="<a href=
                   1788: "http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>"
1.1       david    1789: id="dir-utils-window"
                   1790: orient="vertical"
                   1791: autostretch="never"&gt;
                   1792: &lt;script type="application/x-javascript" src="chrome://jslib/content/io/dirUtils.js"/&gt;
                   1793: &lt;script&gt;
                   1794: var du = new DirUtils( );
                   1795: function getChromeDir( ) {
                   1796: cd = du.getChromeDir( );
                   1797: textfield1 = document.getElementById("tf1");
                   1798: textfield1.setAttribute("value", cd);
                   1799: }
                   1800: function getMozDir( ) {
                   1801: md =   du.getMozHomeDir( );
                   1802: textfield2 = document.getElementById("tf2");
                   1803: textfield2.setAttribute("value", md);
                   1804: }
                   1805: &lt;/script&gt;
                   1806: &lt;box&gt;
                   1807: &lt;button id="chrome" onclick="getChromeDir( );" label="chrome" /&gt;
                   1808: &lt;textbox id="tf1" value="chrome dir" /&gt;
                   1809: &lt;/box&gt;
                   1810: &lt;box&gt;
                   1811: &lt;button id="moz" onclick="getMozDir( );" label="mozdir" /&gt;
                   1812: &lt;textbox id="tf2" value="moz dir" /&gt;
                   1813: &lt;/box&gt;
1.12      petejc   1814: &lt;/window&gt;
                   1815: </pre>
                   1816:     <hr>
                   1817:     <hr>
                   1818:     <a name="260"></a><a href="#b260">[Back]</a> <a name=
                   1819:     "77034"></a> This book does not pretend to give a complete
                   1820:     overview of JavaScript. You can view the full JavaScript 1.5
                   1821:     reference online at <i><a href=
                   1822:     "http://developer.netscape.com/docs/manuals/index.html?content=javascript.html">
                   1823:     http://developer.netscape.com/docs/manuals/index.html?content=javascript.html</a></i>.
                   1824:     
                   1825:     <hr>
                   1826:     <a name="261"></a><a href="#b261">[Back]</a> <a name=
                   1827:     "77035"></a> The third edition of the EMCA-262 EMCAScript
                   1828:     Language Specification can be found at <i><a href=
                   1829:     "http://www.ecma.ch/ecma1/STAND/ECMA-262.HTM">http://www.ecma.ch/ecma1/STAND/ECMA-262.HTM</a>.</i>
                   1830:     
                   1831:     <hr>
                   1832:     <a name="262"></a><a href="#b262">[Back]</a> <a name=
                   1833:     "77036"></a> You can use other DOM methods, but these methods
                   1834:     are most commonly used in the XPFE. Mozilla's support for the
                   1835:     DOM is so thorough that you can use the W3C specifications as a
                   1836:     list of methods and properties available to you in the chrome
                   1837:     and in the web content the browser displays. The full W3C
                   1838:     activity pages, including links to the specifications
                   1839:     implemented by Mozilla, can be found at <i><a href=
                   1840:     "http://www.w3.org/DOM/">http://www.w3.org/DOM/</a></i> . 
                   1841:     <hr>
                   1842:     <br>
                   1843:     <br>
                   1844:     File a <a href=
                   1845:     "http://mozdev.org/bugs/enter_bug.cgi?product=books">Bug</a>
1.20      petejc   1846:     for chapter 5. 
1.23    ! cdn      1847:     <?php $hide_text_control=1; $post_to_list=NO; $author='reviewers@mozdev.org'; $target_page='ch05'; require(NOTES); ?>

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>