ActionScript XML Objects


We keep all the code inside the login MovieClip. But first we reorganize the timeline into two parts : a single frame called Init and another called Loop. The Init frame is executed in the beginning and only once. (It can be considered the constructor of this MovieClip object, to use the language of object-oriented design.) The loop executes continually. Its only real job is to update the stars variable so that it always has the same number of stars as the characters in the password (Figure 16.1).

Figure 16.1. Echoing with Stars

graphics/16fig01.jpg

First we can upgrade the showme() function. This is the onLoad() handler, which is called by Flash when the XML data is completely loaded. Such handlers are passed a parameter that indicates a successful load or a failure.

Our more mature showme() gracefully deals with failure. In this version, a load failure causes showme() to generate its own XML content in the response object that simulates the server's error report. All code that has been written to handle server error reports can now automatically handle this communication failure, as well.

ActionScript
 function showme(ok) {   if(!ok)      this.parseXML("<RESPONSE><DENY error=\ "404\">                      Server not found.</DENY></RESPONSE>")   this.findElements(); } 

Even better, showme can now handle success well. It starts the findElements() method that walks through the document tree searching for elements it recognizes. When it finds either an <ACCEPT> or <DENY> element, it executes the matching method.

Notice that the xmlAccept() and xmlDeny() functions are bound to the login MovieClip ”they exist in the login namespace. On the other hand, the findElements() method is a member of the xmlResponse object. An XML object's methods execute in the _root namespace ”so how can they call methods in another, relative namespace?

One simple way to make the methods addressable would be to give the instance of the login object a known name and absolute position in the swf structure. The methods would be called easily (for example, _root.loginDialogue.xmlAccept() ), but this compels us to commit to an inflexible structure.

It would be much better to create a functional MovieClip object that is self-contained. Doing so requires us to maintain in the xmlResponse object a property called target, which points back to the login MovieClip that created it. this.target resolves to the namespace of the login instance so that this.target.xmlAccept() addresses the acceptance handler in that instance of login. (See the discussion of Execution Context in Chapter 8.)

ActionScript
 function findElements() {     if(this.nodeName eq "ACCEPT") this.target.xmlAccept(this)     if(this.nodeName eq "DENY") this.target.xmlDeny(this)     for(var i=0; i<this.childNodes.length; i++)        if(this.childNodes[i].nodeType ==1){           this.childNodes[i].target      = this.target;           this.childNodes[i].findElements= this.findElements;           this.childNodes[i].findElements();           } } 

Right now, these two functions do little. They display simple messages. In a real implementation, the xmlAccept() function will admit access to the site. The xmlDeny() function would be more or less unchanged: it just displays the error message and allows the user to try again.

Note that in this example, the text display for acceptance is hardcoded and generated on the client side. The text display for denial is extracted from the XML object and is typically generated on the server side (although a moment ago, we saw that showme() can also inject its own client-side denial message into the object). When things work properly, we don't care about the details. But when something fails we need to know what went wrong ”and there are lots of possibilities.

ActionScript
 function xmlAccept(element){     statusline= "helloi have been   accepted"; } function xmlDeny(element)   {     statusline= getText(element); } 

A <DENY> element node launches the getText() function. That function formulates the error message by concatenating all the text nodes that are immediate descendants of the <DENY> element node.

ActionScript
 function gettext(element) {   text="";   for(n in element.childNodes)        if(element.childNodes[n].nodeType==3)            text+= element.childNodes[n].nodeValue;  return text; } 

NOTE

While this form of getText() is certainly adequate as a first approximation and for demonstration, it is not reliable enough for release code. Release code must anticipate improbable conditions and potential evolution.

Today's server process might generate simple error text, but future servers might supply a lightly marked -up string. (Many Apache error messages, for example, include bold and italics.)

Imagine if this simple getText() function with its one-level -deep search got the following message, whose meaning and urgency are pretty clear:

 <DENY>You must <BOLD>NEVER</BOLD> try this again!</DENY> 

The user would see a slightly different message:

 You must try this again! 

This is because the error message appears as an object tree with these nodes:

 <DENY> (element)      You must (text)      <BOLD> (element)              NEVER (text)      try this again! (text) 

When getText() analyzed the <DENY> object, it only concatenated the text nodes immediately below the <DENY> object. The word NEVER is one level further down, within a <BOLD> node.


The submit function (called by a button press or the Enter key) has few modifications. Most notable are the two lines where the function findElements() is assigned to the xmlResponse object as a method by the same name. The target variable, discussed earlier, is established first in this code. It is set to act as a link to the login MovieClip instance.

The submit() function sets up two XML objects ” xmlRequest and xmlResponse (Figure 16.2). But remember that submit itself runs in the namespace of the login instance. The variable this resolves to the address of the login instance (perhaps _root.mylogin ). It is this link that is saved in the target property of the xmlRequest, along with the findElements routine that require that address.

Figure 16.2. Interaction between login and Its XML Objects

graphics/16fig02.jpg

Even though findElements() is coded on the same frame as submit(), it is installed as a method of xmlResponse. When it runs, this does not resolve to the login instance as it does for submit (and for xmlAccept() ). It resolves to the address of xmlResponse. That is why it requires the target variable. Within the XML object this.target has exactly the same meaning as this does in the other functions on this frame.

ActionScript
 function submit() {  login= "<LOGIN>"            + "<USERNAME>" + username + "</USERNAME>"            + "<PASSWORD >" + password + "</PASSWORD>"        +"</LOGIN >";   xmlRequest = new XML(login);   xmlRequest.contentType="text/xml";   xmlResponse = new XML("");   xmlResponse.onload = showme;   xmlResponse.findElements = findElements;   xmlResponse.target = this;   xmlRequest.sendAndLoad("authorize.php", xmlResponse);   statusline="WAITING for XML"; } 

When this code is compiled and loaded to the server to run with its PHP script, the results are satisfying (Figure 16.3). Despite its anticlimactic resemblance to earlier screens, the screen in the figure represents considerably more control ”the XML is causing functions to be fired off in the ActionScript code ”and now there are few limits on what we can do with XML.

Figure 16.3. Flash Driven by XML from Server

graphics/16fig03.jpg



Flash and XML[c] A Developer[ap]s Guide
Flash and XML[c] A Developer[ap]s Guide
ISBN: 201729202
EAN: N/A
Year: 2005
Pages: 160

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net