File:  [mozdev] / books / www / chapters / ch05.html
Revision 1.12: download - view: text, annotated - select for diffs - revision graph
Wed Dec 11 18:57:10 2002 UTC (17 years, 5 months ago) by petejc
Branches: MAIN
CVS tags: HEAD
cleaned up html code w/ html tidy


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

FreeBSD-CVSweb <>