Diff for /books/www/chapters/ch05.html between versions 1.2 and 1.19

version 1.2, 2002/09/23 15:23:31 version 1.19, 2002/12/17 13:13:19
Line 1 Line 1
<HTML>    <link rel="prev" href="http://books.mozdev.org/chapters/ch04.html" />
<HEAD><TITLE>Chapter 5</TITLE></HEAD><BODY BGCOLOR=WHITE><H2>Chapter 5</H2>    <link rel="next" href="http://books.mozdev.org/chapters/ch06.html" />
<H1><A NAME="77037"></A> Scripting Mozilla</H1> 
<P>In Mozilla, scripting plays important roles in the XPFE. Whether developers refer to script access and security, user interface logic, XPCOM object invocation, or script execution in element event handlers, scripting is so integral to application development that Mozilla, as a development platform, would be inconceivable without it. 
<P>The core scripting language used in Mozilla is JavaScript. Although it has had a reputation as an unsophisticated language used mostly in web pages, JavaScript is more like a first-tier programming language. Modularity, good exception handing, regular expression enhancement, and number formatting are just some features of the new JavaScript 1.5,<A NAME="b260"></A><A HREF="#260">[*]</A> which is based on the ECMA-262 standard.<A NAME="b261"></A><A HREF="#261">[*]</A> JavaScript 2.0, due sometime late in 2002, promises to be an even bigger promotion of the language. 
<P>Three distinct levels of JavaScript are identified in this chapter. A user interface level manipulates content through the DOM, a client layer calls on the services provided by XPCOM, and, finally, an application layer is available in which JavaScript can create an XPCOM component. The following section describes these levels in detail. 
<H2><A NAME="77038"></A> Faces of JavaScript in Mozilla</H2> 
<P>As you have already  <!--INDEX scripting:JavaScript, overview -->  <!--INDEX JavaScript:overview --> seen in some examples in this book, the user interface uses JavaScript extensively to create behavior and to glue various widgets together into a coherent whole. When you add code to the event handler of one element to manipulate another-for example, when you update the value of a textbox using a XUL button-you take advantage of this first "level" of scriptability. In this role, JavaScript uses the Document Object Model (DOM) to access parts of the user interface as a hierarchical collection of objects. The section <A HREF="#77054">"Adding Scripts to the UI</A>," later in this chapter, discusses this highest level of scripting. 
<P>At a second level, JavaScript glues the entire user interface to the XPCOM libraries beneath, which create the application core. At this level, XPConnect (see the section <A HREF="#77066">"What Is XPConnect?</A>" later in this chapter) provides a bridge that makes these components "scriptable," which means that they can be invoked from JavaScript and used from the user interface layer. When JavaScript calls methods and gets data from scriptable components, it uses this second layer of scriptability. 
<P>Finally, at the third and ultimate level of Mozilla scripting, JavaScript can be used as a "first-order" language for creating the application  
core itself, for writing software components or libraries whose services are called. We discuss this third level of scripting and provide a long  
example in the section <A HREF="ch08.html#77065">"Creating a JavaScript XPCOM Component</A>" in <A HREF="ch08.html#77048">Chapter 8</A>. 
<P>When you use JavaScript in these contexts, the application architecture looks something like <A HREF="#77002">Figure 5-1</A>, in which scripting binds the user interface to the application core through XPConnect and can reside as a software component using such technologies as XPIDL and XPCOM. 
<P><CENTER><IMG SRC="foo.gif"></CENTER> 
<P><I>Figure 5-1: <A NAME="77002"></A></I> 
<I>Scripting in Mozilla</I> 
   
<H2><A NAME="77039"></A> JavaScript and the DOM</H2>    <style type="text/css">
<P>In the application  <!--INDEX DOM (Document Object Model):overview --> layer of Mozilla, there is little distinction between a web page and the graphical user interface. Mozilla's implementation of the DOM is fundamentally the same for both XUL and HTML. In both cases, state changes and events are propagated through various DOM calls, meaning that the UI itself is content-not unlike that of a web page. In application development, where the difference between application "chrome" and rendered content is typically big, this uniformity is a significant step forward.      div.c15 {font-weight: bold; text-align: center}
<H3><A NAME="77040"></A> What Is the DOM?</H3>      div.c14 {text-align: center}
<P>The DOM is an API used to access HTML and XML documents. It does two things for web developers: provides a structural representation of the document and defines the way the structure should be accessed from script. In the Mozilla XPFE framework, this functionality allows you to manipulate the user interface as a structured group of nodes, create new UI and content, and remove elements as needed.    </style>
<P>Because it is designed to access arbitrary HTML and XML, the DOM applies not only to XUL, but also to MathML, SVG, and other XML markup. By connecting web pages and XML documents to scripts or programming languages, the DOM is not a particular application, product, or proprietary ordering of web pages. Rather, it is an <I>API-</I>an interface that vendors must implement if their products are to conform to the W3C DOM standard. Mozilla's commitment to standards ensures that its applications and tools do just that.
<P>When you use JavaScript to create new elements in an HTML file or change the attributes of a XUL <TT>button</TT>, you access an object model in which these structures are organized. This model is the DOM for that document or data. The DOM provides a context for the scripting language to operate in. The specific context for web and XML documents-the top-level <TT>window</TT> object, the elements that make up a web document, and the data stored in those elements as children-is standardized in several different specifications, the most recent of which is the upcoming DOM Level 3 standard.    <h2>Chapter 5</h2>
<H3><A NAME="77041"></A> The DOM Standards and Mozilla</H3>    <h1><a name="77037"></a> Scripting Mozilla</h1>
<P>The DOM  <!--INDEX DOM (Document Object Model):levels -->  <!--INDEX standards, DOM levels --> specifications are split into different levels overseen by the W3C. Each level provides its own features and Mozilla has varying, but nearly complete, levels of support for each. Currently, Mozilla's support for the DOM can be summarized as follows:    <p>In Mozilla, scripting plays important roles in the XPFE.
<UL><P><LI>DOM Level 1: Excellent<P>    Whether developers refer to script access and security, user
<P><LI>DOM Level 2: Good<P>    interface logic, XPCOM object invocation, or script execution
<P><LI>DOM Level 3: Poor; under construction<P></UL>    in element event handlers, scripting is so integral to
<P>Mozilla strives to be standards-compliant, but typically reaches full support only when those standards have become recommendations rather than working drafts. Currently, Level 1 and Level 2 are recommendations and Level 3 is a working draft.    application development that Mozilla, as a development
<P>Standards like the DOM make Mozilla an especially attractive software development kit (SDK) for web developers. The same layout engine that renders web content also draws the GUI and pushes web development out of the web page into the application chrome. The DOM provides a consistent, unified interface for accessing all the documents you develop, making the content and chrome accessible for easy cross-platform development and deployment.    platform, would be inconceivable without it.</p>
<H3><A NAME="77042"></A> DOM Methods and Properties</H3>    <p>The core scripting language used in Mozilla is JavaScript.
<P>Methods in  <!--INDEX DOM (Document Object Model):methods -->  <!--INDEX methods:DOM --> the DOM allow you to access and manipulate any element in the user interface or in the content of a web page. Getting and setting attributes, creating elements, hiding elements, and appending children all involve direct manipulation of the DOM. The DOM mediates all interaction between scripts and the interface itself, so even when you do something as simple as changing an image when the user clicks a button, you use the DOM to register an event handler with the <TT>button</TT> and DOM attributes on the <TT>image</TT> element to change its source.    Although it has had a reputation as an unsophisticated language
<P>The DOM Level 1 and Level 2 Core specifications contain multiple interfaces, including <I>Node</I>, <I>NodeList</I>, <I>Element</I>, and <I>Document</I>. The following sections describe some interface methods used to manipulate the object model of application chrome, documents, or metadata in Mozilla. The <I>Document</I> and <I>Element</I> interfaces, in particular, contain useful methods for XUL developers.    used mostly in web pages, JavaScript is more like a first-tier
<H4><A NAME="77043"></A> Using dump( ) to print to STDOUT</H4>    programming language. Modularity, good exception handing,
<P>The code  <!--INDEX STDOUT, printing and -->  <!--INDEX printing, STDOUT -->  <!--INDEX dump( ) method -->  <!--INDEX DOM (Document Object Model):methods:printing STDOUT -->  <!--INDEX methods:DOM:printing STDOUT --> samples in this chapter use a method called <TT>dump( )</TT> to print data to STDOUT. This method is primarily used for debugging your code and is turned on using a <TT>PREF</TT>. You can turn this <TT>PREF</TT> on using the following code:    regular expression enhancement, and number formatting are just
<PRE>const PREFS_CID      = "@mozilla.org/preferences;1";    some features of the new JavaScript 1.5,<a name="b260"></a><a
     href="#260">[*]</a> which is based on the ECMA-262 standard.<a
     name="b261"></a><a href="#261">[*]</a> JavaScript 2.0, due
     sometime late in 2002, promises to be an even bigger promotion
     of the language.</p>
     <p>Three distinct levels of JavaScript are identified in this
     chapter. A user interface level manipulates content through the
     DOM, a client layer calls on the services provided by XPCOM,
     and, finally, an application layer is available in which
     JavaScript can create an XPCOM component. The following section
     describes these levels in detail.</p>
     <h2><a name="77038"></a> Faces of JavaScript in Mozilla</h2>
     <p>As you have already 
     <!--INDEX scripting:JavaScript, overview --> 
     <!--INDEX JavaScript:overview --> seen in some examples in this
     book, the user interface uses JavaScript extensively to create
     behavior and to glue various widgets together into a coherent
     whole. When you add code to the event handler of one element to
     manipulate another-for example, when you update the value of a
     textbox using a XUL button-you take advantage of this first
     "level" of scriptability. In this role, JavaScript uses the
     Document Object Model (DOM) to access parts of the user
     interface as a hierarchical collection of objects. The section
     <a href="#77054">"Adding Scripts to the UI</a>," later in this
     chapter, discusses this highest level of scripting.</p>
     <p>At a second level, JavaScript glues the entire user
     interface to the XPCOM libraries beneath, which create the
     application core. At this level, XPConnect (see the section <a
     href="#77066">"What Is XPConnect?</a>" later in this chapter)
     provides a bridge that makes these components "scriptable,"
     which means that they can be invoked from JavaScript and used
     from the user interface layer. When JavaScript calls methods
     and gets data from scriptable components, it uses this second
     layer of scriptability.</p>
     <p>Finally, at the third and ultimate level of Mozilla
     scripting, JavaScript can be used as a "first-order" language
     for creating the application core itself, for writing software
     components or libraries whose services are called. We discuss
     this third level of scripting and provide a long example in the
     section <a href="ch08.html#77065">"Creating a JavaScript XPCOM
     Component</a>" in <a href="ch08.html#77048">Chapter 8</a>.</p>
     <p>When you use JavaScript in these contexts, the application
     architecture looks something like <a href="#77002">Figure
     5-1</a>, in which scripting binds the user interface to the
     application core through XPConnect and can reside as a software
     component using such technologies as XPIDL and XPCOM.</p>
     <div class="c14">
       <img src="foo.gif">
     </div>
     <p><i>Figure 5-1: <a name="77002"></a></i> <i>Scripting in
     Mozilla</i></p>
     <h2><a name="77039"></a> JavaScript and the DOM</h2>
     <p>In the application 
     <!--INDEX DOM (Document Object Model):overview --> layer of
     Mozilla, there is little distinction between a web page and the
     graphical user interface. Mozilla's implementation of the DOM
     is fundamentally the same for both XUL and HTML. In both cases,
     state changes and events are propagated through various DOM
     calls, meaning that the UI itself is content-not unlike that of
     a web page. In application development, where the difference
     between application "chrome" and rendered content is typically
     big, this uniformity is a significant step forward.</p>
     <h3><a name="77040"></a> What Is the DOM?</h3>
     <p>The DOM is an API used to access HTML and XML documents. It
     does two things for web developers: provides a structural
     representation of the document and defines the way the
     structure should be accessed from script. In the Mozilla XPFE
     framework, this functionality allows you to manipulate the user
     interface as a structured group of nodes, create new UI and
     content, and remove elements as needed.</p>
     <p>Because it is designed to access arbitrary HTML and XML, the
     DOM applies not only to XUL, but also to MathML, SVG, and other
     XML markup. By connecting web pages and XML documents to
     scripts or programming languages, the DOM is not a particular
     application, product, or proprietary ordering of web pages.
     Rather, it is an <i>API-</i>an interface that vendors must
     implement if their products are to conform to the W3C DOM
     standard. Mozilla's commitment to standards ensures that its
     applications and tools do just that.</p>
     <p>When you use JavaScript to create new elements in an HTML
     file or change the attributes of a XUL <tt>button</tt>, you
     access an object model in which these structures are organized.
     This model is the DOM for that document or data. The DOM
     provides a context for the scripting language to operate in.
     The specific context for web and XML documents-the top-level
     <tt>window</tt> object, the elements that make up a web
     document, and the data stored in those elements as children-is
     standardized in several different specifications, the most
     recent of which is the upcoming DOM Level 3 standard.</p>
     <h3><a name="77041"></a> The DOM Standards and Mozilla</h3>
     <p>The DOM <!--INDEX DOM (Document Object Model):levels --> 
     <!--INDEX standards, DOM levels --> specifications are split
     into different levels overseen by the W3C. Each level provides
     its own features and Mozilla has varying, but nearly complete,
     levels of support for each. Currently, Mozilla's support for
     the DOM can be summarized as follows:</p>
     <ul>
       <li>DOM Level 1: Excellent</li>
       <li>DOM Level 2: Good</li>
       <li>DOM Level 3: Poor; under construction</li>
     </ul>
     <p>Mozilla strives to be standards-compliant, but typically
     reaches full support only when those standards have become
     recommendations rather than working drafts. Currently, Level 1
     and Level 2 are recommendations and Level 3 is a working
     draft.</p>
     <p>Standards like the DOM make Mozilla an especially attractive
     software development kit (SDK) for web developers. The same
     layout engine that renders web content also draws the GUI and
     pushes web development out of the web page into the application
     chrome. The DOM provides a consistent, unified interface for
     accessing all the documents you develop, making the content and
     chrome accessible for easy cross-platform development and
     deployment.</p>
     <h3><a name="77042"></a> DOM Methods and Properties</h3>
     <p>Methods in <!--INDEX DOM (Document Object Model):methods -->
     <!--INDEX methods:DOM --> the DOM allow you to access and
     manipulate any element in the user interface or in the content
     of a web page. Getting and setting attributes, creating
     elements, hiding elements, and appending children all involve
     direct manipulation of the DOM. The DOM mediates all
     interaction between scripts and the interface itself, so even
     when you do something as simple as changing an image when the
     user clicks a button, you use the DOM to register an event
     handler with the <tt>button</tt> and DOM attributes on the
     <tt>image</tt> element to change its source.</p>
     <p>The DOM Level 1 and Level 2 Core specifications contain
     multiple interfaces, including <i>Node</i>, <i>NodeList</i>,
     <i>Element</i>, and <i>Document</i>. The following sections
     describe some interface methods used to manipulate the object
     model of application chrome, documents, or metadata in Mozilla.
     The <i>Document</i> and <i>Element</i> interfaces, in
     particular, contain useful methods for XUL developers.</p>
     <h4><a name="77043"></a> Using dump( ) to print to STDOUT</h4>
     <p>The code <!--INDEX STDOUT, printing and --> 
     <!--INDEX printing, STDOUT --> <!--INDEX dump( ) method --> 
     <!--INDEX DOM (Document Object Model):methods:printing STDOUT -->
     <!--INDEX methods:DOM:printing STDOUT --> samples in this
     chapter use a method called <tt>dump( )</tt> to print data to
     STDOUT. This method is primarily used for debugging your code
     and is turned on using a <tt>PREF</tt>. You can turn this
     <tt>PREF</tt> on using the following code:</p>
 <pre>
 const PREFS_CID      = "@mozilla.org/preferences;1";
 const PREFS_I_PREF   = "nsIPref";  const PREFS_I_PREF   = "nsIPref";
 const PREF_STRING    = "browser.dom.window.dump.enabled";  const PREF_STRING    = "browser.dom.window.dump.enabled";
 try {  try {
 var Pref        = new Components.Constructor(PREFS_CID, PREFS_I_PREF);  var Pref        = new Components.Constructor(PREFS_CID, PREFS_I_PREF);
 var pref        = new Pref( );  var pref        = new Pref( );
 pref.SetBoolPref(PREF_STRING, true);  pref.SetBoolPref(PREF_STRING, true);
} catch(e) {}</PRE>} catch(e) {}
<P>This code is necessary only if you are doing development with a release distribution build of Mozilla. If you are using a debug or nightly build, this <TT>PREF</TT> can be set from the preferences panel by selecting Edit &gt; Preferences &gt; Debug &gt; Enable JavaScript dump( ) output.</pre>
<H4><A NAME="77044"></A> getElementById</H4>    <p>This code is necessary only if you are doing development
<P><TT>getElementById(aId)</TT> is <!--INDEX elements:referencing -->  <!--INDEX referencing:elements -->  <!--INDEX getElementById( ) method -->  <!--INDEX DOM (Document Object Model):methods:referencing elements -->  <!--INDEX methods:DOM:referencing elements -->  perhaps the most commonly used DOM method in any programming domain. This is a convenient way to get a reference to an element object by passing that element's <TT>id</TT> as an argument, where the <TT>id</TT> acts as a unique identifier for that element.    with a release distribution build of Mozilla. If you are using
<P>DOM calls like this are at the heart of Mozilla UI functionality. <TT>getElementById</TT> is the main programmatic entry point into the chrome and is essential for any dynamic manipulation of XUL elements. For example, to get a box element in script (i.e., to get a reference to it so you can call its methods or read data from it), you must refer to it by using the box <TT>id</TT>:    a debug or nightly build, this <tt>PREF</tt> can be set from
<PRE>&lt;box id="my-id" /&gt;</PRE>    the preferences panel by selecting Edit &gt; Preferences &gt;
<P>Since the return value of <TT>getElementById</TT> is a reference to the specified element object, you usually assign it to a variable like this:    Debug &gt; Enable JavaScript dump( ) output.</p>
<PRE>var boxEl = document.getElementById('my-id');    <h4><a name="77044"></a> getElementById</h4>
     <p><tt>getElementById(aId)</tt> is 
     <!--INDEX elements:referencing --> 
     <!--INDEX referencing:elements --> 
     <!--INDEX getElementById( ) method --> 
     <!--INDEX DOM (Document Object Model):methods:referencing elements -->
     <!--INDEX methods:DOM:referencing elements --> perhaps the most
     commonly used DOM method in any programming domain. This is a
     convenient way to get a reference to an element object by
     passing that element's <tt>id</tt> as an argument, where the
     <tt>id</tt> acts as a unique identifier for that element.</p>
     <p>DOM calls like this are at the heart of Mozilla UI
     functionality. <tt>getElementById</tt> is the main programmatic
     entry point into the chrome and is essential for any dynamic
     manipulation of XUL elements. For example, to get a box element
     in script (i.e., to get a reference to it so you can call its
     methods or read data from it), you must refer to it by using
     the box <tt>id</tt>:</p>
 <pre>
 &lt;box id="my-id" /&gt;
 </pre>
     <p>Since the return value of <tt>getElementById</tt> is a
     reference to the specified element object, you usually assign
     it to a variable like this:</p>
 <pre>
 var boxEl = document.getElementById('my-id');
 dump("boxEl="+boxEl+"\n");  dump("boxEl="+boxEl+"\n");
