[ Team LiB ] |
26.2 Developing the MP3 SelectorsIn the following sections, we create both the local and server MP3 selectors. These are the parts of the jukebox application that enable a user to select MP3s from both her own hard drive and from the server by using a graphical user interface instead of having to type in a URL or path to the file. 26.2.1 Creating a Local MP3 SelectorFor a user to be able to add an MP3 to her jukebox playlist from her local hard drive, she needs to know the path to that file. This process can be simplified for the user if we can provide her with a way of browsing her hard drive graphically and selecting a file with her mouse. This is the idea behind the local MP3 selector feature. HTML allows you to create forms with elements of type "file". File form fields include a Browse button that opens a dialog box so that users can select files from their local hard drives. Flash does not natively support a local browse feature; however, we can devise a workaround using HTML, JavaScript, and a Flash movie with a local connection. There are three files necessary for the local MP3 selector functionality—two HTML pages and one Flash movie. Let's look at each of these files individually. 26.2.1.1 Making the Form pageWe will use a standard HTML file form field in a small pop-up browser window to allow the user to select a file from her hard drive. Create a new HTML document named localFileForm.html and add the following code to it: <!-- Create a form (must be multipart/form-data in order for the file field type to work properly). The form should submit to submitFileForm.html (an HTML page we'll create next) using the GET method. --> <form enctype="multipart/form-data" method="get" action="submitFileForm.html"> <!-- Create a file input field named path. --> <input type="file" name="path"> <br> <!-- Create a Submit button. --> <input type="submit"> </form> As you can see, localFileForm.html is not very complicated. If you test the page in a web browser, you can see that a Browse button is created automatically as part of the file input field. Clicking the Browse button opens a dialog box that allows you to select a local file. 26.2.1.2 Making the Submit pageOnce a user has selected a file using the localFileForm.html page and clicked the Submit button, the form data is sent to another HTML page named submitFileForm.html. We want this HTML page to take the form data (specifically, the value from the file field) and pass it to a Flash movie, which we will create next. You can use the FLASHVARS attribute of the <OBJECT> and <EMBED> tags to pass a value to the movie loaded into the HTML page. Normally, if the values you want to pass to a Flash movie are static, you can hardcode them into the HTML code, as shown in this example (FLASHVARS attributes are shown in bold): <OBJECT classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/ swflash.cab#version=6,0,0,0" WIDTH="550" HEIGHT="400" id="myMovie" ALIGN=""> <PARAM NAME=movie VALUE="myMovie.swf"> <PARAM NAME=quality VALUE=high> <PARAM NAME=bgcolor VALUE=#FFFFFF> <PARAM NAME=FLASHVARS VALUE="param1=value1¶m2=value2"> <EMBED src="myMovie.swf" quality=high bgcolor=#FFFFFF WIDTH="550" HEIGHT="400" NAME="myMovie" ALIGN="" TYPE="application/x-shockwave-flash" PLUGINSPAGE="http://www.macromedia.com/go/getflashplayer" FLASHVARS ="param1=value1¶m2=value2"> </EMBED> </OBJECT> However, we want to obtain the file value dynamically from the HTML form. One option is to use JavaScript to extract the value from the URL—the form values are appended to the URL since we used the GET method to submit the form—and then use the JavaScript write( ) method to generate the <OBJECT> and <EMBED> tags within the HTML page. This solution offers several advantages. First of all, because JavaScript is run on the client and understood by almost all web browsers, you don't have to worry about any server-side language. Furthermore, JavaScript shares the same syntax and many core classes with ActionScript, so it is approachable for most ActionScript developers. In the following code block, you can see the HTML and JavaScript code that extracts the form value from the URL and passes it a Flash movie using the FLASHVARS attribute. Add this code to an HTML document named submitFileForm.html and save it to the same directory as localFileForm.html. <HTML> <HEAD> <TITLE>Get Path</TITLE> </HEAD> <BODY bgColor=#FFFFFF leftmargin="0" marginheight="0" marginwidth="0" topmargin="0"> <SCRIPT language=JavaScript> <!-- var path = location.search.split("=")[1]; var swfCode = "<OBJECT classid=\'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\' "; swfCode += " codebase=\'http://download.macromedia.com/pub/shockwave/cabs/flash/ swflash.cab#version=6,0,0,0\'"; swfCode += " WIDTH=300 HEIGHT=150>"; swfCode += " <PARAM NAME=movie VALUE='pathUploader.swf'>"; swfCode += " <PARAM NAME=quality VALUE=best> "; swfCode += " <PARAM NAME=FlashVars VALUE='path=" + path + "'>"; swfCode += " <EMBED src='pathUploader.swf'"; swfCode += " FLASHVARS ='path=" + path + "'"; swfCode += " quality=best WIDTH=300 HEIGHT=150 "; swfCode += " TYPE=\'application/x-shockwave-flash\' "; swfCode += "PLUGINSPAGE=\'http://www.macromedia.com/shockwave/download/ index.cgi?P1_Prod_Version=ShockwaveFlash\'> "; swfCode += " </EMBED> </OBJECT> "; document.write(swfCode); //--> </SCRIPT> </BODY> </HTML> Let's take a closer look at some of the JavaScript code. First of all, we want to get the value that was submitted by the form. In JavaScript the query string portion of the URL (everything following the ?) can be referenced by location.search. In this case, the value of location.search is of the form path=userSelectedPath. You can use the split( ) method to split the value into an array using the equals sign as the delimiter; the chosen file path is stored in the array's second element. Hence, we use: var path = location.search.split("=")[1]; Next, we want to construct the <OBJECT> and <EMBED> tags. Most of the string defining the tags is hardcoded to contain the necessary attributes. The name of our Flash movie, pathUploader.swf, is specified as the movie parameter for the <OBJECT> tag and the src attribute for the <EMBED> tag. Notice that the FLASHVARS attribute is set to include the file path obtained from the form. var swfCode = "<OBJECT classid=\'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\' "; swfCode += " codebase=\'http://download.macromedia.com/pub/shockwave/cabs/flash/ swflash.cab#version=6,0,0,0\'"; swfCode += " WIDTH=300 HEIGHT=150>"; swfCode += " <PARAM NAME=movie VALUE='pathUploader.swf'>"; swfCode += " <PARAM NAME=quality VALUE=best> "; swfCode += " <PARAM NAME=FLASHVARS VALUE='path=" + path + "'>"; swfCode += " <EMBED src='pathUploader.swf'"; swfCode += " FLASHVARS ='path=" + path + "'"; swfCode += " quality=best WIDTH=300 HEIGHT=150 "; swfCode += " TYPE=\'application/x-shockwave-flash\' "; swfCode += "PLUGINSPAGE=\'http://www.macromedia.com/shockwave/download/ index.cgi?P1_Prod_Version=ShockwaveFlash\'> "; swfCode += " </EMBED> </OBJECT> "; Once the string is constructed, we use the document.write( ) method to output the value in the HTML page. document.write(swfCode); 26.2.1.3 Making the local connection Flash movieTo finish the local MP3 selector, we must create a Flash movie that takes the value passed to it via FLASHVARS and sends it to the main jukebox movie. You can enable movie-to-movie communication with two Flash movies running on the same computer using a LocalConnection object. We'll name our Flash movie pathUploader.swf, as per the movie and src attributes in the preceding submitFileForm.html page. This movie should do the following:
Here are the steps involved in creating this Flash movie:
26.2.2 Creating the Server MP3 SelectorIn the preceding section, we developed a mechanism by which the user can select an MP3 from her local hard drive. In this section, we create a similar mechanism that allows the user to select an MP3 from a server. This portion of the application requires the use of Flash Remoting. Moreover, the example shown here uses ColdFusion to browse the contents of the server directory. However, this feature is not essential to the overall functioning of the application, and if you do not use Flash Remoting or ColdFusion, you can skip over this portion. The server MP3 selector involves three basic parts:
The server MP3 selector opens up in a new browser window, as does the local MP3 selector. The server MP3 selector should allow a user to browse the directory in which the CFC is saved, as well as any of the subdirectories. The user can select a file and add it to the playlist in the main jukebox movie by way of a local connection. 26.2.2.1 Making the CFCThe first step in creating the server MP3 selector is to make the CFC that retrieves the directory and file information. The CFC needs only one method, which takes a parameter specifying the name of the directory about which to return information. The method returns an object with the information about that directory, including the directory name and the files and subdirectories it contains. To make the CFC, do the following:
In the first part of the CFC method, we determine the path to the directory for which we should get the information. The first time the method is called, we don't know the path to the directory, but on subsequent calls (i.e., calls to retrieve subdirectory information) we do. For this reason, the dir parameter should not be required. Also, the directory path value that we use (getdir) should default to the path to the directory containing the CFC, but if a parameter is passed to the CFC method, that value should be used instead. <cfargument name="dir" type="string" required="false"> <cfscript> getdir = #GetDirectoryFromPath(GetCurrentTemplatePath( ))#; if (isDefined("arguments.dir")){ getdir = arguments.dir; } </cfscript> The <cfdirectory> tag returns an array of Structs that provide information about all the files and subdirectories within a given directory. Each of the Structs has both a type and a name property, in which type can be either "Dir" or "File" and name is the name of the file or subdirectory. We sort the results first by type and then by name, yielding a listing in which the subdirectories are grouped together and alphabetized, as are the files. <cfdirectory directory="#getdir#" name="dirListing" sort="type ASC, name ASC"> 26.2.2.2 Making the server MP3 selector Flash movieThe next part of the server MP3 selector is the Flash movie that interfaces with the CFC via Flash Remoting. The Flash movie is opened in its own pop-up browser window, and it displays the directory listing using a Tree component. Once the user selects a file, the path is sent to the main jukebox movie using a local connection, just as with the local MP3 selector. Here are the steps to complete to make the MP3 selector Flash movie:
Now let's look at some of the ActionScript code in this document a little more closely. Much of the code is quite straightforward, but some sections involve techniques with which you might not be familiar. The init( ) function does not do much that is unusual. It creates a connection object and a service object that maps to the DirectoryBrowser.cfc file. In addition, it creates a response object for handling the results from the service function. This uses standard Flash Remoting techniques, as discussed in Chapter 20. The call to the service function is standard as well, but notice that we don't pass any parameters to the function. The first time this service function is called, we don't yet know the path to the directory to list. Remember that you designed the CFC function such that if it receives no parameter, it uses the directory in which the CFC is stored. function init ( ) { var gwURL = "http://localhost:8500/flashservices/gateway"; NetServices.setDefaultGatewayURL(gwURL); var conn = NetServices.createGatewayConnection( ); dirBrowserSrvc = conn.getService("DirectoryBrowser"); dirInfoRes = new Object( ); dirInfoRes.onResult = function (result) { _root.addNodes(result); }; dirBrowserSrvc.getDirectoryInfo(dirInfoRes); sender = new LocalConnection( ); currentNode = null; } The createTreeForm( ) and createCofirmForm( ) functions are very straightforward. They each create form elements, position them, and add them to forms. Then, the createMultiForm( ) function adds both forms to a multipage form and sets it to display the first page. This allows the two forms to occupy the same space while only one is visible. function createMultiForm ( ) { myMPForm = new MultiPageForm( ); myMPForm.addForm(treeForm); myMPForm.addForm(confirmForm); myMPForm.setPage(1); } The addNodes( ) function is called whenever a result is returned from the service function, which we use to populate the selected node in the Tree component. The first time this function is called, the currentNode variable is null, and the function must create the root node of the Tree component. In this case, it needs to get the directory name from the full path. One convenient way to do this is to split the path into an array using the slash as a delimiter. For example, if the path value is "C:\CFusionMX\wwwroot\", you can create an array with values "C:", "CFusionMX", "wwwroot", and an empty string (because of the trailing slash). The directory name is always either the last element of the array (in the case of no trailing slash) or the second-to-last element (in the case of a trailing slash). This code finds the directory name in either case: if (currentNode == null) { var dirNameAr = dlInfo.dir.split("\\"); var dirName = dirNameAr[dirNameAr.length - 1]; if (dirName == "") { dirName = dirNameAr[dirNameAr.length - 2]; } var node = new FTreeNode( ); node.setLabel(dirName); node.setData(dlInfo.dir); tree.setRootNode(node); currentNode = node; } When the user selects a file element from a tree node, you need to know the path to that file on the server. For this purpose, you should store the directory path (dlInfo.dir) as a property of the node that is currently being populated. Additionally, to append the filename to the path, the path must end in a trailing slash, so we add a trailing slash, if necessary: currentNode.baseDir = dlInfo.dir; if (currentNode.baseDir.lastIndexOf("\\") != currentNode.baseDir.length - 1) { currentNode.baseDir += "\\"; } The custom hasContents property tells Flash if a node already has contents loaded into it: currentNode.hasContents = true; Once the contents have been retrieved from the server, it would be wasteful to request that information again, so we'll make future Flash Remoting requests only if hasContents is not true. The last part of the addNodes( ) function populates the selected node with the contents. The dirListing property of the object that is returned from the service function is an array of objects in which each object has a name and type property (this is the value that the <cfdirectory> returns). To populate the selected node, use a for statement to loop through all the elements of the object array. For each element, create a tree node in which the label is the name of the file or subdirectory, and the data is the full path to the file or subdirectory. Furthermore, if the element is a subdirectory, use the setIsBranch( ) method to configure the node so that it can be opened (expanded into a subdirectory listing). var dl = dlInfo.dirListing; for (var i = 0; i < dl.getLength( ); i++) { var tmpNode = new FTreeNode( ); tmpNode.setLabel(dl.getItemAt(i).name); tmpNode.setData(currentNode.baseDir + dl.getItemAt(i).name); tmpNode.type = dl.getItemAt(i).type; if (dl.getItemAt(i).type.toLowerCase( ) == "dir") { tmpNode.setIsBranch(true); } tree.addNode(currentNode, tmpNode); } The doSelect( ) callback function is invoked whenever a tree node is selected. To process the node, you must determine its type. Nodes that represent files are not branch nodes, as detected with the isBranch( ) method. When a user selects a file from the Tree component, you should:
Notice that the path.data value is a substring of the selected node's data value. The jukebox movie needs to know only the relative path to the file and not the full path. Since the CFC and the jukebox .swf file are stored in the same directory, the relative path to the selected file is the difference between the full path to the file and the full path to the application's root directory (which is stored in the baseDir property of the Tree component's root node object). For example, if the full path to the selected file is C:\CFusionMX\wwwroot\myMp3.mp3 and the full path to the application's root directory is C:\CFusionMX\wwwroot\, then the relative path to the file is simply myMp3.mp3. You can employ a little trick to determine the relative path: start with the file's full path, and then extract the substring starting from the length of the root's path and spanning to the end of the string. Additionally, set the currentNode variable to reference the selected node. If the contents of the node have not been downloaded, call the service function to retrieve the data, passing it the path to the directory that the node represents. function doSelect (tr) { var sn = tr.getSelectedNode( ); if (!sn.isBranch( )) { path.text = sn.getLabel( ); path.data = sn.getData().substr(tree.getRootNode( ).baseDir.length); pathUploadConfirm.text = "the file: \n" + path.data + "\n has been added to the playlist"; } currentNode = sn; if (!sn.hasContents) { dirBrowserSrvc.getDirectoryInfo(dirInfoRes, sn.getData( )); } } When the user clicks the Submit button, send the relative path of the selected file to the main jukebox using a local connection. Additionally, display the next page of the multipage form (the confirmation screen). function submitSelected ( ) { if (path.data != undefined) { sender.send("pathSendConnection", "receivePathInfo", path.data); myMPForm.setPage(2); } } 26.2.2.3 Making the HTML page for the server MP3 selectorThe last step in making the server MP3 selector is to export the .swf file and create the HTML page in which to embed it. Flash's Publish feature creates both the .swf and .html files. Afterwards, we modify the .html file to set the margins to 0 so that the Flash movie is flush with the top-left corner of the browser window. Here are the steps to create the .swf file and HTML page:
26.2.2.4 Notes on the server MP3 selectorNote the following when implementing the server MP3 selector:
|
[ Team LiB ] |