Section 13.3. A Simple People List


13.3. A Simple People List

To begin with, let's build a simple people list component that displays the username of each person connected to an application instance and provides additional information such as a user's full name, email address, and connection time whenever a user clicks on someone's name in the list. To keep things manageable, this simple people list does not even manage its own shared objectit uses one managed by the server-side main.asc file.

Before we start, let's consider some questions you should ask before you build any component:

  • Are any database, stream, or shared object resources already available to the component?

  • What resources must the component create and manage by itself?

  • What user interface components should the component contain?

  • What information must the component make available to other components or objects?

In the case of a simple people list, here are some answers:

  • Components often create and manage their own streams and shared objects. In the case of a people list, a shared object containing information about users may already be provided by a server-side script. In other cases, a server-side people list component may be responsible for providing user information. For the simple people list, we can assume the information is already available in a shared object and that each slot name is a user's username and each slot value is an object containing the user's full name, email address, and connection time.

  • Since the people list component will use a preexisting shared object, it doesn't have to create any other resources.

  • There are a few contenders for UI components the people list might use. The most common is a List component, which performs much faster than a DataGrid when used properly. However, a DataGrid has the advantage that columns in the grid can contain different icons so that different information about each user can be shown graphically. Finally, a Tree component can be used. Opening and closing person nodes in the tree can show additional information. For the simple people list, a List component is sufficient.

  • When the user clicks on a username in the people list, any object that needs to know about the user will receive an object containing the username, full name, email address, and connection time for that user. We'll use the v2 component architecture available in Flash MX 2004 to provide this feature with a minimum of fuss.

13.3.1. Building the Component

Our custom SimplePeopleList component is a subclass of the UIComponent class provided as part of the v2 component framework; it contains only two movie clips. One is the BoundingBox movie clip that is normally used to provide an initial size for many components and a List component to display the username of each person. The SimplePeopleList component was created by inserting a new movie clip symbol in a Flash movie and giving it a linkage identifier of SimplePeopleList and an AS 2.0 class name of SimplePeopleList using the Linkage Properties dialog box. (In this chapter, we do not use packages. They are used in Chapter 15 when introducing a simple alternative communication component framework.)

Whenever building a component based on the v2 component set, you should not drag components from the Components panel into your own component. Instead, select File Import Open External Library, then open the StandardComponents.fla file from the .../First Run/ComponentFLA directory. When you need assets from the v2 component set, drag them from the external Library into your movie's Library or onto the Stage.


The SimplePeopleList needs the following assets from the StandardComponents.fla file's Library:


BoundingBox movie clip

A simple movie clip that is often used to provide an initial size for a component when it is first instantiated . Obtain it from the Library's Flash UI Components 2 Component Assets folder.


List component

A component used to create the visible list of users. Obtain it from the Library's Flash UI Components 2 folder.


UIComponent class

The base class on which every component in this chapter is based, located in the Library's Flash UI Components 2 Base Classes FUIObject Subclasses FUIComponent Subclasses folder. You don't need to include it manually because each component manages its own dependencies, so the List component will include it automatically. However, if you build a component that doesn't include an existing subcomponent, you'll need to include the UIComponent class manually.

The SimplePeopleList component is really just a movie clip symbol in the Library that is associated with the SimplePeopleList.as class file, has been exported for ActionScript, and has the linkage identifier SimplePeopleList . Figure 13-1 shows the two frames that make up the SimplePeopleList movie clip symbol.

Figure 13-1. The timeline of the SimplePeopleList movie clip symbol

The BoundingBox clip has been placed at the origin (0, 0) of the SimplePeopleList component in frame 1 and has been named boundingBox_mc . The action in the Actions layer is a simple stop( ) statement to keep the playhead from moving to the second frame. Finally, the second frame of the Assets layer is where the List component has been placed. The stop( ) statement on the first frame guarantees that the second frame will never be reached. Therefore, assetssuch as the List componentthat must be in a movie's Library are placed in the second frame. When the component is imported into a movie, the assets will also be imported and appear in the movie's Library. Since the playhead will never reach the second frame, the List clip in the second frame will never be instantiated and is never directly used. With these elements in place, the real work of creating the SimplePeopleList component, including attaching a List component, is done in the SimplePeopleList.as class file. Example 13-1 shows the complete listing of the SimplePeopleList class definition; this client-side ActionScript 2.0 code must be placed in an external SimplePeopleList.as file. However, this listing does not show all the code necessary to create a working example; see the SimplePeopleList.zip file on the book's web site for the complete code.