console output: boxEl=[object XULElement]</PRE>console output: boxEl=[object XULElement]
<P>Once you have the box element available as <TT>boxEl</TT>, you can use other DOM methods like <TT>getAttribute</TT> and <TT>setAttribute</TT> to change its layout, its position, its state, or other features.</pre>
<H4><A NAME="77045"></A> getAttribute</H4>    <p>Once you have the box element available as <tt>boxEl</tt>,
<P>Attributes  <!--INDEX attributes:referencing -->  <!--INDEX referencing:attributes -->  <!--INDEX getAttribute( ) method -->  <!--INDEX DOM (Document Object Model):methods:referencing attributes -->  <!--INDEX methods:DOM:referencing attributes --> are properties that are defined directly on an element. XUL elements have attributes such as <TT>disabled</TT>, <TT>height</TT>, <TT>style</TT>, <TT>orient</TT>, and <TT>label</TT>.    you can use other DOM methods like <tt>getAttribute</tt> and
<PRE>&lt;box id="my-id" foo="hello 1" bar="hello 2" /&gt;</PRE>    <tt>setAttribute</tt> to change its layout, its position, its
<P>In the snippet above, the strings "my-id," "hello 1," and "hello 2" are values of the box element attributes. Note that Gecko does not enforce a set of attributes for XUL elements. XUL documents must be well-formed, but they are not validated against any particular XUL DTD or schema. This lack of enforcement means that attributes can be placed on elements ad hoc. Although this placement can be confusing, particularly when you look at the source code for the Mozilla browser itself, it can be very helpful when you create your own applications and want to track the data that interests you.    state, or other features.</p>
<P>Once you have an object assigned to a variable, you can use the DOM method <TT>getAttribute</TT> to get a reference to any attribute in that object. The <TT>getAttribute</TT> method takes the name of the desired attribute as a string. For example, if you add an attribute called <TT>foo</TT> to a box element, you can access that attribute's value and assign it to a variable:    <h4><a name="77045"></a> getAttribute</h4>
<PRE>&lt;box id="my-id" foo="this is the foo attribute" /&gt;    <p>Attributes <!--INDEX attributes:referencing --> 
     <!--INDEX referencing:attributes --> 
     <!--INDEX getAttribute( ) method --> 
     <!--INDEX DOM (Document Object Model):methods:referencing attributes -->
     <!--INDEX methods:DOM:referencing attributes --> are properties
     that are defined directly on an element. XUL elements have
     attributes such as <tt>disabled</tt>, <tt>height</tt>,
     <tt>style</tt>, <tt>orient</tt>, and <tt>label</tt>.</p>
 <pre>
 &lt;box id="my-id" foo="hello 1" bar="hello 2" /&gt;
 </pre>
     <p>In the snippet above, the strings "my-id," "hello 1," and
     "hello 2" are values of the box element attributes. Note that
     Gecko does not enforce a set of attributes for XUL elements.
     XUL documents must be well-formed, but they are not validated
     against any particular XUL DTD or schema. This lack of
     enforcement means that attributes can be placed on elements ad
     hoc. Although this placement can be confusing, particularly
     when you look at the source code for the Mozilla browser
     itself, it can be very helpful when you create your own
     applications and want to track the data that interests you.</p>
     <p>Once you have an object assigned to a variable, you can use
     the DOM method <tt>getAttribute</tt> to get a reference to any
     attribute in that object. The <tt>getAttribute</tt> method
     takes the name of the desired attribute as a string. For
     example, if you add an attribute called <tt>foo</tt> to a box
     element, you can access that attribute's value and assign it to
     a variable:</p>
 <pre>
 &lt;box id="my-id" foo="this is the foo attribute" /&gt;
 &lt;script&gt;  &lt;script&gt;
 var boxEl = document.getElementById('my-id');  var boxEl = document.getElementById('my-id');
<TT><I>  </I></TT>var foo   = boxEl.getAttribute('foo'); var foo   = boxEl.getAttribute('foo');
<TT><I>  </I></TT>dump(foo+'\n'); dump(foo+'\n');
&lt;/script&gt;</PRE>&lt;/script&gt;
<P>The <TT>dump</TT> method outputs the string "this is the foo attribute," which is the value of the attribute <TT>foo</TT>. You can also add or change existing attributes with the <TT>setAttribute</TT> DOM method.</pre>
<H4><A NAME="77046"></A> setAttribute</H4>    <p>The <tt>dump</tt> method outputs the string "this is the foo
<P>The <TT>setAttribute</TT>  <!--INDEX attributes:changing values -->  <!--INDEX setAttribute( ) method -->  <!--INDEX DOM (Document Object Model):methods:changing attribute values -->  <!--INDEX methods:DOM:changing attribute values --> method changes an existing attribute value. This method is useful for changing the state of an element-its visibility, size, order within a parent, layout and position, style, etc. It takes two arguments: the attribute name and the new value.    attribute," which is the value of the attribute <tt>foo</tt>.
<PRE>&lt;box id="my-id" foo="this is the foo attribute" /&gt;    You can also add or change existing attributes with the
     <tt>setAttribute</tt> DOM method.</p>
     <h4><a name="77046"></a> setAttribute</h4>
     <p>The <tt>setAttribute</tt> 
     <!--INDEX attributes:changing values --> 
     <!--INDEX setAttribute( ) method --> 
     <!--INDEX DOM (Document Object Model):methods:changing attribute values -->
     <!--INDEX methods:DOM:changing attribute values --> method
     changes an existing attribute value. This method is useful for
     changing the state of an element-its visibility, size, order
     within a parent, layout and position, style, etc. It takes two
     arguments: the attribute name and the new value.</p>
 <pre>
 &lt;box id="my-id" foo="this is the foo attribute" /&gt;
 &lt;script&gt;  &lt;script&gt;
 boxEl=document.getElementById('my-id');  boxEl=document.getElementById('my-id');
 boxEl.setAttribute('foo', 'this is the foo attribute changed');  boxEl.setAttribute('foo', 'this is the foo attribute changed');
 var foo = boxEl.getAttribute('foo');  var foo = boxEl.getAttribute('foo');
 dump(foo+'\n');  dump(foo+'\n');
&lt;/script&gt;</PRE>&lt;/script&gt;
<P>The script above outputs the string "this is the foo attribute changed" to the console. You can also use <TT>setAttribute</TT> to create a new attribute if it does not already exist:</pre>
<PRE>&lt;box id="my-id" /&gt;    <p>The script above outputs the string "this is the foo
     attribute changed" to the console. You can also use
     <tt>setAttribute</tt> to create a new attribute if it does not
     already exist:</p>
 <pre>
 &lt;box id="my-id" /&gt;
 &lt;script&gt;  &lt;script&gt;
 boxEl=document.getElementById('my-id');  boxEl=document.getElementById('my-id');
 boxEl.setAttribute('bar', 'this is the new attribute bar');  boxEl.setAttribute('bar', 'this is the new attribute bar');
&lt;/script&gt;</PRE>&lt;/script&gt;
<P>By setting an attribute that doesn't already exist, you create it dynamically, adding a value to the hierarchical representation of nodes that form the current document object. After this code is executed, the <TT>boxEl</TT> element is the same as an element whose <TT>bar</TT> attribute was hardcoded into the XUL:</pre>
<PRE>&lt;box id="my-id" bar="this is the new attribute bar" /&gt;</PRE>    <p>By setting an attribute that doesn't already exist, you
<P>These sorts of ad hoc changes give you complete control over the state of the application interface.    create it dynamically, adding a value to the hierarchical
<H4><A NAME="77047"></A> createElement</H4>    representation of nodes that form the current document object.
<P>If you  <!--INDEX elements:creating -->  <!--INDEX createElement( ) method -->  <!--INDEX DOM (Document Object Model):methods:creating elements -->  <!--INDEX methods:DOM:creating elements --> need to dynamically create an element that doesn't already exist-for example, to add a new row to a table displaying rows of information, you can use the method <TT>createElement</TT>. To create and add a text element to your box example, for example, you can use the following code:    After this code is executed, the <tt>boxEl</tt> element is the
<PRE>&lt;box id="my-id" /&gt;    same as an element whose <tt>bar</tt> attribute was hardcoded
     into the XUL:</p>
 <pre>
 &lt;box id="my-id" bar="this is the new attribute bar" /&gt;
 </pre>
     <p>These sorts of ad hoc changes give you complete control over
     the state of the application interface.</p>
     <h4><a name="77047"></a> createElement</h4>
     <p>If you <!--INDEX elements:creating --> 
     <!--INDEX createElement( ) method --> 
     <!--INDEX DOM (Document Object Model):methods:creating elements -->
     <!--INDEX methods:DOM:creating elements --> need to dynamically
     create an element that doesn't already exist-for example, to
     add a new row to a table displaying rows of information, you
     can use the method <tt>createElement</tt>. To create and add a
     text element to your box example, for example, you can use the
     following code:</p>
 <pre>
 &lt;box id="my-id" /&gt;
 &lt;script&gt;  &lt;script&gt;
 boxEl = document.getElementById('my-id');  boxEl = document.getElementById('my-id');
 var textEl  = document.createElement('description');  var textEl  = document.createElement('description');
 boxEl.appendChild(textEl);  boxEl.appendChild(textEl);
&lt;/script&gt;</PRE>&lt;/script&gt;
<P>Once you create the new element and assign it to the <TT>textEl</TT> variable, you can use <TT>appendChild</TT> to insert it into the object tree. In this case, it is appended to <TT>boxEl</TT>, which becomes the insertion point.</pre>
<BLOCKQUOTE><CENTER><B>NOTE</B></CENTER>    <p>Once you create the new element and assign it to the
<P>For mixed namespace documents like XUL and HTML, you can use a variation of <TT>createElement</TT> called <TT>createElementNS</TT>. To create a mixed namespace element, use this code:<P></BLOCKQUOTE>    <tt>textEl</tt> variable, you can use <tt>appendChild</tt> to
var node = document.createElementNS('<A HREF="http://www.w3.org/1999.xhtml">http://www.w3.org/1999.xhtml</A>', 'html:div');    insert it into the object tree. In this case, it is appended to
<BLOCKQUOTE><P>Namespace variations for other functions include <TT>setAttributeNS</TT>, <TT>getElementsByTagNameNS</TT>, and <TT>hasAttributeNS</TT>.<P></BLOCKQUOTE>    <tt>boxEl</tt>, which becomes the insertion point.</p>
<H4><A NAME="77048"></A> createTextNode</H4>    <blockquote>
<P>In  <!--INDEX text nodes, creating -->  <!--INDEX createTextNode( ) method -->  <!--INDEX DOM (Document Object Model):methods:creating text nodes -->  <!--INDEX methods:DOM:creating text nodes --> addition to setting the <TT>label</TT> attribute on an element, you can create new text in the interface by using the DOM method <TT>createTextNode</TT>, as shown in the following example:      <div class="c15">
<PRE>&lt;description id="explain" /&gt;        NOTE
       </div>
       <p>For mixed namespace documents like XUL and HTML, you can
       use a variation of <tt>createElement</tt> called
       <tt>createElementNS</tt>. To create a mixed namespace
       element, use this code:</p>
     </blockquote>
     var node = document.createElementNS('<a href=
     "http://www.w3.org/1999.xhtml">http://www.w3.org/1999.xhtml</a>',
     'html:div'); 
     <blockquote>
       <p>Namespace variations for other functions include
       <tt>setAttributeNS</tt>, <tt>getElementsByTagNameNS</tt>, and
       <tt>hasAttributeNS</tt>.</p>
     </blockquote>
     <h4><a name="77048"></a> createTextNode</h4>
     <p>In <!--INDEX text nodes, creating --> 
     <!--INDEX createTextNode( ) method --> 
     <!--INDEX DOM (Document Object Model):methods:creating text nodes -->
     <!--INDEX methods:DOM:creating text nodes --> addition to
     setting the <tt>label</tt> attribute on an element, you can
     create new text in the interface by using the DOM method
     <tt>createTextNode</tt>, as shown in the following example:</p>
 <pre>
 &lt;description id="explain" /&gt;
 &lt;script&gt;  &lt;script&gt;
 var description = document.getElementById("explain");  var description = document.getElementById("explain");
 if (description) {  if (description) {
Line 108  else if (description.childNodes.length = Line 351  else if (description.childNodes.length =
 description.childNodes[0].nodeValue = "Replacement text";  description.childNodes[0].nodeValue = "Replacement text";
 }  }
 }  }
&lt;/script&gt;</PRE>&lt;/script&gt;
<P>Notice the use of <TT>appendChild</TT>. This method, discussed next, is used to insert the new element or text node into the DOM tree after it is created. Create-and-append is a common two-step process for adding new elements to the object model.</pre>
<H4><A NAME="77049"></A> appendChild</H4>    <p>Notice the use of <tt>appendChild</tt>. This method,
<P>To dynamically <!--INDEX elements:adding dynamically -->  <!--INDEX appendChild( ) method -->  <!--INDEX DOM (Document Object Model):methods:adding elements dynamically -->  <!--INDEX methods:DOM:adding elements dynamically -->  add an element to a document, you need to use the method <TT>appendChild( )</TT>. This method adds a newly created element to an existing parent node by appending to it. If a visible widget is added, this change is visible in the interface immediately.    discussed next, is used to insert the new element or text node
<PRE>&lt;groupbox id="my-id" /&gt;    into the DOM tree after it is created. Create-and-append is a
     common two-step process for adding new elements to the object
     model.</p>
     <h4><a name="77049"></a> appendChild</h4>
     <p>To dynamically <!--INDEX elements:adding dynamically --> 
     <!--INDEX appendChild( ) method --> 
     <!--INDEX DOM (Document Object Model):methods:adding elements dynamically -->
     <!--INDEX methods:DOM:adding elements dynamically --> add an
     element to a document, you need to use the method
     <tt>appendChild( )</tt>. This method adds a newly created
     element to an existing parent node by appending to it. If a
     visible widget is added, this change is visible in the
     interface immediately.</p>
 <pre>
 &lt;groupbox id="my-id" /&gt;
 &lt;script&gt;  &lt;script&gt;
 var existingEl  = document.getElementById('my-id');  var existingEl  = document.getElementById('my-id');
 var captionEl   = document.createElement('caption');  var captionEl   = document.createElement('caption');
 existingEl.appendChild(captionEl);  existingEl.appendChild(captionEl);
 captionEl.setAttribute('label', 'This is a new caption');  captionEl.setAttribute('label', 'This is a new caption');
 captionEl.setAttribute('style', 'color: blue;');  captionEl.setAttribute('style', 'color: blue;');
