Creating Applications with Mozilla-Chapter 5. Scripting Mozilla- P1

Chia sẻ: Thanh Cong | Ngày: | Loại File: PDF | Số trang:21

0
35
lượt xem
4
download

Creating Applications with Mozilla-Chapter 5. Scripting Mozilla- P1

Mô tả tài liệu
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Tham khảo tài liệu 'creating applications with mozilla-chapter 5. scripting mozilla- p1', công nghệ thông tin, kỹ thuật lập trình phục vụ nhu cầu học tập, nghiên cứu và làm việc hiệu quả

Chủ đề:
Lưu

Nội dung Text: Creating Applications with Mozilla-Chapter 5. Scripting Mozilla- P1

  1. Chapter 5. Scripting Mozilla- P1 In Mozilla, scripting plays important roles in the XPFE. Whether developers refer to script access and security, user interface logic, XPCOM object invocation, or script execution in element event handlers, scripting is so integral to application development that Mozilla, as a development platform, would be inconceivable without it. The core scripting language used in Mozilla is JavaScript. Although it has had a reputation as an unsophisticated language used mostly in web pages, JavaScript is more like a first-tier programming language. Modularity, good exception handing, regular expression enhancement, and number formatting are just some features of the new JavaScript 1.5,[1] which is based on the ECMA-262 standard.[2] JavaScript 2.0, due sometime late in 2002, promises to be an even bigger promotion of the language. Three distinct levels of JavaScript are identified in this chapter. A user interface level manipulates content through the DOM, a client layer calls on the services provided by XPCOM, and, finally, an application layer is available in which JavaScript can create an XPCOM component. The following section describes these levels in detail. 5.1. Faces of JavaScript in Mozilla As you have already seen in some examples in this book, the user interface uses JavaScript extensively to create behavior and to glue various widgets together into a coherent whole. When you add code to the event handler of one element to manipulate another -- for example, when you update the value of a textbox using a XUL button -- you take advantage of this first "level" of scriptability. In this role, JavaScript uses the Document Object
  2. Model (DOM) to access parts of the user interface as a hierarchical collection of objects. The section Section 5.3, later in this chapter, discusses this highest level of scripting. At a second level, JavaScript glues the entire user interface to the XPCOM libraries beneath, which create the application core. At this level, XPConnect (see the section Section 5.4.1 later in this chapter) provides a bridge that makes these components "scriptable," which means that they can be invoked from JavaScript and used from the user interface layer. When JavaScript calls methods and gets data from scriptable components, it uses this second layer of scriptability. Finally, at the third and ultimate level of Mozilla scripting, JavaScript can be used as a "first-order" language for creating the application core itself, for writing software components or libraries whose services are called. We discuss this third level of scripting and provide a long example in the section Section 8.2.1 in Chapter 8. When you use JavaScript in these contexts, the application architecture looks something like Figure 5-1, in which scripting binds the user interface to the application core through XPConnect and can reside as a software component using such technologies as XPIDL and XPCOM. Figure 5-1. Scripting in Mozilla
  3. Notes [1] This book does not pretend to give a complete overview of JavaScript. You can view the full JavaScript 1.5 reference online at http://developer.netscape.com/docs/manuals/index.html?content=javascript.html. [2] The third edition of the EMCA-262 EMCAScript Language Specification can be found at http://www.ecma.ch/ecma1/STAND/ECMA-262.HTM. 5.2. JavaScript and the DOM In the application layer of Mozilla, there is little distinction between a web page and the graphical user interface. Mozilla's implementation of the DOM is fundamentally the same for both XUL and HTML. In both cases, state changes and events are propagated through various DOM calls, meaning that the UI itself is content -- not unlike that of a web page. In application development, where the difference between application "chrome" and
  4. rendered content is typically big, this uniformity is a significant step forward. 5.2.1. What Is the DOM? The DOM is an API used to access HTML and XML documents. It does two things for web developers: provides a structural representation of the document and defines the way the structure should be accessed from script. In the Mozilla XPFE framework, this functionality allows you to manipulate the user interface as a structured group of nodes, create new UI and content, and remove elements as needed. Because it is designed to access arbitrary HTML and XML, the DOM applies not only to XUL, but also to MathML, SVG, and other XML markup. By connecting web pages and XML documents to scripts or programming languages, the DOM is not a particular application, product, or proprietary ordering of web pages. Rather, it is an API -- an interface that vendors must implement if their products are to conform to the W3C DOM standard. Mozilla's commitment to standards ensures that its applications and tools do just that. When you use JavaScript to create new elements in an HTML file or change the attributes of a XUL button, you access an object model in which these structures are organized. This model is the DOM for that document or data. The DOM provides a context for the scripting language to operate in. The specific context for web and XML documents -- the top-level window object, the elements that make up a web document, and the data stored in those elements as children -- is standardized in several different specifications, the most recent of which is the upcoming DOM Level 3 standard.
  5. 5.2.2. The DOM Standards and Mozilla The DOM specifications are split into different levels overseen by the W3C. Each level provides its own features and Mozilla has varying, but nearly complete, levels of support for each. Currently, Mozilla's support for the DOM can be summarized as follows: • DOM Level 1: Excellent • DOM Level 2: Good • DOM Level 3: Poor; under construction Mozilla strives to be standards-compliant, but typically reaches full support only when those standards have become recommendations rather than working drafts. Currently, Level 1 and Level 2 are recommendations and Level 3 is a working draft. Standards like the DOM make Mozilla an especially attractive software development kit (SDK) for web developers. The same layout engine that renders web content also draws the GUI and pushes web development out of the web page into the application chrome. The DOM provides a consistent, unified interface for accessing all the documents you develop, making the content and chrome accessible for easy cross-platform development and deployment. 5.2.3. DOM Methods and Properties Methods in the DOM allow you to access and manipulate any element in the user interface or in the content of a web page. Getting and setting attributes, creating elements, hiding elements, and appending children all involve direct manipulation of the DOM. The DOM mediates all interaction between scripts and the interface itself, so even when you do something as simple as
  6. changing an image when the user clicks a button, you use the DOM to register an event handler with the button and DOM attributes on the image element to change its source. The DOM Level 1 and Level 2 Core specifications contain multiple interfaces, including Node, NodeList, Element, and Document. The following sections describe some interface methods used to manipulate the object model of application chrome, documents, or metadata in Mozilla. The Document and Element interfaces, in particular, contain useful methods for XUL developers. 5.2.3.1. Using dump( ) to print to STDOUT The code samples in this chapter use a method called dump( ) to print data to STDOUT. This method is primarily used for debugging your code and is turned on using a PREF. You can turn this PREF on using the following code: const PREFS_CID = "@mozilla.org/preferences;1"; const PREFS_I_PREF = "nsIPref"; const PREF_STRING = "browser.dom.window.dump.enabled"; try { var Pref = new Components.Constructor(PREFS_CID, PREFS_I_PREF); var pref = new Pref( ); pref.SetBoolPref(PREF_STRING, true);
  7. } catch(e) {} This code is necessary only if you are doing development with a release distribution build of Mozilla. If you are using a debug or nightly build, this PREF can be set from the preferences panel by selecting Edit > Preferences > Debug > Enable JavaScript dump( ) output. 5.2.3.2. getElementById getElementById(aId) is perhaps the most commonly used DOM method in any programming domain. This is a convenient way to get a reference to an element object by passing that element's id as an argument, where the id acts as a unique identifier for that element. DOM calls like this are at the heart of Mozilla UI functionality. getElementById is the main programmatic entry point into the chrome and is essential for any dynamic manipulation of XUL elements. For example, to get a box element in script (i.e., to get a reference to it so you can call its methods or read data from it), you must refer to it by using the box id: Since the return value of getElementById is a reference to the specified element object, you usually assign it to a variable like this: var boxEl = document.getElementById('my-id'); dump("boxEl="+boxEl+"\n"); console output: boxEl=[object XULElement]
  8. Once you have the box element available as boxEl, you can use other DOM methods like getAttribute and setAttribute to change its layout, its position, its state, or other features. 5.2.3.3. getAttribute Attributes are properties that are defined directly on an element. XUL elements have attributes such as disabled, height, style, orient, and label. In the snippet above, the strings "my-id," "hello 1," and "hello 2" are values of the box element attributes. Note that Gecko does not enforce a set of attributes for XUL elements. XUL documents must be well-formed, but they are not validated against any particular XUL DTD or schema. This lack of enforcement means that attributes can be placed on elements ad hoc. Although this placement can be confusing, particularly when you look at the source code for the Mozilla browser itself, it can be very helpful when you create your own applications and want to track the data that interests you. Once you have an object assigned to a variable, you can use the DOM method getAttribute to get a reference to any attribute in that object. The getAttribute method takes the name of the desired attribute as a string. For example, if you add an attribute called foo to a box element, you can access that attribute's value and assign it to a variable: var boxEl = document.getElementById('my-id');
  9. var foo = boxEl.getAttribute('foo'); dump(foo+'\n'); The dump method outputs the string "this is the foo attribute," which is the value of the attribute foo. You can also add or change existing attributes with the setAttribute DOM method. 5.2.3.4. setAttribute The setAttribute method changes an existing attribute value. This method is useful for changing the state of an element -- its visibility, size, order within a parent, layout and position, style, etc. It takes two arguments: the attribute name and the new value. boxEl=document.getElementById('my-id'); boxEl.setAttribute('foo', 'this is the foo attribute changed'); var foo = boxEl.getAttribute('foo'); dump(foo+'\n'); The script above outputs the string "this is the foo attribute changed" to the console. You can also use setAttribute to create a new attribute if it does not already exist:
  10. boxEl=document.getElementById('my-id'); boxEl.setAttribute('bar', 'this is the new attribute bar'); By setting an attribute that doesn't already exist, you create it dynamically, adding a value to the hierarchical representation of nodes that form the current document object. After this code is executed, the boxEl element is the same as an element whose bar attribute was hardcoded into the XUL: These sorts of ad hoc changes give you complete control over the state of the application interface. 5.2.3.5. createElement If you need to dynamically create an element that doesn't already exist -- for example, to add a new row to a table displaying rows of information, you can use the method createElement. To create and add a text element to your box example, for example, you can use the following code: boxEl = document.getElementById('my-id'); var textEl = document.createElement('description');
  11. boxEl.appendChild(textEl); Once you create the new element and assign it to the textEl variable, you can use appendChild to insert it into the object tree. In this case, it is appended to boxEl, which becomes the insertion point. For mixed namespace documents like XUL and HTML, you can use a variation of createElement called createElementNS. To create a mixed namespace element, use this code: var node = document.createElementNS('http://www.w3.org/1999.xh tml', 'html:div'); Namespace variations for other functions include setAttributeNS, getElementsByTagNameNS, and hasAttributeNS. 5.2.3.6. createTextNode In addition to setting the label attribute on an element, you can create new text in the interface by using the DOM method createTextNode, as shown in the following example: var description = document.getElementById("explain"); if (description) {
  12. if (!description.childNodes.length) { var textNode = document.createTextNode("Newly text"); description.appendChild(textNode); } else if (description.childNodes.length == 1 ) { description.childNodes[0].nodeValue = "Replacement text"; } } Notice the use of appendChild. This method, discussed next, is used to insert the new element or text node into the DOM tree after it is created. Create-and-append is a common two-step process for adding new elements to the object model. 5.2.3.7. appendChild To dynamically add an element to a document, you need to use the method appendChild( ). This method adds a newly created element to an existing parent node by appending to it. If a visible widget is added, this change is visible in the interface immediately.
  13. var existingEl = document.getElementById('my- id'); var captionEl = document.createElement('caption'); existingEl.appendChild(captionEl); captionEl.setAttribute('label', 'This is a new caption'); captionEl.setAttribute('style', 'color: blue;'); This example creates a new element, gets an existing parent element from the document, and then uses appendChild( ) to insert that new element into the document. It also uses setAttribute to add an attribute value and some CSS style rules, which can highlight the new element in the existing interface. 5.2.3.8. cloneNode For elements that already exist, a copy method allows you to duplicate elements to avoid having to recreate them from scratch. cloneNode, which is a method on the element object rather than the document, returns a copy of the given node. // this is untested --pete var element = document.getElementById('my-id'); var clone = element.cloneNode(false);
  14. dump(`element='+element+'\n'); dump(`clone='+clone+'\n'); The method takes a Boolean-optional parameter that specifies whether the copy is "deep." Deep copies duplicate all descendants of a node as well as the node itself. 5.2.3.9. getElementsByTagName Another very useful method is getElementsByTagName. This method returns an array of elements of the specified type. The argument used is the string element type. "box," for example, could be used to obtain an array of all boxes in a document. The array is zero-based, so the elements start at 0 and end with the last occurrence of the element in the document. If you have three boxes in a document and want to reference each box, you can do it as follows: document.getElementsByTagName('box')[0]; document.getElementsByTagName('box')[1]; document.getElementsByTagName('box')[2]; Or you can get the array and index into it like this:
  15. var box = document.getElementsByTagName('box'); box[0], the first object in the returned array, is a XUL box. To see the number of boxes on a page, you can use the length property of an array: var len = document.getElementsByTagName('box').length; dump(len+'\n'); console output: 3 To output the id of the box: var el = document.getElementsByTagName('box'); var tagId = el[0].id; dump(tagId+"\n"); console output: box-one To get to an attribute of the second box:
  16. var el = document.getElementsByTagName('box'); var att = el[1].getAttribute('foo'); dump(att +"\n"); console output: some attribute for the second box getElementsByTagName is a handy way to obtain DOM elements without using getElementById. Not all elements have id attributes, so other means of getting at the elements must be used occasionally.[1] 5.2.3.10. Getting an element object and its properties In addition to a basic set of attributes, an element may have many properties. These properties don't typically appear in the markup for the element, so they can be harder to learn and remember. To see the properties of an element object node, however, you can use a JavaScript for in loop to iterate through the list, as shown in Example 5-1. Example 5-1. Printing element properties to the console var el = document.getElementById('my-id');
  17. for (var list in el) dump("property = "+list+"\n"); console output(subset): property = id property = className property = style property = boxObject property = tagName property = nodeName . . . Note the implicit functionality in the el object itself: when you iterate over the object reference, you ask for all members of the class of which that object is an instance. This simple example "spells" the object out to the console. Since the DOM recognizes the window as another element (albeit the root element) in the Document Object Model, you can use a similar script in Example 5-2 to get the properties of the window itself. Example 5-2. Printing the window properties var el = document.getElementById('test- win'); for(var list in el) dump("property = "+list+"\n");
  18. console output(subset): property = nodeName property = nodeValue property = nodeType property = parentNode property = childNodes property = firstChild . . . The output in Example 5-2 is a small subset of all the DOM properties associated with a XUL window and the other XUL elements, but you can see all of them if you run the example. Analyzing output like this can familiarize you with the interfaces available from window and other DOM objects. 5.2.3.11. Retrieving elements by property You can also use a DOM method to access elements with specific properties by using getElementsByAttribute. This method takes the name and value of the attribute as arguments and returns an array of nodes that contain these attribute values:
  19. var chcks = document.getElementsByAttribute("checked", "true"); var count = chcks.length; dump(count + " items checked \n"); One interesting use of this method is to toggle the state of elements in an interface, as when you get all menu items whose disabled attribute is set to true and set them to false. In the xFly sample, you can add this functionality with a few simple updates. In the xfly.js file in the xFly package, add the function defined in Example 5-3. Example 5-3. Adding toggle functionality to xFly function toggleCheck( ) { // get the elements before you make any changes var chex = document.getElementsByAttribute("disabled", "true"); var unchex = document.getElementsByAttribute("disabled", "false"); for (var i=0; i
  20. unchex[i].setAttributte("disabled", "true"); } Although this example doesn't update elements whose disabled attribute is not specified, you can call this function from a new menu item and have it update all menus whose checked state you do monitor, as shown in Example 5-4. Example 5-4. Adding Toggle menus to xFly
Đồng bộ tài khoản