Many of the examples throughout this chapter use getter and setter methods. These are just methods that are called automatically when a corresponding property is set or retrieved. They provide a way to have assignment and retrieval operations for a property managed by a function, while allowing the developer to read or assign the property in the typical way (without having to invoke a function manually). For more information on these methods, see the section "Getter and Setter Methods " in Chapter 4 of ActionScript for Flash MX: The Definitive Guide (O'Reilly).

Example 13-1. A SimplePeopleList component
 class SimplePeopleList extends mx.core.UIComponent {   // Connect component class and symbol.   var className:String = "SimplePeopleList";   static var symbolName:String = "SimplePeopleList";   static var symbolOwner:Object = SimplePeopleList;   // Subcomponents and movie clips.   var list:mx.controls.List;   var boundingBox_mc:MovieClip;   // Externally supplied NetConnection.   var __nc: NetConnection;   // Shared object obtained via the NetConnection.   var userList:SharedObject;   // Default path to resources for this component.   var __resourcePath:String = "pfcs/SimplePeopleList/main/";   // Constructor function calls UIComponent's constructor.   function SimplePeopleList ( ) {   }   //   init( )   is called after   createChildren( )   and before   onLoad( )   .   function init ( ) {     super.init( );     boundingBox_mc._visible = false;     boundingBox_mc._width = boundingBox_mc._height = 0;   }   // No drawing is required as the List subcomponent is the entire GUI.   function draw ( ) {     size( );   }   // Resize the List to take up the entire area of the compoent.   function size ( ) {     super.size( );     list.setSize(width, height);   }   // Attach the List to this component.   function createChildren ( ) {     var depth = 1;     createObject("List", "list", depth++, {_x:0, _y:0});     list.vScrollPolicy = "auto";   }   // The simplePeopleList.resourcePath = "mypath" setter method.   public function set resourcePath(resourcePath:String) {     if (!resourcePath) {       trace("SimplePeopleList Error: Empty or undefined resourcePath.");       return;     }     __resourcePath = resourcePath;   }   // The simplePeopleList.nc = myNC setter method. Assumes resourcePath is correct.   public function set nc (nc:NetConnection) {     if (!nc) {       trace("SimplePeopleList Error: nc was null or undefined.");       return;     }     __nc = nc;     if(!nc.isConnected) {       trace("SimplePeopleList Error: nc must be connected before use.");       return;     }     // Get the temporary shared object.     // SharedObjectFactory is explained shortly.     userList = SharedObjectFactory.getRemote(__resourcePath + "userList", nc.uri);     userList.addEventListener("onSync", this);     // Assume this component "owns" the userList and is responsible for     // connecting to it.     userList.connect(nc);   }   // Passes through add listener requests to the List subcomponent.   function addEventListener(type, dest) {     list.addEventListener(type, dest);   }   // Passes through remove listener requests to the List subcomponent.   function removeEventListener(type, dest) {     list.removeEventListener(type, dest);   }   // A simple event handler for the   userList   shared object that   // manipulates the List's   dataProvider   directly.   function onSync (ev) {     var dp = list.dataProvider;     dp.splice(0);     for (var p in userList.data) {       dp.push({label:p, data:userList.data[p]});     }     dp.dispatchEvent({target: dp, type:"modelChanged"});   }   // When this component is disposed of, release resources.   function onUnload ( ) {     close( );   }   //   close( )   releases resources.   function close ( ) {     userList.removeEventListener("onSync", this);   } } 

The SimplePeopleList component's code can be broken down into two broad categories: the code required to produce the graphical user interface and the part that ties together the userList shared object and the List component. Let's look at each separately.

13.3.1.1 Building the graphical interface

By extending the UIComponent class and setting the className , symbolName , and symbolOwner variables , the SimplePeopleList class inherits all the properties and methods of the UIComponent class and connects the SimplePeopleList symbol in the Library with the SimplePeopleList class for the v2 component framework. Of particular interest here are the following methods that will be called in order when a SimplePeopleList object is instantiated:


SimplePeopleList( )

The SimplePeopleList constructor function is called first and simply returns.


init( )

The init( ) method is called and in turn calls UIComponent.init( ) and then hides the boundingBox_mc clip. The clip already exists because it was placed on the SimplePeopleList component's Stage in frame 1.


createChildren( )

The createChildren( ) method is called before the clip is shown in a movie frame and is used to attach clips to the component and initialize them. In Example 13-1, a List component instance is attached to the SimplePeopleList component, given the name list , positioned at (0, 0), and set to autohide the vertical scrollbar.


draw( )

The draw( ) method is called after the clip is loaded. If an onLoad( ) method had been defined, it would have been called before draw( ) . The draw( ) method is responsible for updating the visual appearance of the component. Since the entire user interface of the SimplePeopleList component is a List component that can draw itself, the draw( ) method simply calls the size( ) method.


size( )

The size( ) method just passes the width and height of the clip to the List subcomponent so that it resizes itself to fill the area allocated to the SimplePeopleList.

Both the list instance of the List component and the boundingBox_mc instance of the BoundingBox movie clip must be declared as variables within the class definition to avoid compiler errors.

13.3.1.2 Tying the list to the shared object

The SimplePeopleList class has a property named __nc reserved to hold a NetConnection object. For the purposes of designing a simple people list component, we assume that the Flash movie that it is being used connects to a FlashCom application instance and can provide a connected NetConnection object for the SimplePeopleList to use. Rather than providing a method that can be used to pass in a reference to the NetConnection object, the SimplePeopleList component defines a setter method. The setter method will be called when the component's nc property is set this way:

 peopleList.nc = nc; 

The setter methodwith comments and error checking removedis as follows :

 public function set nc (nc:NetConnection) {   __nc = nc;   userList = SharedObjectFactory.getRemote(__resourcePath + "userList", nc.uri);   userList.addEventListener("onSync", this);   userList.connect(nc); } 

The public nc property is saved in the private __nc property for later use. Then the NetConnection object and the SharedObjectFactory class are used to get a reference to the userList shared object. The path to the shared object is composed from two strings:

 __resourcePath + "userList" 

If the __resourcePath property has not been changed from its default, the path to the userList shared object is:

 pfcs/SimplePeopleList/main/userList 

In previous chapters, shorter paths have been used. However, in this chapter, a regular naming scheme is used to identify and keep separate the shared object and stream resources each component manages. The userList path has three parts preceding the name of the shared object itself:


pfcs

The first term in the path is a directory that contains resources that are available to most Flash clients . Chapter 18 describes in detail using directories to secure resources. Creating a pfcs folder makes it possible to deny access to other folders.


SimplePeopleList

The second term in the path is a directory that is reserved for resources needed by any instance of one type of componentin this case, the SimplePeopleList component.


main

The third term in the path is the folder that is reserved for an instance of the component. In this case, main is the default folder name that is normally used by the "main" people list of an application. In a scenario in which more than one people list is used, the third term in the path can be used to distinguish between component resources.

The SharedObjectFactory class is a custom class written to return shared objects that can broadcast events. This class makes it possible to call addEventListener( ) on the userList shared object. The SharedObjectFactory class is discussed in detail in the next section.

The nc( ) setter method adds the SimplePeopleList component instance as a listener of the userList for onSync( ) events. Once again, here is the code that gets the shared object and sets up the SimplePeopleList as a listener for onSync events:

 userList = SharedObjectFactory.getRemote(__resourcePath + "userList", nc.uri); userList.addEventListener("onSync", this); 

The component's onSync( ) handler is called whenever the shared object's onSync( ) method is called. The addEventListener( ) and removeEventListener( ) methods are the standard methods v2 components provide to add and remove event listeners. Finally, the nc( ) setter method connects the shared object using the NetConnection object:

 userList.connect(nc); 

When the connection to the userList shared object occurs, the SimplePeopleList.onSync( ) method is called:

 function onSync (ev) {   var dp = list.dataProvider;   dp.splice(0);   for (var p in userList.data) {     dp.push({label:p, data:userList.data[p]});   }   dp.dispatchEvent({target: dp, type:"modelChanged"}); } 

When onSync( ) is called, the contents of the List component instance are simply removed and re-created using the shared object's data property. Each list item's label is set to the slot name (username) of each slot in the user list, and the item's data is set to the data in the slot. In this case, the data will be an object containing the full name, email address, and connection time of the user. Since the onSync( ) method must delete the entire contents of the list and rewrite it each time the shared object changes, it manipulates the list's dataProvider property directly to improve performance. The contents of the list are deleted by calling splice( ) , and new items are added using push( ) . Unlike the List component's removeAll( ) and addItem( ) methods, splice( ) and push( ) do not tell the list to redraw itself. Directly updating the dataProvider avoids redundant update requests to the list as each item is added. Instead, the data provider's dispatchEvent( ) method is called once to ask the list to redraw itself after all the items have been added.

While it is not used in the SimplePeopleList.onSync( ) method, the onSync( ) method is passed an event object. The list of information objects that was passed to the shared object's onSync( ) method is contained within the event object and is available in its ev.list property.

If the nc( ) setter and onSync( ) methods connect to and display the contents of the userList shared object, you may be wondering how the user information gets into the shared object in the first place. In the case of the SimplePeopleList component, the work of adding and removing user information is done by the main.asc script on the server. The complete file is available in the SimplePeopleList.zip file on the book's web site. Here is an excerpt from the main.asc file that shows how user information is added and removed from the userList shared object:

 application.onAppStart = function (  ) {   userList_so = SharedObject.get("pfcs/SimplePeopleList/main/userList"); }; application.onConnect = function (client, user) {   client.user = user;   client.user.arrival = new Date( );   userList_so.setProperty(client.user.userName, client.user);   return true; }; application.onDisconnect = function (client) {   userList_so.setProperty(client.user.userName, null); }; 

The main.asc script is coded on the assumption that the client will pass a second parameter in the NetConnection connect( ) method when it connects. The parameter should contain an object with userName , fullName , and email properties that will be stored in the userList shared object. The user object is also stored as a property of each Client object in this and later examples, so that the server-side part of any component can easily retrieve user information associated with a client.

The SimplePeopleList class is responsible for managing the userList shared object within the client. (Later, we'll create a people list component that also adds users to the shared object.) So it needs to provide a way to retrieve the user object for any user that appears in its list. Like all Flash MX 2004 v2 components that must broadcast events, the List component has addEventListener( ) and removeEventListener( ) methods.

When a user clicks on the List subcomponent within the SimplePeopleList component, a change event is generated. Other components or objects can add themselves as event listeners in order to know when an item has been selected in the list. When they receive a change event, they can use the event's target property to get a reference to the list and use the list's selectedItem property to get the data object from the selected item.

The SimplePeopleList component provides two methods that allow other objects and components to subscribe to list selection events:

 function addEventListener (type, dest) {   list.addEventListener(type, dest); } function removeEventListener (type, dest) {   list.removeEventListener(type, dest); } 

The methods simply pass through an event listener request to the list component instance. When the user selects an item in the people list, the list component instance broadcasts an event to any listeners that have used the people list's addEventListener( ) method to listen for the event. For example, the following statement adds an application object as a listener for change events:

 peopleList.addEventListener("change", application); 

Other components will require more complex addEventListener( ) methods and may need to be able to broadcast their own custom events.

In Example 13-1, the target property of each change event will be the List component and not the SimplePeopleList. Instead of passing event listener requests through to the List, SimplePeopleList could add itself as a listener to the List, then redispatch List events to its own listeners. Unfortunately, redispatching events is not enough to emulate the List's functionality. The SimplePeopleList must also provide the standard List methods and properties such as selectedItem and selectedIndex that listeners expect to be able to use on the event target. The effort and increase in code size needed to make the target property point to the List instead of the SimplePeopleList may not be justified.


Now that we've described how the SimplePeopleList component works, how do you use it in a Flash movie? Briefly, you must add it to the Library of a movie and attach it to the Stage manually at authoring time or using ActionScript. Once on the Stage or attached with ActionScript, it must be passed a reference to an already connected NetConnection object. In the example .fla found in the SimplePeopleList.zip file, an application object creates a NetConnection object, and the SimplePeopleList instance (named peopleList ) is connected this way:

 // First tell the people list about events we want to listen for. peopleList.addEventListener("change", application); // If necessary, replace the default resource path (not necessary here). peopleList.resourcePath = "pfcs/SimplePeopleList/main/"; // Provide an already connected NetConnection to the component. peopleList.nc = application.nc; 

See SimplePeopleList.zip on the book's web site for a complete example including both the server-side main.asc script and all the client-side files.

You'll find the SimplePeopleList movie clip symbol in the Library of SimplePeopleList.fla in the Zip archive. The SimplePeopleList could also have been compiled into a SWC file. A SWC file is an archive that contains a catalog.xml file that describes the other contents of the archive, ActionScript files that define component classes, and the SWF files that implement each component. A SWC file may also contain other assets. See Understanding SWC Files in the Flash MX 2004 Help. Converting a movie clip symbol into a compiled SWC is relatively easy. Select the symbol in the Library, right-click (Windows) or Ctrl-click (Macintosh) to open the contextual menu, and select Export SWC File. Then save the SWC file. SWC files are not used in this bookpartly because of problems using them as subcomponents within other components. However, they are a good way to package component sets. For more information on creating and compiling components see:

http://www.person13.com/articles/components/creatingcomponents.html

The SimplePeopleList component was developed to show how a component can manage and coordinate the work of both v2 user interface components and communication resources such as the userList shared object. It is a subclass of the UIComponent class, implements many of the core UIComponent methods, and uses the v2-style setter methods. The SimplePeopleList component has two shortcomings that will be addressed later in this chapter: it doesn't provide a way to show the connection status of users, and it relies on code in the main.asc file to populate a shared object. The PeopleList and Status components developed later provide these features.



Programming Flash Communication Server
Programming Flash Communication Server
ISBN: 0596005040
EAN: 2147483647
Year: 2003
Pages: 203

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