&lt;/script&gt;</PRE>&lt;/script&gt;
<P>This example creates a new element, gets an existing parent element from the document, and then uses <TT>appendChild( )</TT> to insert that new element into the document. It also uses <TT>setAttribute</TT> to add an attribute value and some CSS style rules, which can highlight the new element in the existing interface.</pre>
<H4><A NAME="77050"></A> cloneNode</H4>    <p>This example creates a new element, gets an existing parent
<P>For  <!--INDEX nodes:copying -->  <!--INDEX cloneNode( ) method -->  <!--INDEX DOM (Document Object Model):methods:copying nodes -->  <!--INDEX methods:DOM:copying nodes --> elements that already exist, a copy method allows you to duplicate elements to avoid having to recreate them from scratch. <TT>cloneNode</TT>, which is a method on the <TT>element</TT> object rather than the <TT>document</TT>, returns a copy of the given node.    element from the document, and then uses <tt>appendChild(
<PRE>&lt;script&gt;    )</tt> to insert that new element into the document. It also
     uses <tt>setAttribute</tt> to add an attribute value and some
     CSS style rules, which can highlight the new element in the
     existing interface.</p>
     <h4><a name="77050"></a> cloneNode</h4>
     <p>For <!--INDEX nodes:copying --> 
     <!--INDEX cloneNode( ) method --> 
     <!--INDEX DOM (Document Object Model):methods:copying nodes -->
     <!--INDEX methods:DOM:copying nodes --> elements that already
     exist, a copy method allows you to duplicate elements to avoid
     having to recreate them from scratch. <tt>cloneNode</tt>, which
     is a method on the <tt>element</tt> object rather than the
     <tt>document</tt>, returns a copy of the given node.</p>
 <pre>
 &lt;script&gt;
 // this is untested --pete  // this is untested --pete
 var element = document.getElementById('my-id');  var element = document.getElementById('my-id');
 var clone = element.cloneNode(false);  var clone = element.cloneNode(false);
 dump(`element='+element+'\n');  dump(`element='+element+'\n');
 dump(`clone='+clone+'\n');  dump(`clone='+clone+'\n');
&lt;/script&gt;</PRE>&lt;/script&gt;
<P>The method takes a Boolean-optional parameter that specifies whether the copy is "deep." Deep copies duplicate all descendants of a node as well as the node itself.</pre>
<H4><A NAME="77051"></A> getElementsByTagName</H4>    <p>The method takes a Boolean-optional parameter that specifies
<P>Another <!--INDEX elements:arrays, returning -->  <!--INDEX getElementsByTagName( ) method -->  <!--INDEX DOM (Document Object Model):methods:returning element arrays -->  <!--INDEX methods:DOM:returning element arrays -->  very useful method is <TT>getElementsByTagName</TT>. This method returns an array of elements of the specified type. The argument used is the string <I>element type</I>. "box," for example, could be used to obtain an array of all boxes in a document. The array is zero-based, so the elements start at 0 and end with the last occurrence of the element in the document. If you have three boxes in a document and want to reference each box, you can do it as follows:    whether the copy is "deep." Deep copies duplicate all
<PRE>&lt;box id="box-one" /&gt;    descendants of a node as well as the node itself.</p>
     <h4><a name="77051"></a> getElementsByTagName</h4>
     <p>Another <!--INDEX elements:arrays, returning --> 
     <!--INDEX getElementsByTagName( ) method --> 
     <!--INDEX DOM (Document Object Model):methods:returning element arrays -->
     <!--INDEX methods:DOM:returning element arrays --> very useful
     method is <tt>getElementsByTagName</tt>. This method returns an
     array of elements of the specified type. The argument used is
     the string <i>element type</i>. "box," for example, could be
     used to obtain an array of all boxes in a document. The array
     is zero-based, so the elements start at 0 and end with the last
     occurrence of the element in the document. If you have three
     boxes in a document and want to reference each box, you can do
     it as follows:</p>
 <pre>
 &lt;box id="box-one" /&gt;
 &lt;box id="box-two" /&gt;  &lt;box id="box-two" /&gt;
 &lt;box id="box-three" /&gt;  &lt;box id="box-three" /&gt;
 &lt;script&gt;  &lt;script&gt;
 document.getElementsByTagName('box')[0];  document.getElementsByTagName('box')[0];
 document.getElementsByTagName('box')[1];  document.getElementsByTagName('box')[1];
 document.getElementsByTagName('box')[2];  document.getElementsByTagName('box')[2];
&lt;/script.</PRE>&lt;/script&gt;
<P>Or you can get the array and index into it like this:</pre>
<PRE>var box = document.getElementsByTagName('box');</PRE>    <p>Or you can get the array and index into it like this:</p>
<P>box[0], the first object in the returned array, is a XUL box.<pre>
<P>To see the number of boxes on a page, you can use the <TT>length</TT> property of an array:var box = document.getElementsByTagName('box');
<PRE>var len = document.getElementsByTagName('box').length;</pre>
dump(l+'\n');    <p>box[0], the first object in the returned array, is a XUL
console output: 3</PRE>    box.</p>
<P>To output the <TT>id</TT> of the box:    <p>To see the number of boxes on a page, you can use the
<PRE>&lt;box id="box-one" /&gt;    <tt>length</tt> property of an array:</p>
 <pre>
 var len = document.getElementsByTagName('box').length;
 dump(len+'\n');
 console output: 3
 </pre>
     <p>To output the <tt>id</tt> of the box:</p>
 <pre>
 &lt;box id="box-one" /&gt;
 &lt;box id="box-two" /&gt;  &lt;box id="box-two" /&gt;
 &lt;box id="box-three" /&gt;  &lt;box id="box-three" /&gt;
 &lt;script&gt;  &lt;script&gt;
Line 157  var el      = document.getElementsByTagN Line 451  var el      = document.getElementsByTagN
 var tagId   = el[0].id;  var tagId   = el[0].id;
 dump(tagId+"\n");  dump(tagId+"\n");
 &lt;/script&gt;  &lt;/script&gt;
console output: box-one</PRE>console output: box-one
<P>To get to an attribute of the second box:</pre>
<PRE>&lt;box id="box-one" /&gt;    <p>To get to an attribute of the second box:</p>
 <pre>
 &lt;box id="box-one" /&gt;
 &lt;box id="box-two" foo="some attribute for the second box" /&gt;  &lt;box id="box-two" foo="some attribute for the second box" /&gt;
 &lt;box id="box-three" /&gt;  &lt;box id="box-three" /&gt;
 &lt;script&gt;  &lt;script&gt;
Line 167  var el        = document.getElementsByTa Line 463  var el        = document.getElementsByTa
 var att       = el[1].getAttribute('foo');  var att       = el[1].getAttribute('foo');
 dump(att      +"\n");  dump(att      +"\n");
 &lt;/script&gt;  &lt;/script&gt;
console output: some attribute for the second box</PRE>console output: some attribute for the second box
<P><TT>getElementsByTagName</TT> is a handy way to obtain DOM elements without using <TT>getElementById</TT>. Not all elements have <TT>id</TT> attributes, so other means of getting at the elements must be used occasionally.<A NAME="b262"></A><A HREF="#262">[*]</A></pre>
<H4><A NAME="77052"></A> Getting an element object and its properties</H4>    <p><tt>getElementsByTagName</tt> is a handy way to obtain DOM
<P>In addition <!--INDEX properties:elements:viewing -->  <!--INDEX elements:properties:viewing -->  to a basic set of attributes, an element may have many properties. These properties don't typically appear in the markup for the element, so they can be harder to learn and remember. To see the properties of an element object node, however, you can use a JavaScript <TT>for</TT> <TT>in</TT> loop to iterate through the list, as shown in <A HREF="#77012">Example 5-1</A>.    elements without using <tt>getElementById</tt>. Not all
    elements have <tt>id</tt> attributes, so other means of getting
<P><I>Example 5-1: <A NAME="77012"></A></I>    at the elements must be used occasionally.<a name="b262"></a><a
<I>Printing element properties to the console</I>    href="#262">[*]</a></p>
<PRE> &lt;box id="my-id" /&gt;    <h4><a name="77052"></a> Getting an element object and its
     properties</h4>
     <p>In addition <!--INDEX properties:elements:viewing --> 
     <!--INDEX elements:properties:viewing --> to a basic set of
     attributes, an element may have many properties. These
     properties don't typically appear in the markup for the
     element, so they can be harder to learn and remember. To see
     the properties of an element object node, however, you can use
     a JavaScript <tt>for</tt> <tt>in</tt> loop to iterate through
     the list, as shown in <a href="#77012">Example 5-1</a>.</p>
     <p><i>Example 5-1: <a name="77012"></a></i> <i>Printing element
     properties to the console</i></p>
 <pre>
  &lt;box id="my-id" /&gt;
  &lt;script&gt;   &lt;script&gt;
    var el = document.getElementById('my-id');     var el = document.getElementById('my-id');
    for (var list in el)     for (var list in el)
Line 187  console output: some attribute for the s Line 496  console output: some attribute for the s
  property = boxObject   property = boxObject
  property = tagName   property = tagName
  property = nodeName   property = nodeName
 . . .</PRE> . . .
</pre>
<P>Note the implicit functionality in the <TT>el</TT> object itself: when you iterate over the object reference, you ask for all members of the class of which that object is an instance. This simple example "spells" the object out to the console. Since the DOM recognizes the window as another element (albeit the root element) in the Document Object Model, you can use a similar script in <A HREF="#77014">Example 5-2</A> to get the properties of the window itself.    <p>Note the implicit functionality in the <tt>el</tt> object
    itself: when you iterate over the object reference, you ask for
<P><I>Example 5-2: <A NAME="77014"></A></I>    all members of the class of which that object is an instance.
<I>Printing the window properties</I>    This simple example "spells" the object out to the console.
<PRE> &lt;script&gt;    Since the DOM recognizes the window as another element (albeit
     the root element) in the Document Object Model, you can use a
     similar script in <a href="#77014">Example 5-2</a> to get the
     properties of the window itself.</p>
     <p><i>Example 5-2: <a name="77014"></a></i> <i>Printing the
     window properties</i></p>
 <pre>
  &lt;script&gt;
    var el        = document.getElementById('test-win');     var el        = document.getElementById('test-win');
    for(var list in el)     for(var list in el)
      dump("property  = "+list+"\n");       dump("property  = "+list+"\n");
  &lt;/script&gt;   &lt;/script&gt;
 </TD>console output(subset): &lt;/td&gt;console output(subset):
  property = nodeName   property = nodeName
  property = nodeValue   property = nodeValue
  property = nodeType   property = nodeType
  property = parentNode   property = parentNode
  property = childNodes   property = childNodes
  property = firstChild   property = firstChild
 . . .</PRE> . . .
</pre>
<P>The output in <A HREF="#77014">Example 5-2</A> is a small subset of all the DOM properties associated with a XUL window and the other XUL elements, but you can see all of them if you run the example. Analyzing output like this can familiarize you with the interfaces available from <TT>window</TT> and other DOM objects.    <p>The output in <a href="#77014">Example 5-2</a> is a small
<H4><A NAME="77053"></A> Retrieving elements by property</H4>    subset of all the DOM properties associated with a XUL window
<P>You can also use a <!--INDEX properties:elements:returning -->  <!--INDEX elements:properties:returning -->  DOM method to access elements with specific properties by using <TT>getElementsByAttribute</TT>. This method takes the name and value of the attribute as arguments and returns an array of nodes that contain these attribute values:    and the other XUL elements, but you can see all of them if you
<PRE>&lt;checkbox id="box-one" /&gt;    run the example. Analyzing output like this can familiarize you
     with the interfaces available from <tt>window</tt> and other
     DOM objects.</p>
     <h4><a name="77053"></a> Retrieving elements by property</h4>
     <p>You can also use a 
     <!--INDEX properties:elements:returning --> 
     <!--INDEX elements:properties:returning --> DOM method to
     access elements with specific properties by using
     <tt>getElementsByAttribute</tt>. This method takes the name and
     value of the attribute as arguments and returns an array of
     nodes that contain these attribute values:</p>
 <pre>
 &lt;checkbox id="box-one" /&gt;
 &lt;checkbox id="box-two" checked="true"/&gt;  &lt;checkbox id="box-two" checked="true"/&gt;
 &lt;checkbox id="box-three" checked="true"/&gt;  &lt;checkbox id="box-three" checked="true"/&gt;
 &lt;script&gt;  &lt;script&gt;
 var chcks = document.getElementsByAttribute("checked", "true");  var chcks = document.getElementsByAttribute("checked", "true");
 var count = chcks.length;  var count = chcks.length;
 dump(count + " items checked \n");  dump(count + " items checked \n");
&lt;/script&gt;</PRE>&lt;/script&gt;
<P>One interesting use of this method is to toggle the state of elements in an interface, as when you get all menu items whose <TT>disabled</TT> attribute is set to true and set them to false. In the xFly sample, you can add this functionality with a few simple updates. In the <I>xfly.js</I> file in the xFly package, add the function defined in <A HREF="#77016">Example 5-3</A>.</pre>
    <p>One interesting use of this method is to toggle the state of
<P><I>Example 5-3: <A NAME="77016"></A></I>    elements in an interface, as when you get all menu items whose
<I>Adding toggle functionality to xFly</I>    <tt>disabled</tt> attribute is set to true and set them to
<PRE> function toggleCheck( ) {    false. In the xFly sample, you can add this functionality with
     a few simple updates. In the <i>xfly.js</i> file in the xFly
     package, add the function defined in <a href="#77016">Example
     5-3</a>.</p>
     <p><i>Example 5-3: <a name="77016"></a></i> <i>Adding toggle
     functionality to xFly</i></p>
 <pre>
  function toggleCheck( ) {
    // get the elements before you make any changes     // get the elements before you make any changes
    var chex   = document.getElementsByAttribute("disabled", "true");     var chex   = document.getElementsByAttribute("disabled", "true");
    var unchex = document.getElementsByAttribute("disabled", "false");     var unchex = document.getElementsByAttribute("disabled", "false");
    for (var i=0; i&lt;chex.length; i++)     for (var i=0; i&lt;chex.length; i++)
       chex</TD>[i].setAttributte("checked", "false");       chex&lt;/td&gt;[i].setAttributte("checked", "false");
    for (var i=0; i&lt;unchex.length; i++)     for (var i=0; i&lt;unchex.length; i++)
       unchex</TD>[i].setAttributte("checked", "true");       unchex&lt;/td&gt;[i].setAttributte("checked", "true");
 }</PRE> }
</pre>
<P>Although this example doesn't update elements whose <TT>disabled</TT> attribute is not specified, you can call this function from a new menu item and have it update all menus whose checked state you do monitor, as shown in <A HREF="#77018">Example 5-4</A>.    <p>Although this example doesn't update elements whose
    <tt>disabled</tt> attribute is not specified, you can call this
<P><I>Example 5-4: <A NAME="77018"></A></I>    function from a new menu item and have it update all menus
<I>Adding Toggle menus to xFly</I>    whose checked state you do monitor, as shown in <a href=
<PRE> &lt;menubar id="appbar"&gt;    "#77018">Example 5-4</a>.</p>
     <p><i>Example 5-4: <a name="77018"></a></i> <i>Adding Toggle
     menus to xFly</i></p>
 <pre>
  &lt;menubar id="appbar"&gt;
    &lt;menu label="File"&gt;     &lt;menu label="File"&gt;
       &lt;menupopup&gt;        &lt;menupopup&gt;
         &lt;menuitem label="New"/&gt;          &lt;menuitem label="New"/&gt;
Line 255  dump(count + " items checked \n"); Line 594  dump(count + " items checked \n");
         &lt;menuitem label="Fruit" disabled="false" /&gt;          &lt;menuitem label="Fruit" disabled="false" /&gt;
       &lt;/menupopup&gt;        &lt;/menupopup&gt;
    &lt;/menu&gt;     &lt;/menu&gt;
 &lt;/menubar&gt;
 &lt;/menubar&gt;</PRE></pre>
    <p>When you add this to the xFly application window (from <a
<P>When you add this to the xFly application window (from <A HREF="ch02.html#77034">Example 2-10</A>, for example, above the basic <TT>vbox</TT>     href="ch02.html#77034">Example 2-10</a>, for example, above the
structure), you get an application menu bar with a menu item, Toggle, that reverses the checked state of the three items in the "Fly Types" menu, as seen in <A HREF="#77004">Figure 5-2</A>.    basic <tt>vbox</tt> structure), you get an application menu bar
<P><CENTER><IMG SRC="foo.gif"></CENTER>    with a menu item, Toggle, that reverses the checked state of
<P><I>Figure 5-2: <A NAME="77004"></A></I>    the three items in the "Fly Types" menu, as seen in <a href=
<I>Toggling the state of menu items in xFly</I>    "#77004">Figure 5-2</a>.</p>
    <div class="c14">
<P>The following section explains more about hooking scripts up to the interface. Needless to say, when you use a method like <TT>getElementsByAttribute</TT> that operates on all elements with a particular attribute value, you must be careful not to grab elements you didn't intend (like a button elsewhere in the application that gets disabled for other purpose).      <img src="foo.gif">
<H2><A NAME="77054"></A> Adding Scripts to the UI</H2>    </div>
<P>Once you are comfortable with how JavaScript works in the context of the user interface layer and are familiar with some of the primary DOM methods used to manipulate the various elements and attributes, you can add your own scripts to your application. Though you can use other techniques to get scripts into the UI, one of the most common methods is to use Mozilla's event model, which is described in the next few sections.    <p><i>Figure 5-2: <a name="77004"></a></i> <i>Toggling the
<H3><A NAME="77055"></A> Handling Events from a XUL Element</H3>    state of menu items in xFly</i></p>
<P><I>Events</I> are input  <!--INDEX scripts:adding to UI, event handling and -->  <!--INDEX event handling:adding scripts to UI --> messages  <!--INDEX XUL (XML-based User-interface Language):elements:event handling --> that pass information from the user interface to the application code. Capturing this information, or <I>event handling</I>, is how you usually tell scripts when to start and stop.    <p>The following section explains more about hooking scripts up
<P>When the user clicks a XUL button, for instance, the button "listens" for the click event, and may also handle that event. If the button itself does not handle the event (e.g., by supplying executable JavaScript in an event handler attribute), then the event "bubbles," or travels further up into the hierarchy of elements above the button. The event handlers in <A HREF="#77016">Example 5-3</A> use simple inline JavaScript to show that the given event (e.g., the window loading in the first example, the button getting clicked in the second, and so on) was fired and handled.    to the interface. Needless to say, when you use a method like
<P>As in HTML, predefined event handlers are available as attributes on a XUL element. These attributes are entry points where you can hook in your JavaScript code, as these examples show. Note that event handler attributes are technically a shortcut, for which the alternative is to register event listeners explicitly to specified elements. The value of these on[event] event handler attributes is the inline JavaScript that should be executed when that event is triggered. <A HREF="#77020">Example 5-5</A> shows some basic button activation events.    <tt>getElementsByAttribute</tt> that operates on all elements
    with a particular attribute value, you must be careful not to
<P><I>Example 5-5: <A NAME="77020"></A></I>    grab elements you didn't intend (like a button elsewhere in the
<I>Basic event handler attributes</I>    application that gets disabled for other purpose).</p>
<PRE> &lt;window onload="dump('this window has loaded\n');" /&gt;    <h2><a name="77054"></a> Adding Scripts to the UI</h2>
     <p>Once you are comfortable with how JavaScript works in the
     context of the user interface layer and are familiar with some
     of the primary DOM methods used to manipulate the various
     elements and attributes, you can add your own scripts to your
     application. Though you can use other techniques to get scripts
     into the UI, one of the most common methods is to use Mozilla's
     event model, which is described in the next few sections.</p>
     <h3><a name="77055"></a> Handling Events from a XUL
     Element</h3>
     <p><i>Events</i> are input 
     <!--INDEX scripts:adding to UI, event handling and --> 
     <!--INDEX event handling:adding scripts to UI --> messages 
     <!--INDEX XUL (XML-based User-interface Language):elements:event handling -->
     that pass information from the user interface to the
     application code. Capturing this information, or <i>event
     handling</i>, is how you usually tell scripts when to start and
     stop.</p>
     <p>When the user clicks a XUL button, for instance, the button
     "listens" for the click event, and may also handle that event.
     If the button itself does not handle the event (e.g., by
     supplying executable JavaScript in an event handler attribute),
     then the event "bubbles," or travels further up into the
     hierarchy of elements above the button. The event handlers in
     <a href="#77016">Example 5-3</a> use simple inline JavaScript
     to show that the given event (e.g., the window loading in the
     first example, the button getting clicked in the second, and so
     on) was fired and handled.</p>
     <p>As in HTML, predefined event handlers are available as
     attributes on a XUL element. These attributes are entry points
     where you can hook in your JavaScript code, as these examples
     show. Note that event handler attributes are technically a
     shortcut, for which the alternative is to register event
     listeners explicitly to specified elements. The value of these
     on[event] event handler attributes is the inline JavaScript
     that should be executed when that event is triggered. <a href=
     "#77020">Example 5-5</a> shows some basic button activation
     events.</p>
     <p><i>Example 5-5: <a name="77020"></a></i> <i>Basic event
     handler attributes</i></p>
 <pre>
  &lt;window onload="dump('this window has loaded\n');" /&gt;
  &lt;button label="onclick-test"   &lt;button label="onclick-test"
     onclick="dump('The event handler onclick has just been used\n');" /&gt;      onclick="dump('The event handler onclick has just been used\n');" /&gt;
  &lt;button label="oncommand-test"   &lt;button label="oncommand-test"
     oncommand="dump('The event handler oncommand has just been used\n');" /&gt;      oncommand="dump('The event handler oncommand has just been used\n');" /&gt;
  &lt;menulist id="custom"   &lt;menulist id="custom"
    onchange="doMyCustomFunction( );" /&gt;</PRE>    onchange="doMyCustomFunction( );" /&gt;
</pre>
<P>While the window and button events in <A HREF="#77020">Example 5-5</A> carry out some inline script, there is a variation with the <TT>onchange</TT> handler attached to the <TT>menulist</TT> element. <TT>onchange</TT> contains a JavaScript function call whose definition may live in the XUL document itself or in an external file that is included by using the <TT>src</TT> attribute on a <TT>script</TT> element:    <p>While the window and button events in <a href=
<PRE>&lt;script type="application/x-javascript" src="chrome://mypackage/content/myfile.js" /&gt;</PRE>    "#77020">Example 5-5</a> carry out some inline script, there is
<P>A large basic set of event handler attributes is available for use on XUL elements (and HTML elements). <A HREF="appc.html#77003">Appendix     a variation with the <tt>onchange</tt> handler attached to the
C</A> has a full listing of these events along with explanations. The following subset <!--INDEX attributes:event handling:XUL elements -->  shows the potential for script interaction when the UI uses event handlers:    <tt>menulist</tt> element. <tt>onchange</tt> contains a
<PRE>onabort    JavaScript function call whose definition may live in the XUL
     document itself or in an external file that is included by
     using the <tt>src</tt> attribute on a <tt>script</tt>
     element:</p>
 <pre>
 &lt;script type="application/x-javascript" src="chrome://mypackage/content/myfile.js" /&gt;
 </pre>
     <p>A large basic set of event handler attributes is available
     for use on XUL elements (and HTML elements). <a href=
     "appc.html#77003">Appendix C</a> has a full listing of these
     events along with explanations. The following subset 
     <!--INDEX attributes:event handling:XUL elements --> shows the
     potential for script interaction when the UI uses event
     handlers:</p>
 <pre>
 onabort
 onblur  onblur
 onerror  onerror
 onfocus  onfocus
Line 309  onrest Line 704  onrest
 onresize  onresize
 onscroll  onscroll
 onselect  onselect
onsubmit</PRE>onsubmit
<P>Some of these event handlers work only on particular elements, such as <TT>window</TT>, which listens for the <TT>load</TT> event, the <TT>paint</TT> event, and other special events.</pre>
<P>To see all event handler attributes on a particular element, you can execute the short script in <A HREF="#77022">Example 5-6</A>, which uses the <TT>for</TT> <TT>in</TT> loop in JavaScript to iterate over the members of an object-in this  <!--INDEX attributes:event handling:viewing for elements --> case, a XUL element.    <p>Some of these event handlers work only on particular
    elements, such as <tt>window</tt>, which listens for the
<P><I>Example 5-6: <A NAME="77022"></A></I>    <tt>load</tt> event, the <tt>paint</tt> event, and other
<I>Getting event handler attributes from an element</I>    special events.</p>
<PRE> &lt;script type="application/x-javascript"&gt;    <p>To see all event handler attributes on a particular element,
     you can execute the short script in <a href="#77022">Example
     5-6</a>, which uses the <tt>for</tt> <tt>in</tt> loop in
     JavaScript to iterate over the members of an object-in this 
     <!--INDEX attributes:event handling:viewing for elements -->
     case, a XUL element.</p>
     <p><i>Example 5-6: <a name="77022"></a></i> <i>Getting event
     handler attributes from an element</i></p>
 <pre>
  &lt;script type="application/x-javascript"&gt;
    function listElementHandlers(aObj)     function listElementHandlers(aObj)
    {     {
      if(!aObj)       if(!aObj)
Line 325  onsubmit</PRE> Line 729  onsubmit</PRE>
          dump(list+'\n');           dump(list+'\n');
    }     }
  &lt;/script&gt;   &lt;/script&gt;
 &lt;button label="oncommand" oncommand="listElementHandlers(this);" /&gt;</PRE> &lt;button label="oncommand" oncommand="listElementHandlers(this);" /&gt;
</pre>
<P>The function you added in <A HREF="#77018">Example 5-4</A> is also an example of event handler code in an application's interface.    <p>The function you added in <a href="#77018">Example 5-4</a>
<H3><A NAME="77056"></A> Events and the Mozilla Event Model</H3>    is also an example of event handler code in an application's
<P>The event model in Mozilla is the general framework for how events work and move around in the user interface. As you've already seen, events tend to rise up through the DOM hierarchy-a natural process referred to as event propagation or event bubbling. The next two sections describe event propagation and its complement, event capturing.    interface.</p>
<H4><A NAME="77057"></A> Event propagation and event bubbling</H4>    <h3><a name="77056"></a> Events and the Mozilla Event
<P>This availability of events in <!--INDEX event handling:bubbling -->  <!--INDEX bubbling (event handling) -->  <!--INDEX hierarchy:event bubbling -->  <!--INDEX elements:event handling, bubbling -->  nodes above the element of origin is known as event propagation or event bubbling. Event bubbling means you can handle events anywhere above the event-raising element in the hierarchy. When events are handled by elements that did not initiate those events, you must determine which element below actually raised the event. For example, if an event handler in a menu element handles an event raised by one of the menu items, then the menu should be able to identify the raising element and take the appropriate action, as shown in <A HREF="#77024">Example 5-7</A>. In this example, a JavaScript function determines which <TT>menuitem</TT> was selected and responds appropriately.    Model</h3>
    <p>The event model in Mozilla is the general framework for how
<P><I>Example 5-7: <A NAME="77024"></A></I>    events work and move around in the user interface. As you've
<I>Event propagation</I>    already seen, events tend to rise up through the DOM
<PRE> &lt;script type="application/x-javascript"&gt;    hierarchy-a natural process referred to as event propagation or
     event bubbling. The next two sections describe event
     propagation and its complement, event capturing.</p>
     <h4><a name="77057"></a> Event propagation and event
     bubbling</h4>
     <p>This availability of events in 
     <!--INDEX event handling:bubbling --> 
     <!--INDEX bubbling (event handling) --> 
     <!--INDEX hierarchy:event bubbling --> 
     <!--INDEX elements:event handling, bubbling --> nodes above the
     element of origin is known as event propagation or event
     bubbling. Event bubbling means you can handle events anywhere
     above the event-raising element in the hierarchy. When events
     are handled by elements that did not initiate those events, you
     must determine which element below actually raised the event.
     For example, if an event handler in a menu element handles an
     event raised by one of the menu items, then the menu should be
     able to identify the raising element and take the appropriate
     action, as shown in <a href="#77024">Example 5-7</a>. In this
     example, a JavaScript function determines which
     <tt>menuitem</tt> was selected and responds appropriately.</p>
     <p><i>Example 5-7: <a name="77024"></a></i> <i>Event
     propagation</i></p>
 <pre>
  &lt;script type="application/x-javascript"&gt;
  function doCMD(el) {   function doCMD(el) {
      v = el.getAttribute("label")       v = el.getAttribute("label")
      switch (v) {       switch (v) {
Line 358  onsubmit</PRE> Line 786  onsubmit</PRE>
      &lt;menuitem label="Open" /&gt;       &lt;menuitem label="Open" /&gt;
      &lt;menuitem label="Close" /&gt;       &lt;menuitem label="Close" /&gt;
    &lt;/menupopup&gt;     &lt;/menupopup&gt;
 &lt;/menu&gt;</PRE> &lt;/menu&gt;
</pre>
<P>The event handler in the parent node menu finds out which child <TT>menuitem</TT> was actually clicked by using <TT>event.target</TT> and takes action accordingly. Let's walk through another possible scenario. If a user of an application selects an item from a menu list, you could get the node of that item by using <TT>event.target</TT>. Your script could then abstract that item's value or other information, if necessary.    <p>The event handler in the parent node menu finds out which
<H5><A NAME="77058"></A> Trapping events</H5>    child <tt>menuitem</tt> was actually clicked by using
<P>When an  <!--INDEX event handling:trapping -->  <!--INDEX trapping events --> event is raised, it is typically handled by any node interested in it as it continues its way up the DOM hierarchy. In some cases, you may want to handle an event and then prevent it from bubbling further up, which is where the DOM Event <!--INDEX DOM (Document Object Model):event handling, trapping events -->  <!--INDEX stopPropagation( ) method -->  method <TT>stopPropagation( )</TT> comes in handy.    <tt>event.target</tt> and takes action accordingly. Let's walk
<P><A HREF="#77026">Example 5-8</A> demonstrates how event bubbling can be arrested very simply. When the XUL document in <A HREF="#77026">Example 5-8</A> loads, an event listener is registered with a <TT>row</TT> in the tree. The event listener handles the event by executing the function <TT>stopEvent( )</TT>. This function calls an event object method, <TT>stopPropagation</TT>, which keeps the event from bubbling further up into the DOM. Note that the tree itself has an <TT>onclick</TT> event handler that should display a message when clicked. However, the  <!--INDEX stopEvent( ) method --> <TT>stopEvent( )</TT> method has stopped propagation, so after the data in the table is updated, the event phase is effectively ended. In this case, the function was used to trap the event and handle it only there.    through another possible scenario. If a user of an application
    selects an item from a menu list, you could get the node of
<P><I>Example 5-8: <A NAME="77026"></A></I>    that item by using <tt>event.target</tt>. Your script could
<I>stopPropagation( ) event function</I>    then abstract that item's value or other information, if
<PRE> &lt;?xml version="1.0"?&gt;    necessary.</p>
     <h5><a name="77058"></a> Trapping events</h5>
     <p>When an <!--INDEX event handling:trapping --> 
     <!--INDEX trapping events --> event is raised, it is typically
     handled by any node interested in it as it continues its way up
     the DOM hierarchy. In some cases, you may want to handle an
     event and then prevent it from bubbling further up, which is
     where the DOM Event 
     <!--INDEX DOM (Document Object Model):event handling, trapping events -->
     <!--INDEX stopPropagation( ) method --> method
     <tt>stopPropagation( )</tt> comes in handy.</p>
     <p><a href="#77026">Example 5-8</a> demonstrates how event
     bubbling can be arrested very simply. When the XUL document in
     <a href="#77026">Example 5-8</a> loads, an event listener is
     registered with a <tt>row</tt> in the tree. The event listener
     handles the event by executing the function <tt>stopEvent(
     )</tt>. This function calls an event object method,
     <tt>stopPropagation</tt>, which keeps the event from bubbling
     further up into the DOM. Note that the tree itself has an
     <tt>onclick</tt> event handler that should display a message
     when clicked. However, the <!--INDEX stopEvent( ) method -->
     <tt>stopEvent( )</tt> method has stopped propagation, so after
     the data in the table is updated, the event phase is
     effectively ended. In this case, the function was used to trap
     the event and handle it only there.</p>
     <p><i>Example 5-8: <a name="77026"></a></i> <i>stopPropagation(
     ) event function</i></p>
 <pre>
  &lt;?xml version="1.0"?&gt;
  &lt;!DOCTYPE  window&gt;   &lt;!DOCTYPE  window&gt;
  &lt;window id="test-win"   &lt;window id="test-win"
   xmlns="<A HREF="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul</A>"   xmlns="<a href=
 "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul</a>"
    orient="vertical"     orient="vertical"
    onload="load( );"&gt;     onload="load( );"&gt;
  &lt;script type="application/x-javascript"&gt;   &lt;script type="application/x-javascript"&gt;
Line 378  onsubmit</PRE> Line 835  onsubmit</PRE>
      el = document.getElementById("t");       el = document.getElementById("t");
      el.addEventListener("click", stopEvent, false);       el.addEventListener("click", stopEvent, false);
    }     }
   </TD>function stopEvent(e) {   &lt;/td&gt;function stopEvent(e) {
      // this ought to keep t-daddy from getting the click.       // this ought to keep t-daddy from getting the click.
      e.stopPropagation( );       e.stopPropagation( );
    }     }
Line 387  onsubmit</PRE> Line 844  onsubmit</PRE>
    &lt;!-- tree columns definition omitted --&gt;     &lt;!-- tree columns definition omitted --&gt;
    &lt;treechildren flex="1" &gt;     &lt;treechildren flex="1" &gt;
      &lt;treeitem id="t-daddy"       &lt;treeitem id="t-daddy"
       </TD>onclick="alert('t-daddy');"  // this event is never fired       &lt;/td&gt;onclick="alert('t-daddy');"  // this event is never fired
        container="true" parent="true"&gt;         container="true" parent="true"&gt;
        &lt;treerow id="t"&gt;         &lt;treerow id="t"&gt;
          &lt;treecell label="O'Reilly" id="t1" /&gt;           &lt;treecell label="O'Reilly" id="t1" /&gt;
         &lt;treecell label="<A HREF="http://www.oreilly.com">http://www.oreilly.com</A>" id="t2" /&gt;         &lt;treecell label="<a href=
 "http://www.oreilly.com">http://www.oreilly.com</a>" id="t2" /&gt;
        &lt;/treerow&gt;         &lt;/treerow&gt;
       &lt;/treeitem&gt;        &lt;/treeitem&gt;
    &lt;/treechildren&gt;     &lt;/treechildren&gt;
  &lt;/tree&gt;   &lt;/tree&gt;
 &lt;/window&gt;</PRE> &lt;/window&gt;
</pre>
<H4><A NAME="77059"></A> Capturing events</H4>    <h4><a name="77059"></a> Capturing events</h4>
<P>Event  <!--INDEX event handling:capturing events -->  <!--INDEX capturing events --> capturing is the complement of event bubbling. The DOM provides the <TT>addEventListener</TT> method for creating event listeners on nodes that do not otherwise supply them. When you register an event listener on an ancestor of the event target (i.e., any node above the event-raising element in the node hierarchy), you can use event capturing to handle the event in the ancestor before it is heard in the target itself or any intervening nodes.    <p>Event <!--INDEX event handling:capturing events --> 
<P>To take advantage of event capturing (or event bubbling with elements that do not already have event listeners), you must add an event listener to the element that wants to capture events occurring below it. Any XUL element may use the DOM <TT>addEventListener</TT> <!--INDEX addEventListener( ) method -->   <!--INDEX registering:elements, event capturing -->  <!--INDEX elements:registering, event capturing -->  <!--INDEX listeners, event capturing --> method to register itself to capture events. The syntax for using this method in XUL is shown here:    <!--INDEX capturing events --> capturing is the complement of
<PRE>XULelement = document.getElementById("id of XULelement");    event bubbling. The DOM provides the <tt>addEventListener</tt>
     method for creating event listeners on nodes that do not
     otherwise supply them. When you register an event listener on
     an ancestor of the event target (i.e., any node above the
     event-raising element in the node hierarchy), you can use event
     capturing to handle the event in the ancestor before it is
     heard in the target itself or any intervening nodes.</p>
     <p>To take advantage of event capturing (or event bubbling with
     elements that do not already have event listeners), you must
     add an event listener to the element that wants to capture
     events occurring below it. Any XUL element may use the DOM
     <tt>addEventListener</tt> 
     <!--INDEX addEventListener( ) method --> 
     <!--INDEX registering:elements, event capturing --> 
     <!--INDEX elements:registering, event capturing --> 
     <!--INDEX listeners, event capturing --> method to register
     itself to capture events. The syntax for using this method in
     XUL is shown here:</p>
 <pre>
 XULelement = document.getElementById("id of XULelement");
 XULelement.addEventListener("event name", "event handler code",  XULelement.addEventListener("event name", "event handler code",
useCapture bool);</PRE>useCapture bool);
<P>The event handler code argument can be inline code or the name of a function. The <TT> <!--INDEX useCapture parameter --> useCapture</TT> parameter specifies whether the event listener wants to use event capturing or be registered to listen for events that bubble up the hierarchy normally. In <A HREF="#77006">Figure 5-3</A>, the alert dialog invoked by the <TT>menuitem</TT> itself is not displayed, since the root <TT>window</TT> element used event capture to handle the event itself.</pre>
<P><CENTER><IMG SRC="foo.gif"></CENTER>    <p>The event handler code argument can be inline code or the
<P><I>Figure 5-3: <A NAME="77006"></A></I>    name of a function. The <tt><!--INDEX useCapture parameter -->
<I>Event capturing</I>    useCapture</tt> parameter specifies whether the event listener
    wants to use event capturing or be registered to listen for
<P>An <TT> <!--INDEX onload event handler --> onload</TT>  <!--INDEX event handling:onload handler --> event handler for a XUL window can also register a <TT>box</TT> element to capture all click events that are raised from its child elements:    events that bubble up the hierarchy normally. In <a href=
<PRE>var bbox = document.getElementById("bigbox");    "#77006">Figure 5-3</a>, the alert dialog invoked by the
     <tt>menuitem</tt> itself is not displayed, since the root
     <tt>window</tt> element used event capture to handle the event
     itself.</p>
     <div class="c14">
       <img src="foo.gif">
     </div>
     <p><i>Figure 5-3: <a name="77006"></a></i> <i>Event
     capturing</i></p>
     <p>An <tt><!--INDEX onload event handler --> onload</tt> 
     <!--INDEX event handling:onload handler --> event handler for a
     XUL window can also register a <tt>box</tt> element to capture
     all click events that are raised from its child elements:</p>
 <pre>
 var bbox = document.getElementById("bigbox");
 if (bbox) {  if (bbox) {
 bbox.addEventListener("click", "alert('captured')", true);  bbox.addEventListener("click", "alert('captured')", true);
 }  }
Line 422  bbox.addEventListener("click", "alert('c Line 913  bbox.addEventListener("click", "alert('c
 ...  ...
 &lt;menupopup&gt;  &lt;menupopup&gt;
 &lt;/menu&gt;  &lt;/menu&gt;
&lt;/box&gt;</PRE>&lt;/box&gt;
<H3><A NAME="77060"></A> Changing an Element's CSS Style Using JavaScript</H3></pre>
<P>Much of  <!--INDEX CSS (Cascading Style Sheets):styles, changing with JavaScript -->  <!--INDEX styles:CSS, changing with JavaScript -->  <!--INDEX JavaScript:Cascading Style Sheets and:changing styles -->  <!--INDEX scripting:CSS styles, changing --> what makes the Mozilla UI both flexible and programmable is its ability to dynamically alter the CSS style rules for elements at runtime. For example, if you have a button, you can toggle its visibility by using a simple combination of JavaScript and CSS. Given a basic set of buttons like this:    <h3><a name="77060"></a> Changing an Element's CSS Style Using
<PRE>&lt;button id="somebutton" class="testButton" label="foo" /&gt;    JavaScript</h3>
     <p>Much of 
     <!--INDEX CSS (Cascading Style Sheets):styles, changing with JavaScript -->
     <!--INDEX styles:CSS, changing with JavaScript --> 
     <!--INDEX JavaScript:Cascading Style Sheets and:changing styles -->
     <!--INDEX scripting:CSS styles, changing --> what makes the
     Mozilla UI both flexible and programmable is its ability to
     dynamically alter the CSS style rules for elements at runtime.
     For example, if you have a button, you can toggle its
     visibility by using a simple combination of JavaScript and CSS.
     Given a basic set of buttons like this:</p>
 <pre>
 &lt;button id="somebutton" class="testButton" label="foo" /&gt;
 &lt;spacer flex="1" /&gt;  &lt;spacer flex="1" /&gt;
 &lt;button id="ctlbutton"  &lt;button id="ctlbutton"
 class="testButton"  class="testButton"
 label="make disappear"  label="make disappear"
oncommand="disappear( );" /&gt;</PRE>oncommand="disappear( );" /&gt;
<P>as well as a stylesheet import statement at the top of the XUL like this:</pre>
<PRE>&lt;?xml-stylesheet href="test.css" type="text/css"?&gt;</PRE>    <p>as well as a stylesheet import statement at the top of the
<P>and a simple CSS file in your <I>chrome/xfly/content</I> directory called <I>test.css</I> that contains the following style rule:    XUL like this:</p>
<PRE>#somebutton[hidden="true"]{ display: none; }<pre>
 &lt;?xml-stylesheet href="test.css" type="text/css"?&gt;
 </pre>
     <p>and a simple CSS file in your <i>chrome/xfly/content</i>
     directory called <i>test.css</i> that contains the following
     style rule:</p>
 <pre>
 #somebutton[hidden="true"]{ display: none; }
 .testButton{  .testButton{
 border            : 1px outset #cccccc;  border            : 1px outset #cccccc;
 background-color  : #cccccc;  background-color  : #cccccc;
 padding           : 4px;  padding           : 4px;
 margin            : 50px;  margin            : 50px;
}</PRE>}
<P>You can call <TT> <!--INDEX setAttribute( ) method:calling at runtime --> setAttribute</TT> in your script to hide the button at runtime.</pre>
<PRE>&lt;script&gt;    <p>You can call <tt>
     <!--INDEX setAttribute( ) method:calling at runtime -->
     setAttribute</tt> in your script to hide the button at
     runtime.</p>
 <pre>
 &lt;script&gt;
 function disappear( ){  function disappear( ){
 return document.getElementById('somebutton').setAttribute('hidden', true);  return document.getElementById('somebutton').setAttribute('hidden', true);
 }  }
&lt;/script&gt;</PRE>&lt;/script&gt;
<P>The previous code snippet makes a visible button disappear by setting its <TT>hidden</TT> attribute to true. Adding a few more lines, you can toggle the visibility of the button, also making it appear if it is hidden:</pre>
<PRE>&lt;script&gt;    <p>The previous code snippet makes a visible button disappear
     by setting its <tt>hidden</tt> attribute to true. Adding a few
     more lines, you can toggle the visibility of the button, also
     making it appear if it is hidden:</p>
 <pre>
 &lt;script&gt;
 function disappear( ){  function disappear( ){
 const defaultLabel  = "make disappear";  const defaultLabel  = "make disappear";
 const newLabel      = "make reappear";  const newLabel      = "make reappear";
Line 463  ctlButton.setAttribute('label', defaultL Line 983  ctlButton.setAttribute('label', defaultL
 }  }
 return;  return;
 }  }
&lt;/script&gt;</PRE>&lt;/script&gt;
<P>Another useful application of this functionality is to collapse elements such as toolbars, boxes, and iframes in your application.</pre>
<P>The <TT>setAttribute</TT> method can also be used to update the element's <TT>class</TT> attribute with which style rules are so often associated. <TT>toolbarbutton-1</TT> and <TT>button-toolbar</TT> are two different classes of button. You can change a button from a <TT>toolbarbutton-1-</TT>the large button used in the browser-to a standard toolbar button using the following DOM code:    <p>Another useful application of this functionality is to
<PRE>// get the Back button in the browser    collapse elements such as toolbars, boxes, and iframes in your
     application.</p>
     <p>The <tt>setAttribute</tt> method can also be used to update
     the element's <tt>class</tt> attribute with which style rules
     are so often associated. <tt>toolbarbutton-1</tt> and
     <tt>button-toolbar</tt> are two different classes of button.
     You can change a button from a <tt>toolbarbutton-1-</tt>the
     large button used in the browser-to a standard toolbar button
     using the following DOM code:</p>
 <pre>
 // get the Back button in the browser
 b1 = document.getElementById("back-button");\  b1 = document.getElementById("back-button");\
b1.setAttribute("class", "button-toolbar");</PRE>b1.setAttribute("class", "button-toolbar");
<P>This dynamically demotes the Back button to an ordinary toolbar button. Code such as this assumes, of course, that you know the classes that are used to style the various widgets in the interface.</pre>
<P>You can also set the <TT>style</TT> attribute directly using the DOM:    <p>This dynamically demotes the Back button to an ordinary
<PRE>el = document.getElementById("some-element");    toolbar button. Code such as this assumes, of course, that you
el.setAttribute("style", "background-color:darkblue;");</PRE>    know the classes that are used to style the various widgets in
<P>Be aware, however, that when you set the <TT>style</TT> attribute in this way, you are overwriting whatever style properties may already have been defined in the <TT>style</TT> attribute. If the document referenced in the snippet above by the ID <TT>some-element</TT> has a <TT>style</TT> attribute in which the font size is set to 18pc, for example, that information is erased when the style attribute is manipulated in this way.    the interface.</p>
<H3><A NAME="77061"></A> Creating Elements Dynamically</H3>    <p>You can also set the <tt>style</tt> attribute directly using
<P>Using the <!--INDEX elements:creating dynamically -->  <!--INDEX XUL (XML-based User-interface Language):elements:creating dynamically -->  <TT>createElement</TT> method in XUL lets you accomplish things similar to <TT>document.write</TT> in HTML, with which you can create new pages and parts of a web page. In <A HREF="#77028">Example 5-9</A>, <TT> <!--INDEX createElement( ) method:dynamic element creation --> createElement</TT> is used to generate a menu dynamically.    the DOM:</p>
<pre>
<P><I>Example 5-9: <A NAME="77028"></A></I>el = document.getElementById("some-element");
<I>Dynamic menu generation</I>el.setAttribute("style", "background-color:darkblue;");
<PRE> &lt;?xml version="1.0"?&gt;</pre>
     <p>Be aware, however, that when you set the <tt>style</tt>
     attribute in this way, you are overwriting whatever style
     properties may already have been defined in the <tt>style</tt>
     attribute. If the document referenced in the snippet above by
     the ID <tt>some-element</tt> has a <tt>style</tt> attribute in
     which the font size is set to 18pc, for example, that
     information is erased when the style attribute is manipulated
     in this way.</p>
     <h3><a name="77061"></a> Creating Elements Dynamically</h3>
     <p>Using the <!--INDEX elements:creating dynamically --> 
     <!--INDEX XUL (XML-based User-interface Language):elements:creating dynamically -->
     <tt>createElement</tt> method in XUL lets you accomplish things
     similar to <tt>document.write</tt> in HTML, with which you can
     create new pages and parts of a web page. In <a href=
     "#77028">Example 5-9</a>, <tt>
     <!--INDEX createElement( ) method:dynamic element creation -->
     createElement</tt> is used to generate a menu dynamically.</p>
     <p><i>Example 5-9: <a name="77028"></a></i> <i>Dynamic menu
     generation</i></p>
 <pre>
  &lt;?xml version="1.0"?&gt;
  &lt;?xml-stylesheet href="test.css" type="text/css"?&gt;   &lt;?xml-stylesheet href="test.css" type="text/css"?&gt;
  &lt;!DOCTYPE  window&gt;   &lt;!DOCTYPE  window&gt;
  &lt;window id="test-win"   &lt;window id="test-win"
         xmlns="<A HREF="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul</A>"         xmlns="<a href=
 "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul</a>"
          title="test"           title="test"
          style="           style="
          min-width : 200px;           min-width : 200px;
          min-height: 200px;"&gt;           min-height: 200px;"&gt;
  &lt;script&gt;   &lt;script&gt;
 &lt;!</TD>[CDATA[ &lt;!&lt;/td&gt;[CDATA[
  function generate( ){   function generate( ){
    var d           = document;     var d           = document;
    var popup       = d.getElementById('menupopup');     var popup       = d.getElementById('menupopup');
Line 501  el.setAttribute("style", "background-col Line 1053  el.setAttribute("style", "background-col
    for(var i=0; i&lt;l; i++)     for(var i=0; i&lt;l; i++)
    {     {
      newElement = d.createElement('menuitem');       newElement = d.createElement('menuitem');
     newElement.setAttribute('id', menuitems</TD>[i]);     newElement.setAttribute('id', menuitems&lt;/td&gt;[i]);
     newElement.setAttribute('label', menuitems</TD>[i]);     newElement.setAttribute('label', menuitems&lt;/td&gt;[i]);
      popup.appendChild(newElement);       popup.appendChild(newElement);
    }     }
    return true;     return true;
Line 515  el.setAttribute("style", "background-col Line 1067  el.setAttribute("style", "background-col
  &lt;/menu&gt;   &lt;/menu&gt;
  &lt;spacer flex="1" /&gt;   &lt;spacer flex="1" /&gt;
  &lt;button id="ctlbutton" class="testButton" label="generate" oncommand="generate( );" /&gt;   &lt;button id="ctlbutton" class="testButton" label="generate" oncommand="generate( );" /&gt;
 &lt;/window&gt;</PRE> &lt;/window&gt;
</pre>
<P>The JavaScript function <TT> <!--INDEX generate( ) function --> generate( )</TT> in <A HREF="#77028">Example 5-9</A> gets the <TT>menupopup</TT> as the parent element for the new elements, creates five <TT>menuitems</TT> in an array called <TT>menuitems</TT>, and stores five string ID names for those <TT>menuitems</TT>.    <p>The JavaScript function <tt>
<P>The variable <I>l</I> is the length of the array. The variable <TT>newElement</TT> is a placeholder for elements created by using the <TT>createElement</TT> method inside of the <TT>for</TT> loop. <TT>generate( )</TT> assigns <TT>newElement</TT> on each iteration of the loop and creates a new <TT>menuitem</TT> each time, providing a way to dynamically generate a list of menu choices based on input data or user feedback. Try this example and experiment with different sources of data, such as a menu of different auto manufacturers, different styles on group of boxes that come from user selection, or tabular data in a tree.    <!--INDEX generate( ) function --> generate( )</tt> in <a href=
<H3><A NAME="77062"></A> Sharing Data Between Documents</H3>    "#77028">Example 5-9</a> gets the <tt>menupopup</tt> as the
<P>As the scale of your application development increases and your applications grow new windows and components, you may become interested in passing data around and ensuring that the data remains in scope. Misunderstanding that scope often leads to problems when beginning Mozilla applications.    parent element for the new elements, creates five
<H4><A NAME="77063"></A> Scope in Mozilla</H4>    <tt>menuitems</tt> in an array called <tt>menuitems</tt>, and
<P>The general  <!--INDEX documents:sharing data:scope -->  <!--INDEX sharing data, scope -->  <!--INDEX scope, sharing data between documents --> rule is that all scripts pulled in by the base XUL document and scripts included in overlays of this document are in the same scope. Therefore, any global variables you declare in any of these scripts can be used by any other scripts in the same scope. The decision to put a class structure or more sophisticated design in place is up to you.    stores five string ID names for those <tt>menuitems</tt>.</p>
<P>The relationship of a parent and child window indicates the importance of storing data in language constructs that can be passed around. This code shows a common way for a parent to pass data to a window it spawns:    <p>The variable <i>l</i> is the length of the array. The
<PRE>var obj = new Object ( );    variable <tt>newElement</tt> is a placeholder for elements
     created by using the <tt>createElement</tt> method inside of
     the <tt>for</tt> loop. <tt>generate( )</tt> assigns
     <tt>newElement</tt> on each iteration of the loop and creates a
     new <tt>menuitem</tt> each time, providing a way to dynamically
     generate a list of menu choices based on input data or user
     feedback. Try this example and experiment with different
     sources of data, such as a menu of different auto
     manufacturers, different styles on group of boxes that come
     from user selection, or tabular data in a tree.</p>
     <h3><a name="77062"></a> Sharing Data Between Documents</h3>
     <p>As the scale of your application development increases and
     your applications grow new windows and components, you may
     become interested in passing data around and ensuring that the
     data remains in scope. Misunderstanding that scope often leads
     to problems when beginning Mozilla applications.</p>
     <h4><a name="77063"></a> Scope in Mozilla</h4>
     <p>The general <!--INDEX documents:sharing data:scope --> 
     <!--INDEX sharing data, scope --> 
     <!--INDEX scope, sharing data between documents --> rule is
     that all scripts pulled in by the base XUL document and scripts
     included in overlays of this document are in the same scope.
     Therefore, any global variables you declare in any of these
     scripts can be used by any other scripts in the same scope. The
     decision to put a class structure or more sophisticated design
     in place is up to you.</p>
     <p>The relationship of a parent and child window indicates the
     importance of storing data in language constructs that can be
     passed around. This code shows a common way for a parent to
     pass data to a window it spawns:</p>
 <pre>
 var obj = new Object ( );
 obj.res = "";  obj.res = "";
 window.openDialog("chrome://xfly/content/foo.xul", 'foo_main',  window.openDialog("chrome://xfly/content/foo.xul", 'foo_main',
 "chrome,resizable,scrollbars,dialog=yes,close,modal=yes",  "chrome,resizable,scrollbars,dialog=yes,close,modal=yes",
obj);</PRE>obj);
<H4><A NAME="77064"></A> Using the window.arguments array</H4></pre>
<P>The previous  <!--INDEX window.arguments array -->  <!--INDEX arrays, sharing data between documents;window.arguments array -->  <!--INDEX documents:sharing data:window.arguments array --> code snippet creates a new JavaScript object, <TT>obj</TT>, and assigns the value of an empty string to that object's <TT>res</TT> property. The object is then passed by reference to the new window as the last parameter of the <TT>openDialog( )</TT> method so it can be manipulated in the scope of the child window:    <h4><a name="77064"></a> Using the window.arguments array</h4>
<PRE>function onOk( ) {    <p>The previous <!--INDEX window.arguments array --> 
     <!--INDEX arrays, sharing data between documents;window.arguments array -->
     <!--INDEX documents:sharing data:window.arguments array -->
     code snippet creates a new JavaScript object, <tt>obj</tt>, and
     assigns the value of an empty string to that object's
     <tt>res</tt> property. The object is then passed by reference
     to the new window as the last parameter of the <tt>openDialog(
     )</tt> method so it can be manipulated in the scope of the
     child window:</p>
 <pre>
 function onOk( ) {
 window.arguments[0].res  = "ok";  window.arguments[0].res  = "ok";
 return;  return;
 }  }
 function onCancel( ) {  function onCancel( ) {
 window.arguments[0].res  = "cancel";  window.arguments[0].res  = "cancel";
 return;  return;
}</PRE>}
<P>In that child window, the object is available as an indexed item in the special <TT>window.arguments</TT> array. This array holds a list of the arguments passed to a window when it is created. window.arguments[0] is a reference to the first argument in the <TT>openDialog( )</TT> parameter list that is not a part of the input parameters for that method, window.arguments[1] is the second argument, and so on. Using <TT>window.arguments</TT> is the most common way to pass objects and other data around between documents.</pre>
<P>When the user clicks a button in the displayed dialog (i.e., the OK or Cancel button), one of the functions sets a value to the <TT>res</TT> property of the passed-in object. The object is in the scope of the newly created window. When control is passed back to the script that launched the window, the return value can be checked:    <p>In that child window, the object is available as an indexed
<PRE>if (obj.res != "ok") {    item in the special <tt>window.arguments</tt> array. This array
     holds a list of the arguments passed to a window when it is
     created. window.arguments[0] is a reference to the first
     argument in the <tt>openDialog( )</tt> parameter list that is
     not a part of the input parameters for that method,
     window.arguments[1] is the second argument, and so on. Using
     <tt>window.arguments</tt> is the most common way to pass
     objects and other data around between documents.</p>
     <p>When the user clicks a button in the displayed dialog (i.e.,
     the OK or Cancel button), one of the functions sets a value to
     the <tt>res</tt> property of the passed-in object. The object
     is in the scope of the newly created window. When control is
     passed back to the script that launched the window, the return
     value can be checked:</p>
 <pre>
 if (obj.res != "ok") {
 dump("User has cancelled the dialog");  dump("User has cancelled the dialog");
 return;  return;
}</PRE>}
<P>In this case, a simple dump statement prints the result, but you can also test the result in your application code and fork accordingly.</pre>
<H2><A NAME="77065"></A> XPConnect and Scriptable Components</H2>    <p>In this case, a simple dump statement prints the result, but
<P>At the second level of scripting, XPConnect binds JavaScript and the user interface to the application core. Here, JavaScript can access all XPCOM components that implement scriptable libraries and services through a special global object whose methods and properties can be used in JavaScript. Consider these JavaScript snippets from the Mozilla source code:    you can also test the result in your application code and fork
<PRE>// add filters to the file picker    accordingly.</p>
     <h2><a name="77065"></a> XPConnect and Scriptable
     Components</h2>
     <p>At the second level of scripting, XPConnect binds JavaScript
     and the user interface to the application core. Here,
     JavaScript can access all XPCOM components that implement
     scriptable libraries and services through a special global
     object whose methods and properties can be used in JavaScript.
     Consider these JavaScript snippets from the Mozilla source
     code:</p>
 <pre>
 // add filters to the file picker
 fp.appendFilters( nsIFilePicker.HTML );  fp.appendFilters( nsIFilePicker.HTML );
 // display a directory in the file picker  // display a directory in the file picker
 fp.displayDirectory ( dir );  fp.displayDirectory ( dir );
Line 556  fp.displayDirectory ( dir ); Line 1175  fp.displayDirectory ( dir );
 file.readLine(tmpBuf, 1024, didTruncate);  file.readLine(tmpBuf, 1024, didTruncate);
 // create a new directory  // create a new directory
 this.fileInst.create( DIRECTORY, parseInt(permissions) );  this.fileInst.create( DIRECTORY, parseInt(permissions) );
retval=OK;</PRE>retval=OK;
<P>The <TT>filepicker</TT>, <TT>file</TT>, and <TT>localfile</TT> components that these JavaScript objects represent are a tiny fraction of the components available via XPConnect to programmers in Mozilla. This section describes how to find these components, create the corresponding JavaScript objects, and use them in your application programming.</pre>
<H3><A NAME="77066"></A> What Is XPConnect?</H3>    <p>The <tt>filepicker</tt>, <tt>file</tt>, and
<P>Until now,  <!--INDEX XPConnect:overview -->  <!--INDEX scripting:XPConnect, overview --> scripting has referred to scripting the DOM, manipulating various elements in the interface, and using methods available in Mozilla JavaScript files. However, for real applications like the Mozilla browser itself, this may be only the beginning. The UI must be hooked up to the application code and services (i.e., the application's actual functionality) to be more than just a visual interface. This is where XPConnect and XPCOM come in.    <tt>localfile</tt> components that these JavaScript objects
<P>Browsing the Web, reading email, and parsing XML files are examples of application-level services in Mozilla. They are part of Mozilla's lower-level functionality. This functionality is usually written and compiled in platform-native code and typically written in C++. This functionality is also most often organized into modules, which take advantage of Mozilla's cross-platform component object model (XPCOM), and are known as <I> <!--INDEX XPCOM components --> XPCOM components</I>. The relationship of these components and the application services they provide to the interface is shown in <A HREF="#77008">Figure 5-4</A>.    represent are a tiny fraction of the components available via
<P><CENTER><IMG SRC="foo.gif"></CENTER>    XPConnect to programmers in Mozilla. This section describes how
<P><I>Figure 5-4: <A NAME="77008"></A></I>    to find these components, create the corresponding JavaScript
<I>How XPConnect fits into the application model</I>    objects, and use them in your application programming.</p>
    <h3><a name="77066"></a> What Is XPConnect?</h3>
<P>In Mozilla, XPConnect is the bridge between JavaScript and XPCOM components. The XPConnect technology wraps natively compiled components with JavaScript objects. XPCOM, Mozilla's own cross-platform component technology, is the framework on top of which these scriptable components are built. Using JavaScript and XPConnect, you can create instances of these components and use their methods and properties as you do any regular JavaScript object, as described here. You can access any or all of the functionality in Mozilla in this way.    <p>Until now, <!--INDEX XPConnect:overview --> 
<P><A HREF="ch08.html#77048">Chapter 8</A> describes more about the XPConnect technology and how it connects components to the interface. It also     <!--INDEX scripting:XPConnect, overview --> scripting has
describes the components themselves and their interfaces, the XPCOM technology, and how you can create your own XPCOM components.    referred to scripting the DOM, manipulating various elements in
<H4><A NAME="77067"></A> Creating XPCOM objects in script</H4>    the interface, and using methods available in Mozilla
<P><A HREF="#77030">Example 5-10</A> demonstrates  <!--INDEX XPCOM:methods:JavaScript implementation -->  <!--INDEX JavaScript:XPCOM objects,     JavaScript files. However, for real applications like the
creating --> the creation and use of an  <!--INDEX XPCOM:components --> XPCOM component in JavaScript. In this example, the script instantiates the <TT>filepicker</TT> object and then uses it to display a file picker dialog with all of the file filters selected. To run this example, add the function to your <I>xfly.js</I> file and call it from an event handler on the "New" menu item you added in <A HREF="ch03.html#77042">Example 3-5</A>.    Mozilla browser itself, this may be only the beginning. The UI
    must be hooked up to the application code and services (i.e.,
Example 5-10<A NAME="77030"></A>    the application's actual functionality) to be more than just a
<I>Scriptable component example</I>    visual interface. This is where XPConnect and XPCOM come
<PRE> // chooseApp:  Open file picker and prompt user for application.    in.</p>
     <p>Browsing the Web, reading email, and parsing XML files are
     examples of application-level services in Mozilla. They are
     part of Mozilla's lower-level functionality. This functionality
     is usually written and compiled in platform-native code and
     typically written in C++. This functionality is also most often
     organized into modules, which take advantage of Mozilla's
     cross-platform component object model (XPCOM), and are known as
     <i><!--INDEX XPCOM components --> XPCOM components</i>. The
     relationship of these components and the application services
     they provide to the interface is shown in <a href=
     "#77008">Figure 5-4</a>.</p>
     <div class="c14">
       <img src="foo.gif">
     </div>
     <p><i>Figure 5-4: <a name="77008"></a></i> <i>How XPConnect
     fits into the application model</i></p>
     <p>In Mozilla, XPConnect is the bridge between JavaScript and
     XPCOM components. The XPConnect technology wraps natively
     compiled components with JavaScript objects. XPCOM, Mozilla's
     own cross-platform component technology, is the framework on
     top of which these scriptable components are built. Using
     JavaScript and XPConnect, you can create instances of these
     components and use their methods and properties as you do any
     regular JavaScript object, as described here. You can access
     any or all of the functionality in Mozilla in this way.</p>
     <p><a href="ch08.html#77048">Chapter 8</a> describes more about
     the XPConnect technology and how it connects components to the
     interface. It also describes the components themselves and
     their interfaces, the XPCOM technology, and how you can create
     your own XPCOM components.</p>
     <h4><a name="77067"></a> Creating XPCOM objects in script</h4>
     <p><a href="#77030">Example 5-10</a> demonstrates 
     <!--INDEX XPCOM:methods:JavaScript implementation --> 
     <!--INDEX JavaScript:XPCOM objects, 
     creating --> the creation and use of an 
     <!--INDEX XPCOM:components --> XPCOM component in JavaScript.
     In this example, the script instantiates the
     <tt>filepicker</tt> object and then uses it to display a file
     picker dialog with all of the file filters selected. To run
     this example, add the function to your <i>xfly.js</i> file and
     call it from an event handler on the "New" menu item you added
     in <a href="ch03.html#77042">Example 3-5</a>. Example 5-10<a
     name="77030"></a> <i>Scriptable component example</i></p>
 <pre>
  // chooseApp:  Open file picker and prompt user for application.
  chooseApp: function( ) {   chooseApp: function( ) {
    var nsIFilePicker = Components.interfaces.nsIFilePicker;     var nsIFilePicker = Components.interfaces.nsIFilePicker;
    var fp =     var fp =
      Components.classes</TD>["@mozilla.org/filepicker;1"].      Components.classes&lt;/td&gt;["@mozilla.org/filepicker;1"].
           createInstance( nsIFilePicker );            createInstance( nsIFilePicker );
    fp.init( this.mDialog,     fp.init( this.mDialog,
       this.getString( "chooseAppFilePickerTitle" ),        this.getString( "chooseAppFilePickerTitle" ),
Line 589  Example 5-10<A NAME="77030"></A> Line 1253  Example 5-10<A NAME="77030"></A>
    this.chosenApp  = fp.file;     this.chosenApp  = fp.file;
    // Update dialog.     // Update dialog.
    this.updateApplicationName(this.chosenApp.unicodePath);     this.updateApplicationName(this.chosenApp.unicodePath);
 }</PRE> }
</pre>
<P>Note the first two lines in the function and the way they work together to create the <TT>fp</TT> <TT>filepicker</TT> object. The first line in the function assigns the name of the <I>nsFile-picker</I> interface to the <TT>nsIFilePicker</TT> variable in JavaScript. This variable is used in the second line, where the instance is created from the component to specify which interface on that component should be used. Discovering and using library interfaces is an important aspect of XPCOM, where components always implement at least two interfaces.    <p>Note the first two lines in the function and the way they
<P>In <A HREF="#77032">Example 5-11</A>, an HTML file (stored locally, since it wouldn't have the required XPConnect access as a remote file because of security boundaries) loaded in Mozilla instantiates a Mozilla sound component and plays a sound with it. Go ahead and try it.    work together to create the <tt>fp</tt> <tt>filepicker</tt>
    object. The first line in the function assigns the name of the
Example 5-11<A NAME="77032"></A>    <i>nsFile-picker</i> interface to the <tt>nsIFilePicker</tt>
<I>Scripting components from HTML</I>    variable in JavaScript. This variable is used in the second
<PRE> &lt;html&gt;    line, where the instance is created from the component to
 &lt;head&gt;    specify which interface on that component should be used.
 &lt;title&gt;Sound Service Play Example&lt;/title&gt;    Discovering and using library interfaces is an important aspect
 &lt;/head&gt;    of XPCOM, where components always implement at least two
 &lt;body&gt;    interfaces.</p>
 &lt;script&gt;    <p>In <a href="#77032">Example 5-11</a>, an HTML file (stored
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");    locally, since it wouldn't have the required XPConnect access
   var url = Components.classes</TD>["@mozilla.org/network/standard-    as a remote file because of security boundaries) loaded in
       url;1"].createInstance( );    Mozilla instantiates a Mozilla sound component and plays a
   url = url.QueryInterface(Components.interfaces.nsIURL);    sound with it. Go ahead and try it. Example 5-11<a name=
   url.spec = "resource:/res/samples/test.wav";    "77032"></a> <i>Scripting components from HTML</i></p>
   var sample = Components.classes</TD>["@mozilla.org/sound;1"].createInstance( );<xmp>
   sample = sample.QueryInterface(Components.interfaces.nsISound);<html>
 &lt;/script&gt;  <head>
 &lt;form name="form"&gt;    <title>Sound Service Play Example</title>
   &lt;input type="button" value="Play Sound" onclick="sample.play(url);"&gt;    <script>
 &lt;form&gt;      function play() {
 &lt;/body&gt;        netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 &lt;/html&gt;</PRE>        var sample = Components.classes["@mozilla.org/sound;1"].createInstance();
        sample = sample.QueryInterface(Components.interfaces.nsISound);
<P>As in <A HREF="#77030">Example 5-10</A>, the classes[ ] array on the special Mozilla <TT>Components</TT> object refers to a particular         const SND_NETWORK_STD_CID = "@mozilla.org/network/standard-url;1";
component-in this case, the <TT>sound</TT> component-by contract ID. All XPCOM objects must have a contract ID that uniquely identifies them with         const SND_I_URL           = "nsIURL";
the domain, the component name, and a version number ["@mozilla.org/sound;1"], respectively. See the <A HREF="ch08.html#77058">"XPCOM Identifiers</A>" section in <A HREF="ch08.html#77048">Chapter 8</A> for more information about this.        const SND_URL             = new  C.Constructor(SND_NETWORK_STD_CID, SND_I_URL);
<H4><A NAME="77068"></A> Finding components and interfaces</H4>        var url                   = new SND_URL();
<P>Most <!--INDEX XPCOM:components:locating and viewing -->  components are scripted in Mozilla. In fact, the challenge is not to find cases when this scripting occurs (which you can learn by searching LXR for the <TT>Components</TT>), but to find Mozilla components that don't use scriptable components. Finding components and interfaces in Mozilla and seeing how they are used can be useful when writing your own application.        url.spec                  = 'http://jslib.mozdev.org/test.wav';
<P>The Mozilla  <!--INDEX Component Viewer development tool --> Component Viewer is a great tool for discovering components and provides a         sample.play(url);
convenient UI for seeing components and looking at their interfaces from within Mozilla. The Component Viewer can be built as an extension to Mozilla (see "cview" in the extensions directory of the Mozilla source), or it can be downloaded and installed as a separate  <!--INDEX web sites:Component Viewer --> XPI from <I><A HREF="http://www.hacksrus.com/~ginda/cview/">http://www.hacksrus.com/~ginda/cview/</A></I>. <A HREF="appb.html#77021">Appendix B</A> describes the Component Viewer in more detail.      }
<P>Commonly used XPCOM objects in the browser and other Mozilla applications include file objects, RDF services, URL objects, and category managers.    </script>
<H4><A NAME="77069"></A> Selecting the appropriate interface from the component</H4>  </head>
<P>In all cases,  <!--INDEX XPCOM:components:interfaces, selecting -->  <!--INDEX interfaces:XPCOM:components, selecting --> the way to get the object into script is to instantiate it with the special <TT>classes</TT> object and use the <TT>createInstance( )</TT> method on the class to select the interface you want to use. These two steps are often done together, as in the following example, which gets the component with the contract ID <TT>ldap-connection;1</TT>, instantiates an object from the <I>nsILDAPConnection</I> interface, and then calls a method on that object:  <body>
<PRE>var connection = Components.classes    <form name="form">
       <input type="button" value="Play Sound" onclick="play();">
     </form>
   </body>
 </html>
 </xmp>
     <p>As in <a href="#77030">Example 5-10</a>, the classes[ ]
     array on the special Mozilla <tt>Components</tt> object refers
     to a particular component-in this case, the <tt>sound</tt>
     component-by contract ID. All XPCOM objects must have a
     contract ID that uniquely identifies them with the domain, the
     component name, and a version number ["@mozilla.org/sound;1"],
     respectively. See the <a href="ch08.html#77058">"XPCOM
     Identifiers</a>" section in <a href="ch08.html#77048">Chapter
     8</a> for more information about this.</p>
     <h4><a name="77068"></a> Finding components and interfaces</h4>
     <p>Most <!--INDEX XPCOM:components:locating and viewing -->
     components are scripted in Mozilla. In fact, the challenge is
     not to find cases when this scripting occurs (which you can
     learn by searching LXR for the <tt>Components</tt>), but to
     find Mozilla components that don't use scriptable components.
     Finding components and interfaces in Mozilla and seeing how
     they are used can be useful when writing your own
     application.</p>
     <p>The Mozilla <!--INDEX Component Viewer development tool -->
     Component Viewer is a great tool for discovering components and
     provides a convenient UI for seeing components and looking at
     their interfaces from within Mozilla. The Component Viewer can
     be built as an extension to Mozilla (see "cview" in the
     extensions directory of the Mozilla source), or it can be
     downloaded and installed as a separate 
     <!--INDEX web sites:Component Viewer --> XPI from <i><a href=
     "http://www.hacksrus.com/~ginda/cview/">http://www.hacksrus.com/~ginda/cview/</a></i>.
     <a href="appb.html#77021">Appendix B</a> describes the
     Component Viewer in more detail.</p>
     <p>Commonly used XPCOM objects in the browser and other Mozilla
     applications include file objects, RDF services, URL objects,
     and category managers.</p>
     <h4><a name="77069"></a> Selecting the appropriate interface
     from the component</h4>
     <p>In all cases, 
     <!--INDEX XPCOM:components:interfaces, selecting --> 
     <!--INDEX interfaces:XPCOM:components, selecting --> the way to
     get the object into script is to instantiate it with the
     special <tt>classes</tt> object and use the <tt>createInstance(
     )</tt> method on the class to select the interface you want to
     use. These two steps are often done together, as in the
     following example, which gets the component with the contract
     ID <tt>ldap-connection;1</tt>, instantiates an object from the
     <i>nsILDAPConnection</i> interface, and then calls a method on
     that object:</p>
 <pre>
 var connection = Components.classes
 ["@mozilla.org/network/ldap-connection;1"].  ["@mozilla.org/network/ldap-connection;1"].
 createInstance(Components.interfaces.nsILDAPConnection);  createInstance(Components.interfaces.nsILDAPConnection);
 connection.init(queryURL.host, queryURL.port, null,  connection.init(queryURL.host, queryURL.port, null,
generateGetTargetsBoundCallback( ));</PRE>generateGetTargetsBoundCallback( ));
<P>These two common processes-getting a component and selecting one of its interfaces to assign to an object-can also be separated into two different statements:</pre>
<PRE>// get the ldap connection component    <p>These two common processes-getting a component and selecting
     one of its interfaces to assign to an object-can also be
     separated into two different statements:</p>
 <pre>
 // get the ldap connection component
 var connection = Components.classes  var connection = Components.classes
["@mozilla.org/network/ldap-connection;1";["@mozilla.org/network/ldap-connection;1"];
 // create an object from the nsILDAPConnection interface;  // create an object from the nsILDAPConnection interface;
 connection.createInstance(Components.interfaces.nsILDAPConnection);  connection.createInstance(Components.interfaces.nsILDAPConnection);
 // call the init( ) method on that object  // call the init( ) method on that object
 connection.init(queryURL.host, queryURL.port, null,  connection.init(queryURL.host, queryURL.port, null,
generateGetTargetsBoundCallback( ));</PRE>generateGetTargetsBoundCallback( ));
<P>Mozilla constantly uses these processes. Wherever functionality is organized into XPCOM objects (and most of it is), these two statements bring that functionality into JavaScript as high-level and user-friendly JavaScript objects.</pre>
<H2><A NAME="77070"></A> JavaScript Application Code</H2>    <p>Mozilla constantly uses these processes. Wherever
<P>There are <!--INDEX JavaScript:application programming:overview -->  <!--INDEX application programming, JavaScript:overview -->  two ways to use JavaScript in the third, deepest level of application programming. The first is to organize your JavaScript into libraries so your functions can be reused, distributed, and perhaps collaborated upon.    functionality is organized into XPCOM objects (and most of it
<P>The second way is to write a JavaScript component, create a separate interface for that component, and compile it as an XPCOM component whose     is), these two statements bring that functionality into
methods and data can be accessed from XPConnect (using JavaScript). This kind of application programming is described in <A HREF="ch08.html#77048">Chapter 8</A>, which includes examples of creating new interfaces, implementing them in JavaScript or C++, and compiling, testing, and using the resulting component in the Mozilla interface.    JavaScript as high-level and user-friendly JavaScript
<P>This section introduces the library organization method of JavaScript application programming. The JSLib code discussed here is a group of JavaScript libraries currently being developed by Mozilla contributors and is especially useful for working with the XPFE and other aspects of the Mozilla application/package programming model. When you include the right source files at the top of your JavaScript and/or XUL file, you can use the functions defined in JSLib libraries as you would use any third-party library or built-in functions. You may even want to contribute to the JSLib project yourself if you think functionality is missing and as your Mozilla programming skills grow.    objects.</p>
<H3><A NAME="77071"></A> JavaScript Libraries</H3>    <h2><a name="77070"></a> JavaScript Application Code</h2>
<P>The open  <!--INDEX JSLib libraries -->  <!--INDEX JavaScript:application programming:JSLib -->  <!--INDEX application programming, JavaScript:JSLib --> source JSLib project makes life easier for developers. The JSLib package implements some of the key XPCOM components just discussed and wraps them in simpler, JavaScript interfaces, which means that you can use the services of common XPCOM components without having to do any of the instantiation, interface selection, or glue code yourself. Collectively, these interfaces are intended to provide a general-purpose library for Mozilla application developers. To understand what JSLib does, consider the following short snippet from the JSLib source file <I>jslib/io/file.js</I>, which implements a <TT>close( )</TT> function for open file objects and provides a handy way to clean up things when you finish editing a file in the filesystem.    <p>There are 
<PRE>/********************* CLOSE ********************************    <!--INDEX JavaScript:application programming:overview --> 
     <!--INDEX application programming, JavaScript:overview --> two
     ways to use JavaScript in the third, deepest level of
     application programming. The first is to organize your
     JavaScript into libraries so your functions can be reused,
     distributed, and perhaps collaborated upon.</p>
     <p>The second way is to write a JavaScript component, create a
     separate interface for that component, and compile it as an
     XPCOM component whose methods and data can be accessed from
     XPConnect (using JavaScript). This kind of application
     programming is described in <a href="ch08.html#77048">Chapter
     8</a>, which includes examples of creating new interfaces,
     implementing them in JavaScript or C++, and compiling, testing,
     and using the resulting component in the Mozilla interface.</p>
     <p>This section introduces the library organization method of
     JavaScript application programming. The JSLib code discussed
     here is a group of JavaScript libraries currently being
     developed by Mozilla contributors and is especially useful for
     working with the XPFE and other aspects of the Mozilla
     application/package programming model. When you include the
     right source files at the top of your JavaScript and/or XUL
     file, you can use the functions defined in JSLib libraries as
     you would use any third-party library or built-in functions.
     You may even want to contribute to the JSLib project yourself
     if you think functionality is missing and as your Mozilla
     programming skills grow.</p>
     <h3><a name="77071"></a> JavaScript Libraries</h3>
     <p>The open <!--INDEX JSLib libraries --> 
     <!--INDEX JavaScript:application programming:JSLib --> 
     <!--INDEX application programming, JavaScript:JSLib --> source
     JSLib project makes life easier for developers. The JSLib
     package implements some of the key XPCOM components just
     discussed and wraps them in simpler, JavaScript interfaces,
     which means that you can use the services of common XPCOM
     components without having to do any of the instantiation,
     interface selection, or glue code yourself. Collectively, these
     interfaces are intended to provide a general-purpose library
     for Mozilla application developers. To understand what JSLib
     does, consider the following short snippet from the JSLib
     source file <i>jslib/io/file.js</i>, which implements a
     <tt>close( )</tt> function for open file objects and provides a
     handy way to clean up things when you finish editing a file in
     the filesystem.</p>
 <pre>
 /********************* CLOSE ********************************
 * void close( )                                              *  * void close( )                                              *
 *                                                           *  *                                                           *
 * void file close                                           *  * void file close                                           *
Line 678  if(this.mLineBuffer)     this.mLineBuffe Line 1442  if(this.mLineBuffer)     this.mLineBuffe
 this.mPosition           = 0;  this.mPosition           = 0;
 /***************** Destroy Instances *********************/  /***************** Destroy Instances *********************/
 return;  return;
}</PRE>}
<P>To use the <TT>close</TT> method as it's defined here, import the <I>file.js</I> source file into your JavaScript, create a file object (as shown in the examples below), and call its <TT>close( )</TT> method.</pre>
<BLOCKQUOTE><HR><B>xpcshell</B>    <p>To use the <tt>close</tt> method as it's defined here,
<P>Most  <!--INDEX xpcshell -->  <!--INDEX shells:xpcshell -->  <!--INDEX JavaScript:xpcshell --> examples in this section are in <I>xpcshell</I>, but using these libraries in your user interface JavaScript is just as easy. You can access these libraries from a XUL file, as the section <A HREF="#77077">"Using the DirUtils class</A>," later in this chapter, demonstrates.    import the <i>file.js</i> source file into your JavaScript,
<P>xpcshell is the command-line interpreter to JavaScript and XPConnect. This shell that uses XPConnect to call and instantiate scriptable XPCOM interfaces. It is used primarily for debugging and testing scripts.    create a file object (as shown in the examples below), and call
<P>To run xpcshell, you need to go to the Mozilla <I>bin</I> directory or have that folder in your PATH. For each platform, enter:    its <tt>close( )</tt> method.</p>
<P>Windows:    <blockquote>
<PRE>xpcshell.exe</PRE>      <hr>
Unix:      <b>xpcshell</b> 
<PRE>./run-mozilla.sh ./xpcshell</PRE>      <p>Most <!--INDEX xpcshell --> <!--INDEX shells:xpcshell --> 
To run xpcshell on Unix, you need to supply environment variables that the interpreter needs. You can use the <I>run-mozilla.sh</I> shell script that resides in the Mozilla <I>bin</I> directory.      <!--INDEX JavaScript:xpcshell --> examples in this section
<PRE>$ ./run-mozilla.sh ./xpcshell</PRE>      are in <i>xpcshell</i>, but using these libraries in your
To see the available options for xpcshell, type this:<HR></BLOCKQUOTE>      user interface JavaScript is just as easy. You can access
$ ./run-mozilla.sh ./xpcshell --help      these libraries from a XUL file, as the section <a href=
JavaScript-C 1.5 pre-release 4a 2002-03-21      "#77077">"Using the DirUtils class</a>," later in this
usage: xpcshell [-s] [-w] [-W] [-v version] [-f scriptfile] [scriptfile] [scriptarg...]      chapter, demonstrates.</p>
</PRE>      <p>xpcshell is the command-line interpreter to JavaScript and
The two most important parameters here are -w, which enables warnings output, and -s, which turns on strict mode.<HR></BLOCKQUOTE>      XPConnect. This shell that uses XPConnect to call and
      instantiate scriptable XPCOM interfaces. It is used primarily
<P>The source files for JSLib are well annotated and easy to read. JSLib provide easy-to-use interfaces for creating instances of components (e.g., File objects), performing necessary error checking, and ensuring proper usage. To use a function like the one just shown, simply include the source file you need in your XUL:      for debugging and testing scripts.</p>
<PRE>&lt;script type="application/x-JavaScript"      <p>To run xpcshell, you need to go to the Mozilla <i>bin</i>
src="chrome://jslib/content/jslib.js" /&gt;</PRE>      directory or have that folder in your PATH. For each
<P>Then you can include the specific library files you need in your JavaScript code by using the include method:      platform, enter:</p>
<PRE>include("chrome://jslib/content/io/file.js");      <p>Windows:</p>
include("chrome://jslib/content/zip/zip.js");</PRE><pre>
<H4><A NAME="77072"></A> Installing JSLib</H4>xpcshell.exe
<P>To use the <!--INDEX installation:JSLib -->  <!--INDEX JSLib libraries:installing -->  <!--INDEX JavaScript:application programming:installing </pre>
JSLib -->  <!--INDEX application programming, JavaScript:installing JSLib -->  JavaScript libraries, install the JSLib package in Mozilla. The package is available as a tarball, a zip file, or as CVS sources. The easiest way to obtain it is to install it from the Web using Mozilla's XPInstall technology, described in <A HREF="ch06.html#77063">Chapter 6</A>.      Unix: 
<P>Using your Mozilla browser, go to <I><A HREF="http://jslib.mozdev.org/installation.html">http://jslib.mozdev.org/installation.html</A></I> and click the installation hyperlink. The link uses XPInstall to install JSLIB and make it available to you in Mozilla. To test whether it is installed properly, type the following code in your shell:<pre>
<PRE>./mozilla -chrome chrome://jslib/content/</PRE>./run-mozilla.sh ./xpcshell
<P>You should see a simple window that says "welcome to jslib."</pre>
<H4><A NAME="77073"></A> The JSLib libraries</H4>      To run xpcshell on Unix, you need to supply environment
<P>Currently  <!--INDEX classes:JSLib -->  <!--INDEX JSLib libraries:classes -->  <!--INDEX JavaScript:application programming:JSLib classes -->  <!--INDEX application programming, JavaScript:JSLib classes --> available JavaScript functions in the JSLib package are divided into different modules that, in turn, are divided into different classes defined in source files such as <I>file.js</I>, <I>dir.js</I>, and <I>fileUtils.js</I>. <A HREF="#77010">Table 5-1</A> describes the basic classes in the JSLib package's I/O module and describes how they are used.      variables that the interpreter needs. You can use the
      <i>run-mozilla.sh</i> shell script that resides in the
<P><I>Table 5-1: <A NAME="77010"></A></I>      Mozilla <i>bin</i> directory. 
<I>JSLib classes</I><pre>
<P><TABLE WIDTH=100% BORDER=1><TR><TD><B>  Class / (filename)</B></TD> <TD><B>  Description</B></TD></TR>$ ./run-mozilla.sh ./xpcshell
<TR><TD>  File / (</TD><I>file.js</I>)     <TD>  Contains most routines associated with the File object (implementing </TD><TT>nsIFile</TT>). The library is part of the jslib I/O module.</TR></pre>
<TR><TD>  FileUtils / (</TD><I>fileUtils.js</I>)     <TD>  The chrome registry to local file path conversion, file metadata, etc.</TD></TR>      To see the available options for xpcshell, type this:
<TR><TD>  Dir / (</TD><I>dir.js</I>)     <TD>  Directory creation; variations of directory listings.</TD></TR>      <hr>
<TR><TD>  DirUtils / (</TD><I>dirUtils.js</I>)     <TD>  Paths to useful Mozilla directories and files such as </TD><I>chrome</I>, <I>prefs</I>, <I>bookmarks</I>, <I>localstore</I>, etc.</TR></TABLE><P>    </blockquote>
    $ ./run-mozilla.sh ./xpcshell --help JavaScript-C 1.5
<H4><A NAME="77074"></A> Using the File class</H4>    pre-release 4a 2002-03-21 usage: xpcshell [-s] [-w] [-W] [-v
<P>The JSLib <TT>File</TT>  <!--INDEX classes:JSLib:File -->  <!--INDEX File class, JSLib -->  <!--INDEX JSLib libraries:File class -->  <!--INDEX JavaScript:application programming:JSLib File class -->  <!--INDEX application programming, JavaScript:JSLib File class --> class exposes most local file routines from the <I>nsIFile</I> interface. The <TT>File</TT> class is part of the JSLib I/O module, and is defined in <I>jslib/io/file.js</I>. Here is how you load the library from xpcshell:    version] [-f scriptfile] [scriptfile] [scriptarg...]  The two
<PRE>$ ./run-mozilla.sh ./xpcshell -w -s    most important parameters here are -w, which enables warnings
js&gt; load(`chrome/jslib/jslib.js');    output, and -s, which turns on strict mode.
     <hr>
     <p>The source files for JSLib are well annotated and easy to
     read. JSLib provide easy-to-use interfaces for creating
     instances of components (e.g., File objects), performing
     necessary error checking, and ensuring proper usage. To use a
     function like the one just shown, simply include the source
     file you need in your XUL:</p>
 <pre>
 &lt;script type="application/x-JavaScript"
 src="chrome://jslib/content/jslib.js" /&gt;
 </pre>
     <p>Then you can include the specific library files you need in
     your JavaScript code by using the include method:</p>
 <pre>
 include("chrome://jslib/content/io/file.js");
 include("chrome://jslib/content/zip/zip.js");
 </pre>
     <h4><a name="77072"></a> Installing JSLib</h4>
     <p>To use the <!--INDEX installation:JSLib --> 
     <!--INDEX JSLib libraries:installing --> 
     <!--INDEX JavaScript:application programming:installing 
     JSLib --> 
     <!--INDEX application programming, JavaScript:installing JSLib -->
     JavaScript libraries, install the JSLib package in Mozilla. The
     package is available as a tarball, a zip file, or as CVS
     sources. The easiest way to obtain it is to install it from the
     Web using Mozilla's XPInstall technology, described in <a href=
     "ch06.html#77063">Chapter 6</a>.</p>
     <p>Using your Mozilla browser, go to <i><a href=
     "http://jslib.mozdev.org/installation.html">http://jslib.mozdev.org/installation.html</a></i>
     and click the installation hyperlink. The link uses XPInstall
     to install JSLIB and make it available to you in Mozilla. To
     test whether it is installed properly, type the following code
     in your shell:</p>
 <pre>
 ./mozilla -chrome chrome://jslib/content/
 </pre>
     <p>You should see a simple window that says "welcome to
     jslib."</p>
     <h4><a name="77073"></a> The JSLib libraries</h4>
     <p>Currently <!--INDEX classes:JSLib --> 
     <!--INDEX JSLib libraries:classes --> 
     <!--INDEX JavaScript:application programming:JSLib classes --> 
     <!--INDEX application programming, JavaScript:JSLib classes -->
     available JavaScript functions in the JSLib package are divided
     into different modules that, in turn, are divided into
     different classes defined in source files such as
     <i>file.js</i>, <i>dir.js</i>, and <i>fileUtils.js</i>. <a
     href="#77010">Table 5-1</a> describes the basic classes in the
     JSLib package's I/O module and describes how they are used.</p>
     <p><i>Table 5-1: <a name="77010"></a></i><i>JSLib
     classes</i></p>
     <table width="100%" border="1">
       <tbody>
         <tr>
           <td><b>Class / (filename)</b></td>
           <td><b>Description</b></td>
         </tr>
         <tr>
           <td>File / (<i>file.js</i>)</td>
           <td>Contains most routines associated with the File
           object (implementing <tt>nsIFile</tt>). The library is
           part of the jslib I/O module.</td>
         </tr>
         <tr>
           <td>FileUtils / (<i>fileUtils.js</i>)</td>
           <td>The chrome registry to local file path conversion,
           file metadata, etc.</td>
         </tr>
         <tr>
           <td>Dir / (<i>dir.js</i>)</td>
           <td>Directory creation; variations of directory
           listings.</td>
         </tr>
         <tr>
           <td>DirUtils / (<i>dirUtils.js</i>)</td>
           <td>Paths to useful Mozilla directories and files such as
           <i>chrome</i>, <i>prefs</i>, <i>bookmarks</i>,
           <i>localstore</i>, etc.</td>
         </tr>
       </tbody>
     </table>
     <br>
     <br>
      
     <h4><a name="77074"></a> Using the File class</h4>
     <p>The JSLib <tt>File</tt> <!--INDEX classes:JSLib:File --> 
     <!--INDEX File class, JSLib --> 
     <!--INDEX JSLib libraries:File class --> 
     <!--INDEX JavaScript:application programming:JSLib File class -->
     <!--INDEX application programming, JavaScript:JSLib File class -->
     class exposes most local file routines from the <i>nsIFile</i>
     interface. The <tt>File</tt> class is part of the JSLib I/O
     module, and is defined in <i>jslib/io/file.js</i>. Here is how
     you load the library from xpcshell:</p>
 <pre>
 $ ./run-mozilla.sh ./xpcshell -w -s
 js&gt; load('chrome/jslib/jslib.js');
 *********************  *********************
 JS_LIB DEBUG IS ON  JS_LIB DEBUG IS ON
 *********************  *********************
js&gt;</PRE>js&gt;
<P>Once JSLib is loaded, you can load the <TT>File</TT> module with an <TT>include</TT> statement:</pre>
<PRE>js&gt; include(`chrome://jslib/content/io/file.js');    <p>Once JSLib is loaded, you can load the <tt>File</tt> module
     with an <tt>include</tt> statement:</p>
 <pre>
 js&gt; include(`chrome://jslib/content/io/file.js');
 *** Chrome Registration of package: Checking for contents.rdf at  *** Chrome Registration of package: Checking for contents.rdf at
 resource:/chrome/jslib/  resource:/chrome/jslib/
 *** load: filesystem.js OK  *** load: filesystem.js OK
 *** load: file.js OK  *** load: file.js OK
 true  true
js&gt;</PRE>js&gt;
<P>Note that <I>file.js</I> loads <I>filesystem.js</I> in turn. The class <TT>FileSystem</TT> in <I>filesystem.js</I> is the base class for the <TT>File</TT> object. You can also load <I>file.js</I> by using the top-level construct <TT>JS_LIB_PATH</TT>:</pre>
<PRE>js&gt; include(JS_LIB_PATH+'io/file.js');</PRE>    <p>Note that <i>file.js</i> loads <i>filesystem.js</i> in turn.
<P>Once you have the <I>file.js</I> module loaded, you can create an instance of a <TT>File</TT> object and call methods on it to manipulate the file and path it represents:    The class <tt>FileSystem</tt> in <i>filesystem.js</i> is the
<PRE>js&gt; var f = new File('/tmp/foo');    base class for the <tt>File</tt> object. You can also load
     <i>file.js</i> by using the top-level construct
     <tt>JS_LIB_PATH</tt>:</p>
 <pre>
 js&gt; include(JS_LIB_PATH+'io/file.js');
 </pre>
     <p>Once you have the <i>file.js</i> module loaded, you can
     create an instance of a <tt>File</tt> object and call methods
     on it to manipulate the file and path it represents:</p>
 <pre>
 js&gt; var f = new File('/tmp/foo');
 js&gt; f;  js&gt; f;
 [object Object]  [object Object]
 js&gt; f.help; // listing of everything available to the object  js&gt; f.help; // listing of everything available to the object
Line 762  js&gt; f.open( );     // open the file a Line 1637  js&gt; f.open( );     // open the file a
 js&gt; f.read( );     // read back the data  js&gt; f.read( );     // read back the data
 // you can also use default flag 'r' for reading  // you can also use default flag 'r' for reading
 this is line #1  this is line #1
js&gt; f.close( );</PRE>js&gt; f.close( );
<P>You can also assign the contents of the file to a variable for later use, iterative loops through the file contents, or updates to the data:</pre>
<PRE>js&gt; f.open( );    <p>You can also assign the contents of the file to a variable
     for later use, iterative loops through the file contents, or
     updates to the data:</p>
 <pre>
 js&gt; f.open( );
 true  true
 js&gt; var contents = f.read( );  js&gt; var contents = f.read( );
 js&gt; f.close( );  js&gt; f.close( );
Line 776  js&gt; f.move(`/tmp/foo.dat'); Line 1655  js&gt; f.move(`/tmp/foo.dat');
 foo.dat  foo.dat
 filesystem.js:move successful!  filesystem.js:move successful!
 js&gt; f.path;  js&gt; f.path;
/tmp/foo.dat</PRE>/tmp/foo.dat
<P>These examples show some ways the JSLib <TT>File</TT> object can manipulate local files. Using these interfaces can make life a lot easier by letting you focus on creating your Mozilla application without having to implement XPCOM <TT>nsIFile</TT> objects manually from your script.</pre>
<H4><A NAME="77075"></A> Using the FileUtils class</H4>    <p>These examples show some ways the JSLib <tt>File</tt> object
<P>To create an  <!--INDEX classes:JSLib:FileUtils -->  <!--INDEX FileUtils class, JSLib -->  <!--INDEX JSLib libraries:FileUtils class -->  <!--INDEX JavaScript:application programming:JSLib FileUtils class -->  <!--INDEX application programming, JavaScript:JSLib FileUtils class --> instance of the <TT>FileUtils</TT> class, use the <TT>FileUtils</TT> constructor:    can manipulate local files. Using these interfaces can make
<PRE>js&gt; var fu = new FileUtils( );    life a lot easier by letting you focus on creating your Mozilla
     application without having to implement XPCOM <tt>nsIFile</tt>
     objects manually from your script.</p>
     <h4><a name="77075"></a> Using the FileUtils class</h4>
     <p>To create an <!--INDEX classes:JSLib:FileUtils --> 
     <!--INDEX FileUtils class, JSLib --> 
     <!--INDEX JSLib libraries:FileUtils class --> 
     <!--INDEX JavaScript:application programming:JSLib FileUtils class -->
     <!--INDEX application programming, JavaScript:JSLib FileUtils class -->
     instance of the <tt>FileUtils</tt> class, use the
     <tt>FileUtils</tt> constructor:</p>
 <pre>
 js&gt; var fu = new FileUtils( );
 js&gt; fu;  js&gt; fu;
[object Object]</PRE>[object Object]
<P>Then look at the object by calling its <TT>help</TT> method:</pre>
<PRE>js&gt; fu.help;</PRE>    <p>Then look at the object by calling its <tt>help</tt>
<P>The difference between using the <I>File</I> and <I>FileUtils</I> interfaces is that methods and properties on the latter are <I>singleton</I> and require a path argument, while the <I>FileUtils</I> utilities are general purpose and not bound to any particular file. The <I>FileUtils</I> interface has several handy I/O utilities for converting, testing, and using URLs, of which this example shows a few:    method:</p>
<PRE>js&gt; fu.exists('/tmp');<pre>
 js&gt; fu.help;
 </pre>
     <p>The difference between using the <i>File</i> and
     <i>FileUtils</i> interfaces is that methods and properties on
     the latter are <i>singleton</i> and require a path argument,
     while the <i>FileUtils</i> utilities are general purpose and
     not bound to any particular file. The <i>FileUtils</i>
     interface has several handy I/O utilities for converting,
     testing, and using URLs, of which this example shows a few:</p>
 <pre>
 js&gt; fu.exists('/tmp');
 true  true
 // convert a chrome path to a url  // convert a chrome path to a url
 js&gt; fu.chromeToPath('chrome://jslib/content/');  js&gt; fu.chromeToPath('chrome://jslib/content/');
 /usr/src/mozilla/dist/bin/chrome/jslib/jslib.xul  /usr/src/mozilla/dist/bin/chrome/jslib/jslib.xul
 // convert a file URL path to a local file path  // convert a file URL path to a local file path
 js&gt; fu.urlToPath('file:///tmp/foo.dat');  js&gt; fu.urlToPath('file:///tmp/foo.dat');
/tmp/foo.dat</PRE>/tmp/foo.dat
<P>Most methods on the <TT>FileUtils</TT> objects are identical to the methods found in <I>file.js</I>, except they require a path argument. Another handy method in the <TT>FileUtils</TT> class is <TT>spawn</TT>, which spawns an external executable from the operating system. It's used as follows:</pre>
<PRE>js&gt; fu.spawn('/usr/X11R6/bin/Eterm');</PRE>    <p>Most methods on the <tt>FileUtils</tt> objects are identical
<P>This command spawns a new Eterm with no argument. To open an Eterm with vi, you could also use this code:    to the methods found in <i>file.js</i>, except they require a
<PRE>js&gt; fu.spawn('/usr/X11R6/bin/Eterm', ['-e/usr/bin/vi']);</PRE>    path argument. Another handy method in the <tt>FileUtils</tt>
<P>Checking to see if three different files exist would take several lines when using the File class, but the <TT>FileUtils</TT> class is optimized for this type of check, as the following listing shows:    class is <tt>spawn</tt>, which spawns an external executable
<PRE>js&gt; var fu=new FileUtils( );    from the operating system. It's used as follows:</p>
 <pre>
 js&gt; fu.spawn('/usr/X11R6/bin/Eterm');
 </pre>
     <p>This command spawns a new Eterm with no argument. To open an
     Eterm with vi, you could also use this code:</p>
 <pre>
 js&gt; fu.spawn('/usr/X11R6/bin/Eterm', ['-e/usr/bin/vi']);
 </pre>
     <p>Checking to see if three different files exist would take
     several lines when using the File class, but the
     <tt>FileUtils</tt> class is optimized for this type of check,
     as the following listing shows:</p>
 <pre>
 js&gt; var fu=new FileUtils( );
 js&gt; fu.exists('/tmp');  js&gt; fu.exists('/tmp');
 true  true
 js&gt; fu.exists('/tmp/foo.dat');  js&gt; fu.exists('/tmp/foo.dat');
 true  true
 js&gt; fu.exists('/tmp/foo.baz');  js&gt; fu.exists('/tmp/foo.baz');
false</PRE>false
<P>You need to initialize the <TT>FileUtils</TT> class only once to use its members and handle local files robustly.</pre>
<H4><A NAME="77076"></A> Using the Dir class</H4>    <p>You need to initialize the <tt>FileUtils</tt> class only
<P>The <TT>Dir</TT>  <!--INDEX classes:JSLib:Dir -->  <!--INDEX Dir class, JSLib -->  <!--INDEX JSLib libraries:Dir class -->  <!--INDEX JavaScript:application programming:JSLib Dir class -->  <!--INDEX application programming, JavaScript:JSLib Dir class --> class is custom-made for working with directory structures on a local filesystem. To create an instance of the <TT>Dir</TT> class, call its constructor and then its <TT>help</TT> method to see the class properties:    once to use its members and handle local files robustly.</p>
<PRE>js&gt; var d = new Dir('/tmp');    <h4><a name="77076"></a> Using the Dir class</h4>
js&gt; d.help;</PRE>    <p>The <tt>Dir</tt> <!--INDEX classes:JSLib:Dir --> 
<P><TT>Dir</TT> inherits from the same base class as <TT>File</TT>, which is why it looks similar, but it implements methods used specifically for directory manipulation:    <!--INDEX Dir class, JSLib --> 
<PRE>js&gt; d.path;    <!--INDEX JSLib libraries:Dir class --> 
     <!--INDEX JavaScript:application programming:JSLib Dir class -->
     <!--INDEX application programming, JavaScript:JSLib Dir class -->
     class is custom-made for working with directory structures on a
     local filesystem. To create an instance of the <tt>Dir</tt>
     class, call its constructor and then its <tt>help</tt> method
     to see the class properties:</p>
 <pre>
 js&gt; var d = new Dir('/tmp');
 js&gt; d.help;
 </pre>
     <p><tt>Dir</tt> inherits from the same base class as
     <tt>File</tt>, which is why it looks similar, but it implements
     methods used specifically for directory manipulation:</p>
 <pre>
 js&gt; d.path;
 /tmp  /tmp
 js&gt; d.exists( );  js&gt; d.exists( );
 true  true
 js&gt; d.isDir( );  js&gt; d.isDir( );
true</PRE>true
<P>The methods all work like those in the <TT>File</TT> and <TT>FileUtils</TT> classes, so you can append a new directory name to the object, see if it exists, and create it if (it does not) by entering:</pre>
<PRE>js&gt; d.append('newDir');    <p>The methods all work like those in the <tt>File</tt> and
     <tt>FileUtils</tt> classes, so you can append a new directory
     name to the object, see if it exists, and create it if (it does
     not) by entering:</p>
 <pre>
 js&gt; d.append('newDir');
 /tmp/newDir  /tmp/newDir
 js&gt; d.path;  js&gt; d.path;
 /tmp/newDir  /tmp/newDir
Line 827  js&gt; d.exists( ); Line 1763  js&gt; d.exists( );
 false  false
 js&gt; d.create( );  js&gt; d.create( );
 js&gt; d.exists( );  js&gt; d.exists( );
true</PRE>true
<H4><A NAME="77077"></A> Using the DirUtils class</H4></pre>
<P>Note that  <!--INDEX classes:JSLib:DirUtils -->  <!--INDEX DirUtils class, JSLib -->  <!--INDEX JSLib libraries:DirUtils class -->  <!--INDEX JavaScript:application programming:JSLib DirUtils class -->  <!--INDEX application programming, JavaScript:JSLib DirUtils class --> some methods in the <TT>DirUtils</TT> class cannot be called from xpcshell and instead must be called from a XUL window into which the proper JSLib source file was imported. The following XUL file provides two buttons that display information in textboxes about the system directories:    <h4><a name="77077"></a> Using the DirUtils class</h4>
<PRE>&lt;?xml version="1.0"?&gt;    <p>Note that <!--INDEX classes:JSLib:DirUtils --> 
     <!--INDEX DirUtils class, JSLib --> 
     <!--INDEX JSLib libraries:DirUtils class --> 
     <!--INDEX JavaScript:application programming:JSLib DirUtils class -->
     <!--INDEX application programming, JavaScript:JSLib DirUtils class -->
     some methods in the <tt>DirUtils</tt> class cannot be called
     from xpcshell and instead must be called from a XUL window into
     which the proper JSLib source file was imported. The following
     XUL file provides two buttons that display information in
     textboxes about the system directories:</p>
 <pre>
 &lt;?xml version="1.0"?&gt;
 &lt;?xml-stylesheet href="chrome://global/skin" type="text/css"?&gt;  &lt;?xml-stylesheet href="chrome://global/skin" type="text/css"?&gt;
&lt;window xmlns="<A HREF="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul</A>"&lt;window xmlns="<a href=
xmlns:html="<A HREF="http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</A>""http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul</a>"
 xmlns:html="<a href=
 "http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml</a>"
 id="dir-utils-window"  id="dir-utils-window"
 orient="vertical"  orient="vertical"
 autostretch="never"&gt;  autostretch="never"&gt;
Line 859  textfield2.setAttribute("value", md); Line 1808  textfield2.setAttribute("value", md);
 &lt;button id="moz" onclick="getMozDir( );" label="mozdir" /&gt;  &lt;button id="moz" onclick="getMozDir( );" label="mozdir" /&gt;
 &lt;textbox id="tf2" value="moz dir" /&gt;  &lt;textbox id="tf2" value="moz dir" /&gt;
 &lt;/box&gt;  &lt;/box&gt;
&lt;/window&gt;</PRE>&lt;/window&gt;
<HR></pre>
<HR><A NAME="260"></A><A HREF="#b260">[Back]</A>    <hr>
<A NAME="77034"></A>    <hr>
This book does not pretend    <a name="260"></a><a href="#b260">[Back]</a> <a name=
to give a complete overview of JavaScript. You    "77034"></a> This book does not pretend to give a complete
can view the full JavaScript 1.5 reference online    overview of JavaScript. You can view the full JavaScript 1.5
at    reference online at <i><a href=
<I><A HREF="http://developer.netscape.com/docs/manuals/js/">http://developer.netscape.com/docs/manuals/js/</A></I>    "http://developer.netscape.com/docs/manuals/index.html?content=javascript.html">
core/jsref15/contents.html.    http://developer.netscape.com/docs/manuals/index.html?content=javascript.html</a></i>.
<HR><A NAME="261"></A><A HREF="#b261">[Back]</A>    
<A NAME="77035"></A>    <hr>
The third edition of the EMCA-262 EMCAScript    <a name="261"></a><a href="#b261">[Back]</a> <a name=
Language Specification can be found at    "77035"></a> The third edition of the EMCA-262 EMCAScript
<I><A HREF="http://www.ecma.ch/ecma1/STAND/ECMA-262.HTM">http://www.ecma.ch/ecma1/STAND/ECMA-262.HTM</A>.</I>    Language Specification can be found at <i><a href=
<HR><A NAME="262"></A><A HREF="#b262">[Back]</A>    "http://www.ecma.ch/ecma1/STAND/ECMA-262.HTM">http://www.ecma.ch/ecma1/STAND/ECMA-262.HTM</a>.</i>
<A NAME="77036"></A>    
You can use other DOM methods, but these    <hr>
methods are most commonly used in the XPFE. Mozilla's support for    <a name="262"></a><a href="#b262">[Back]</a> <a name=
the DOM is so thorough that you can use the W3C specifications as a    "77036"></a> You can use other DOM methods, but these methods
list of methods and properties available to you in the chrome and in    are most commonly used in the XPFE. Mozilla's support for the
the web content the browser displays. The full W3C activity pages,    DOM is so thorough that you can use the W3C specifications as a
including links to the specifications implemented by Mozilla, can be    list of methods and properties available to you in the chrome
found at    and in the web content the browser displays. The full W3C
<I><A HREF="http://www.w3.org/DOM/">http://www.w3.org/DOM/</A></I>    activity pages, including links to the specifications
.    implemented by Mozilla, can be found at <i><a href=
<HR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR>    "http://www.w3.org/DOM/">http://www.w3.org/DOM/</a></i> . 
<BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR><BR></BODY>    <hr>
</HTML>    <br>
     <br>
     File a <a href=
     "http://mozdev.org/bugs/enter_bug.cgi?product=books">Bug</a>
     for chapter 5. <!-- ?php require(NOTES); ? -->
     <?php $post_to_list=NO; $author='reviewers@mozdev.org'; $target_page='ch05'; require(NOTES); ?>

Removed from v.1.2  
changed lines
  Added in v.1.19


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