Web DevCenter    
 Published on Web DevCenter (http://www.oreillynet.com/javascript/)
 See this if you're having trouble printing code examples


O'Reilly Book Excerpts: ActionScript Cookbook

Cooking with ActionScript, Part 2

Related Reading

Actionscript Cookbook
Solutions and Examples for Flash MX Developers
By Joey Lott

by Joey Lott

Editor's note: Last week's sample recipes from ActionScript Cookbook covered using a unique depth when creating a new movie clip, performing actions at set intervals, and more. This week we conclude this series with recipes on pausing and resuming a sound, saving a local shared object, and searching XML. Just a sampling of the hundreds of solutions to common ActionScript problems that you'll find in this book.

Recipe 13.7: Pausing and Resuming a Sound

Problem

You want to pause and then resume a sound.

Solution

To pause a sound, store the sound's current position and call the stop( ) method. To resume the sound, call the start( ) method, passing it the value of the sound's stopping position. Alternatively, you can create custom pause( ) and resume( ) methods to automate this process.

Discussion

The Sound class does not provide built-in methods to pause and resume a sound. However, with a little bit of code, you can achieve the same result. The key is to store the sound's position property before stopping (pausing) the sound and then use that value to tell Flash at what point to resume playback.

Therefore, to pause a sound:

  1. Get the value of the sound's position property and store it in a variable:

    pauseTime = mySound_sound.position;
  2. Call the stop( ) method:

    mySound_sound.stop(  );

And when you want to resume the sound, simply do the following:

  1. Convert the stored position, in milliseconds, into a starting offset, in seconds, by dividing by 1000.

  2. Call the start( ) method and pass it the appropriate value for the offset:

    mySound_sound.start(pauseTime/1000);

You can automate the preceding process by creating two custom methods: pause( ) and resume( ). Add the following code to your Sound.as file for easy inclusion in other projects:

Sound.prototype.pause = function (  ) {
  // Get the current position and then stop the sound.
  this.pauseTime = this.position;
  this.stop(  );
};

Sound.prototype.resume = function (  ) {
  // Start the sound at the point at which it was previously stopped.
  this.start(this.pauseTime/1000);
};

Here is an example that uses the custom pause( ) and resume( ) methods:

// Attach a push button from the Library. You must first drag a push button from the
// Components panel to the Stage to create the Library symbol.
this.attachMovie("FPushButtonSymbol", "myPushButton", 1);

// Create a sound holder movie clip.
this.createEmptyMovieClip("soundHolder_mc", 2);

// Create the Sound object.
mySound_sound = new Sound(soundHolder_mc);

// Attach the sound from the Library. You must have a sound with the linkage
// identifier of MySoundSymbol for this to work.
mySound_sound.attachSound("MySoundSymbol");

// Define two callback functions. One resumes the sound, and the other pauses the
// sound. When each is called, it toggles the click handler for the push button to
// the other function.
function resumeSound (  ) {
  mySound_sound.resume(  );
  myPushButton.setClickHandler("pauseSound");
  myPushButton.setLabel("Pause Sound");
}

function pauseSound (  ) {
  mySound_sound.pause(  );
  myPushButton.setClickHandler("resumeSound");
  myPushButton.setLabel("Resume Sound");
}

// Define the initial click handler and label for the push button.
myPushButton.setClickHandler("pauseSound");
myPushButton.setLabel("Pause Sound");

// Tell the sound to start.
mySound_sound.start(  );

Recipe 16.4: Saving a Local Shared Object

Problem

You want to save local shared object data to the client computer.

Solution

Use the SharedObject.flush( ) method in the Flash movie.

Discussion

Flash automatically attempts to save local shared object data to disk when the movie is unloaded from the Player (such as when the Player closes). However, it is not a good practice to rely on the automatic save functionality, as there are several reasons why the data might not save successfully. Instead, you should explicitly instruct the local shared object to write the data to disk using the SharedObject.flush( ) method:

flushResult = my_l_so.flush(  );

When the flush( ) method is invoked, it attempts to write the data to the client computer. The result of a flush( ) invocation can be one of three possibilities:

In the third case, in which the flush( ) method returns "pending", there is an additional step you can take to determine whether the user grants or denies access to save the data. When the user makes a selection from the automatic prompt, the onStatus( ) method of the shared object is automatically invoked. It is up to you to define the method to handle the results in the way that is appropriate for your application. When the callback method is invoked, it is passed a parameter. The parameter is an object with a code property that is set to "SharedObject.Flush.Success" if the user granted access or "SharedObject.Flush.Failed" if the user denied access.

Here is an example that invokes flush( ) to save the data explicitly and then handles the possible responses:

my_l_so = SharedObject.getLocal("myFirstLSO");
my_l_so.data.val = "a value";
result = my_l_so.flush(  );
// If the flush operation completes, check the result. 
// If the operation is pending, the onStatus(  ) method of the 
// shared object is invoked before any result is returned.
if (result) {
  // Saved successfully. Place any code here that you want to execute after the data
  // was successfully saved.
}
else if (!result) {
  // This means the user has the local storage settings to 'Never.' If it is
  // important to save your data, you may want to alert the user here. Also, if you
  // want to make it easy for the user to change his settings, you can open the local
  // storage tab of the Player Settings dialog box with the following code:
  // System.showSettings(1);.
}

// Define the onStatus(  ) method for the shared object. 
// It is invoked automatically after the user makes a selection 
// from the prompt that occurs when flush(  ) returns "pending."
my_l_so.onStatus = function (infoObj) {
  if (infoObj.code == "SharedObject.Flush.Success") {
    // If the infoObj.code property is "SharedObject.Flush.Success", it means the
    // user granted access. Place any code here that you want to execute when the
    // user grants access.
  } else if (infoObj.code == "SharedObject.Flush.Failed") {
    // If the infoObj.code property is "SharedObject.Flush.Failed", it means the user
    // denied access. Place any code here that you want to execute when the user
    // denies access.
  }
};

If you know in advance that a shared object is likely to continue to increase in size with each session, it is prudent to request a larger amount of local storage space when the shared object is created. Otherwise, each time the current allotted space is exceeded, the user is prompted again to accept or deny the storage request. Setting aside extra space avoids repeatedly asking the user for permission to store incrementally more data. You can request a specific amount of space when you call the flush( ) method by passing it a number of bytes to set aside for the shared object:

// Request 500 KB of space for the shared object.
result = mySO.flush(1024 * 500);

Recipe 19.15: Searching XML

Problem

You want to search an XML object for nodes based on keywords and other criteria such as node hierarchy.

Solution

Use the third-party XPath class from XFactorStudio.com.

Discussion

Thus far in this chapter you've read recipes on how to work with XML objects using the DOM, or Document Object Model. This means that if you want to locate a particular node in the XML tree, you need to know the relationship of that node to the whole (i.e., first child, next sibling, etc.). However, when you want a more flexible way of looking for nodes, the DOM can become tedious.

XPath is a language that allows you a much more intuitive and flexible way to find nodes within an XML object. XPath is a W3C standard (see http://www.w3c.org/TR/xpath) that is supported on many platforms, but it is not natively supported in Flash. However, Neeld Tanksley of XFactorStudio.com has created an ActionScript XPath class that you can download from http://www.xfactorstudio.com/projects/XPath/index.php. You should download the .zip file and extract all the .as files into your Flash Include directory (make sure they are extracted into the Include directory, and not into subdirectories).

Once you have downloaded and installed the custom XPath class, you can include it in your Flash movies and begin using XPath to work with XML, as follows:

#include "XPath.as"

XPath uses path expressions to denote the node or nodes you want to find. For example, if the root node in your XML object is named books, then you can find that root node using:

/books

If books contains child nodes named book, then you can return all the book nodes using:

/books/book

If you don't know or care about the full path from the root node to the node or nodes for which you are searching, you can use a double slash to indicate that you want to locate all matching nodes at any level in the XML tree. For example, the following returns all author nodes regardless of their hierarchy:

//author

An asterisk (*) is a wildcard. For example, the following matches all author nodes that are children of any nodes that are, in turn, children of the books node:

/books/*/author

You can also use square brackets ([]) to indicate criteria that the nodes must match. For example, you can match all book nodes that contain author nodes with the following:

//book[author]

Notice that the preceding is different from //book/author in that the former returns book nodes and the latter returns author nodes.

You can also use expressions with equality operators such as the following, which returns all book nodes containing a child title node with a text value of "ActionScript Cookbook":

//book[title='ActionScript Cookbook']

The @ sign can be used to signify an attribute. The following example matches all author nodes containing a name attribute:

//author[@name]

There are also many other built-in functions, operators, and keywords in XPath that you can read about in the documentation.

The XPath class has one method that we are interested in for this recipe. The XPath.selectNodes( ) method is a static method, which means you invoke it from the class itself, not from an instance of XPath. The method takes two parameters - the XMLNode object to search and the XPath expression to use - and returns an array of matching nodes:

 matches = XPath.selectNodes(my_xml, "/books/book");

Now let's take a look at an example of XPath in use. For this example you should make sure that you have installed all the .as files for the XPath class.

  1. Create an XML document using a simple text editor such as WordPad. Add the following XML code to the document, and then save it as books.xml:

    <books>
      <book>
        <title>ActionScript Cookbook</title>
        <authors>
          <author name="Joey Lott" />
        </authors>
      </book>
      <book>
        <title>Flash Cookbook</title>
        <authors>
          <author name="Joey Lott" />
          <author name="Jeffrey Bardzell" />
        </authors>
      </book>
      <book>
        <title>Flash Remoting: The Definitive Guide</title>
        <authors>
          <author name="Tom Muck" />
        </authors>
      </book>
      <book>
        <title>ActionScript for Flash MX: The Definitive Guide</title>
        <authors>
          <author name="Colin Moock" />
        </authors>
      </book>
    </books>
  2. Open a new Flash document. Copy the PushButton component symbol into the Library by dragging an instance from the Components panel onto the Stage and then deleting the instance. The symbol remains in the Library. Then add the following code to the first frame of the main timeline:

    #include "XPath.as"
    
    function doSearch (  ) {
      // Use the selectNodes(  ) method to find all matches to the XPath expression the
      // user has entered into xpath_txt. Display the results in output_txt. Use a
      // newline character between each match.
      var results = XPath.selectNodes(my_xml, xpath_txt.text);
      output_txt.text = results.join("\n");
    }
    
    // Create the input text field for the user to enter the XPath expression.
    this.createTextField("xpath_txt", 1, 20, 20, 300, 20);
    xpath_txt.border = true;
    xpath_txt.type = "input";
    
    // Create the text field for the output of the results.
    this.createTextField("output_txt", 2, 20, 70, 300, 300);
    output_txt.border = true;
    output_txt.multiline = true;
    output_txt.wordWrap = true;
    
    // Add the push button instance so the user can perform the search.
    this.attachMovie("FPushButtonSymbol", "search_pb", 3, {_x: 20, _y: 45});
    search_pb.setClickHandler("doSearch");
    search_pb.setLabel("Find Matches");
    
    // Set the ignoreWhite property to true for all XML objects.
    XML.prototype.ignoreWhite = true;
    
    // Create an XML object and load books.xml into it.
    my_xml = new XML(  );
    my_xml.load("books.xml");
  3. Save the Flash document to the same directory as the books.xml file. Test the movie. Try entering the following XPath expressions, and you should get the results as shown:

    //book/title 
    
        <title>ActionScript Cookbook</title>
        
        <title>Flash Cookbook</title>
        
        <title>Flash Remoting: The Definitive Guide</title>
    	
        <title>ActionScript for Flash MX: The Definitive Guide</title>
    	
    //book[contains(title, `ActionScript')]/title 
    
        <title>ActionScript Cookbook</title>
    
        <title>ActionScript for Flash MX: The Definitive Guide</title>
    
    //book[authors[author[@name='Joey Lott']]]/title
    
        <title>ActionScript Cookbook</title>
        <title>Flash Cookbook</title>

See Also

XPath is too large a subject to cover in detail in this book. For more information, refer to the online tutorial at http://www.w3schools.com/xpath/default.asp or check out the book XPath and XPointer by John E. Simpson (O'Reilly).

Joey Lott is a founding partner of The Morphic Group. He has written many books on Flex and Flash-related technologies, including Programming Flex 3, ActionScript 3 Cookbook, Adobe AIR in Action, and Advanced ActionScript 3 with Design Patterns.


Return to the Web DevCenter.

Copyright © 2009 O'Reilly Media, Inc.