<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>hubflanger &#187; Flash</title>
	<atom:link href="http://hubflanger.com/tag/flash/feed/" rel="self" type="application/rss+xml" />
	<link>http://hubflanger.com</link>
	<description>adventures in code</description>
	<lastBuildDate>Mon, 29 Mar 2010 22:41:12 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<atom:link rel='hub' href='http://hubflanger.com/?pushpress=hub'/>
		<item>
		<title>A Robotlegs Flash Site Tutorial</title>
		<link>http://hubflanger.com/a-robotlegs-flash-site-tutorial/</link>
		<comments>http://hubflanger.com/a-robotlegs-flash-site-tutorial/#comments</comments>
		<pubDate>Mon, 29 Mar 2010 22:41:12 +0000</pubDate>
		<dc:creator>Peng</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Robotlegs]]></category>

		<guid isPermaLink="false">http://hubflanger.com/?p=444</guid>
		<description><![CDATA[Robotlegs is a light-weight, pure AS3 micro-architecture that has developed some intense devotion amongst the Flash community recently. Created by Shaun Smith, it provides a mechanism for wiring your objects together in a decoupled way, and through the use of automated metadata based dependency injection, Robotlegs removes boilerplate code in an application. 
If you&#8217;re familiar [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.robotlegs.org/">Robotlegs</a> is a light-weight, pure AS3 micro-architecture that has developed some intense devotion amongst the Flash community recently. Created by <a href="http://shaun.boyblack.co.za/blog/">Shaun Smith</a>, it provides a mechanism for wiring your objects together in a decoupled way, and through the use of automated metadata based dependency injection, Robotlegs removes boilerplate code in an application. </p>
<p>If you&#8217;re familiar with PureMVC, you&#8217;ll find lots of similarities in Robotlegs and then some &#8211; cool features such as Dependency Injection. In this tutorial, I shall demonstrate how to build a typical Flash site with Robotlegs, similar to the one in my <a href="http://hubflanger.com/building-a-flash-site-using-puremvc/">PureMVC Flash Site</a> tutorial. The application begins by loading an xml document, parsing that data, and finally displaying a Flash site based on the dynamic data.</p>
<p><span id="more-444"></span><br />
<a href="/demos/robotlegs_flashsite/">View Demo</a></p>
<p><a href="http://github.com/hubflanger/Robotlegs_Flash_Site">Download Source Files</a></p>
<h3>Using Robotlegs with Flash CS3 / CS4</h3>
<p>Since Robotlegs relies on custom metadata for its dependency injection and Flash CS3/CS4 don&#8217;t support compiling custom metadata, Robotlegs is more suited for a workflow that doesn&#8217;t rely on the Flash IDE for compilation. However, the bundled SwiftSuspenders DI solution does provide a way to configure injection points using XML, allowing for <a href="http://knowledge.robotlegs.org/faqs/framework-core/is-robotlegs-compatible-with-the-flash-ide-cs3cs4">Robotlegs usage in Flash CS3/CS4 compiled projects</a>. Helmut Granda has written a <a href="http://www.helmutgranda.com/2009/12/02/robotlegs-and-flash-ide-cs4-injection/">detailed tutorial</a> on how to configure the SwiftSuspenders XML_CONFIG to enable this.</p>
<h3>Prerequisites</h3>
<p>This tutorial shall assume that you are familiar with setting up an Actionscript only project in Flex/Flash Builder, FDT or Flash Develop. You must also be comfortable with compiling your AS3 project using the MXMLC compiler. If you must use the Flash IDE, please follow the suggested links above to set up your environment to support the dependency injection solution.</p>
<h3>1. Examine the asset.fla</h3>
<p>In this example, the FLA is purely used to generate a SWC containing the font assets which will be imported into the application. </p>
<h3>2. The RobotlegsFlashSite document class</h3>
<p>The document class registers the Georgia and Helvetica fonts by creating the respective font instances. It also creates an instance of the <code>ApplicationContext</code> class. </p>
<div class="codeblock">
<pre>
package
{
  import Georgia;
  import Helvetica;

  import flash.display.*;
  import flash.text.Font;

  import com.hubflanger.robotlegsdemo.ApplicationContext;

  public class RobotlegsFlashSite extends Sprite
  {
    protected var context:ApplicationContext;

    public function RobotlegsFlashSite()
    {
      stage.scaleMode = StageScaleMode.NO_SCALE;

      var georgia:Font = new Georgia();
      var helvetica:Font = new Helvetica();

      context = new ApplicationContext(this);
    }
  }
}
</pre>
</div>
<h3>3. The ApplicationContext class</h3>
<p>The Context lies in the heart of a Robotlegs implementation, providing the mechanism by which the implementation’s tiers will communicate. The Context provides three functions within an application: initialization, de-initialization, and creates the central event bus for communication. Although an application is not limited to a single Context, for many use cases one Context is sufficient. </p>
<p>The <code>ApplicationContext</code> class extends the base <code>Context</code> class in the Robotlegs framework. Its constructor accepts an instance of the <code>RobotlegsFlashSite</code> document class which is assigned to the variable <code>contextView</code>. Later on, we shall see how <code>contextView</code> is accessed throughout the application. </p>
<p>In a Robotlegs implementation, we typically override the <code>startup()</code> method to set up all the mappings for dependency injection, views and events. Here, we map a Singleton of <code>SiteModel</code> and an instance of <code>SiteDataService</code> which implements the <code>ISiteDataService</code> interface to the <code>Injector</code>. This makes them available to other classes in the application via the <code>[Inject]</code> metadata. </p>
<p>We then map 3 view classes (<code>Header</code>, <code>Navigation</code> and <code>SectionContainer</code>) to their respective Mediators by calling the <code>mapView()</code> method of the <code>MediatorMap</code> instance. In Robotlegs, a <code>Mediator</code> performs similar functions as ones in PureMVC. A <code>Mediator</code> provides a bridge between the framework and the View Component it&#8217;s responsible for. It passes along framework events to its view component and sends framework events in response to events dispatched by its view component. By putting application-specific logic in the <code>Mediator</code>, we de-couple the view component from the application&#8217;s implementation.</p>
<p>Finally, we call the <code>mapEvent()</code> method of the <code>CommandMap</code> instance to map 3 events to their respective Commands. The <code>ContextEvent.STARTUP_COMPLETE</code> event is dispatched by the framework upon completing execution of the Context&#8217;s <code>startup()</code> method. Here, we map the <code>LoadDataCommand</code> class to handle this event.</p>
<div class="codeblock">
<pre>
package com.hubflanger.robotlegsdemo
{
  import com.hubflanger.robotlegsdemo.model.SiteModel;
  import com.hubflanger.robotlegsdemo.controller.*;
  import com.hubflanger.robotlegsdemo.service.*;
  import com.hubflanger.robotlegsdemo.events.*;
  import com.hubflanger.robotlegsdemo.view.*;
  import com.hubflanger.robotlegsdemo.view.components.*;

  import flash.display.DisplayObjectContainer;

  import org.robotlegs.mvcs.Context;
  import org.robotlegs.base.ContextEvent;

  public class ApplicationContext extends Context
  {
    public function ApplicationContext(contextView:DisplayObjectContainer)
    {
      super(contextView);
    }

    override public function startup():void
    {
      injector.mapSingleton(SiteModel);

      injector.mapClass(ISiteDataService, SiteDataService);

      mediatorMap.mapView(Header, HeaderMediator);
      mediatorMap.mapView(Navigation, NavigationMediator);
      mediatorMap.mapView(SectionContainer, SectionContainerMediator);

      commandMap.mapEvent(ContextEvent.STARTUP_COMPLETE, LoadDataCommand, ContextEvent, true);
      commandMap.mapEvent(SystemEvent.INIT_VIEW, InitViewCommand, SystemEvent, true);
      commandMap.mapEvent(UserEvent.NAV_CLICK, SectionSelectedCommand, UserEvent, false);

      super.startup();
    }
  }
}
</pre>
</div>
<h3>4. The LoadDataCommand class</h3>
<p>As intended by the command mapping, the <code>LoadDataCommand</code> command responds to the Context&#8217;s <code>STARTUP_COMPLETE</code> event. It creates an instance of <code>SiteDataService</code> using the <code>[Inject]</code> metadata. In its <code>execute()</code> method, we call the <code>loadData()</code> method of the <code>SiteDataService</code> instance to initiate the loading of xml data.</p>
<div class="codeblock">
<pre>
package com.hubflanger.robotlegsdemo.controller
{
  import com.hubflanger.robotlegsdemo.service.ISiteDataService;

  import org.robotlegs.mvcs.Command;

  public class LoadDataCommand extends Command
  {
    [Inject]
    public var siteDataService:ISiteDataService;

    override public function execute():void
    {
      siteDataService.loadData();
    }
  }
}
</pre>
</div>
<h3>5. The SiteDataService class</h3>
<p>In Robotlegs, Model and Service classes extend the base <code>Actor</code> class to inherit functionality for communicating with the framework. A Model encapsulates and provides an API for data and sends event notifications when the data model has been changed. A Service communicates with the outside world through web services or file access and dispatches system events in response to external events. </p>
<p>In the <code>SiteDataService</code> class, we access the <code>SiteModel</code> singleton via the <code>[Inject]</code> metadata and assign it to the <code>model</code> variable. The <code>loadData()</code> method creates a URLLoader instance and loads the xml.</p>
<p>The <code>loadCompleteHandler</code> event handler parses the xml data, creates <code>SectionVO</code> objects for each section node and stores them in the <code>SiteModel</code> singleton. It then dispatches a <code>SystemEvent.INIT_VIEW</code> event to the framework, instructing the application to start its view construction.</p>
<div class="codeblock">
<pre>
package com.hubflanger.robotlegsdemo.service
{
  import com.hubflanger.robotlegsdemo.model.vo.SectionVO;
  import com.hubflanger.robotlegsdemo.model.SiteModel;
  import com.hubflanger.robotlegsdemo.events.SystemEvent;

  import flash.events.Event;
  import flash.net.*;

  import org.robotlegs.mvcs.Actor;

  public class SiteDataService extends Actor implements ISiteDataService
  {
    [Inject]
    public var model:SiteModel;

    public function SiteDataService()
    {
      //
    }

    public function loadData():void
    {
      var loader:URLLoader = new URLLoader();
      loader.addEventListener(Event.COMPLETE, loadCompleteHandler);
      loader.load(new URLRequest("assets/data.xml"));
    }

    private function loadCompleteHandler(event:Event):void
    {
      var loader:URLLoader = event.target as URLLoader;
      loader.removeEventListener(Event.COMPLETE, loadCompleteHandler);

      var xml:XML = new XML(event.target.data);
      model.header = xml.header.text();

      var sections:XMLList = xml.sections.section;

      for each (var section:XML in sections) {
        var sectionVO:SectionVO = new SectionVO(section.@id,
                            section.label.toString(),
                            section.content.toString());

        model.sectionsList.push(sectionVO);
        model.sectionsHash[sectionVO.id] = sectionVO;
      }

      model.defaultSection = model.sectionsList[0].id;

      dispatch(new SystemEvent(SystemEvent.INIT_VIEW, false));
    }
  }
}
</pre>
</div>
<h3>6. The InitViewCommand class</h3>
<p>The <code>InitViewCommand</code> command responds to the <code>SystemEvent.INIT_VIEW</code> event by instantiating 3 view components and adding them as children to the main display container. In Robotlegs, the mappings in the MediatorMap as shown in <code>ApplicationContext</code> allows a Mediator to be automatically created when its view component is instantiated.</p>
<div class="codeblock">
<pre>
package com.hubflanger.robotlegsdemo.controller
{
  import com.hubflanger.robotlegsdemo.model.SiteModel;
  import com.hubflanger.robotlegsdemo.view.components.*;

  import org.robotlegs.mvcs.Command;

  public class InitViewCommand extends Command
  {
    [Inject]
    public var model:SiteModel;

    override public function execute():void
    {
      contextView.addChild(new SectionContainer());
      contextView.addChild(new Header());
      contextView.addChild(new Navigation());
    }
  }
}
</pre>
</div>
<h3>6. The NavigationMediator class</h3>
<p>We won&#8217;t be getting into in-depth discussions of the view classes except to say they&#8217;re pretty generic display containers extending the Sprite class. Instead, we shall take a look at the <code>NavigationMediator</code> and see how it handles Mouse Click events dispatched by the <code>NavButton</code> instances in the <code>Navigation</code> view component. </p>
<p>Typically, one takes advantage of the <code>onRegister()</code> handler which is invoked when the Mediator has been registered with the framework, to perform set up tasks on the view component and map events with their event handlers. Here, we invoke the view component&#8217;s <code>init()</code> method and pass the <code>SiteModel</code>&#8217;s sectionsList array so that the <code>Navigation</code> view component will dynamically create a list of <code>NavButton</code> instances. Then we invoke the <code>mapListener()</code> method of the <code>EventMap</code> instance to map a <code>SystemEvent.SECTION_CHANGED</code> framework event and a <code>NavButton.CLICK</code> user event with their respective event handlers. Finally, it calls the <code>dispatch()</code> method sending a <code>UserEvent.NAV_CLICK</code> custom event with the default section&#8217;s ID to the framework. </p>
<p>The <code>navClickHandler()</code> responds to <code>NavButton.CLICK</code> events bubbled from the <code>NavButton</code> instances. It in turn dispatches a <code>UserEvent.NAV_CLICK</code> event to the framework. This is how user interactions with display objects are commonly handled in Robotlegs.</p>
<p>As you can see, <code>NavigationMediator</code> extends the base Mediator class of the Robotlegs framework and inherits from it a bunch of useful features. In addition to dependency injection, the <code>EventMap</code> instance is a built-in property and the <code>dispatch()</code> method allows the Mediator to communicate events to the framework. </p>
<div class="codeblock">
<pre>
package com.hubflanger.robotlegsdemo.view
{
  import com.hubflanger.robotlegsdemo.model.SiteModel;
  import com.hubflanger.robotlegsdemo.view.components.Navigation;
  import com.hubflanger.robotlegsdemo.view.components.NavButton;
  import com.hubflanger.robotlegsdemo.events.*;

  import flash.events.*;

  import org.robotlegs.mvcs.Mediator;

  public class NavigationMediator extends Mediator
  {
    [Inject]
    public var model:SiteModel;

    [Inject]
    public var nav:Navigation;

    public function NavigationMediator()
    {
      //
    }

    override public function onRegister():void
    {
      nav.init(model.sectionsList);

      eventMap.mapListener(eventDispatcher, SystemEvent.SECTION_CHANGED, sectionChangeHandler);
      eventMap.mapListener(nav, NavButton.CLICK, navClickHandler);

      dispatch(new UserEvent(UserEvent.NAV_CLICK, model.defaultSection));
    }

    private function navClickHandler(event:Event):void
    {
      event.stopPropagation();
      var btn:NavButton = event.target as NavButton;

      if (!btn.isSelected)
        dispatch(new UserEvent(UserEvent.NAV_CLICK, btn.id));
    }

    private function sectionChangeHandler(event:SystemEvent):void
    {
      nav.update(model.currentSection);
    }
  }
}
</pre>
</div>
<h3>7. The SectionSelectedCommand class</h3>
<p>Earlier in <code>ApplicationContext</code>, we see that the <code>SectionSelectedCommand</code> is mapped to the <code>UserEvent.NAV_CLICK</code> event. It assigns the event&#8217;s <code>id</code>&#8217;s property to the <code>currentSection</code> property of the <code>SiteModel</code> instance.</p>
<div class="codeblock">
<pre>
package com.hubflanger.robotlegsdemo.controller
{
  import com.hubflanger.robotlegsdemo.model.SiteModel;
  import com.hubflanger.robotlegsdemo.events.UserEvent;

  import org.robotlegs.mvcs.Command;

  public class SectionSelectedCommand extends Command
  {
    [Inject]
    public var model:SiteModel;

    [Inject]
    public var event:UserEvent;

    override public function execute():void
    {
      model.currentSection = event.id;
    }
  }
}
</pre>
</div>
<h3>8. SiteModel&#8217;s currentSection setter</h3>
<p>In the <code>currentSection</code> setter, upon updating the value of the <code>_currentSection</code> variable, the Model dispatches a <code>SystemEvent.SECTION_CHANGED</code> framework event. This event announces to the application that the Model has been changed and the views will then respond accordingly by updating their display states.</p>
<div class="codeblock">
<pre>
public function set currentSection(value:String):void
{
  _currentSection = value;
  dispatch(new SystemEvent(SystemEvent.SECTION_CHANGED, false));
}
</pre>
</div>
<h3>8. NavigationMediator&#8217;s sectionChangeHandler</h3>
<p>The <code>NavigationMediator</code>&#8217;s <code>sectionChangeHandler()</code> responds to the <code>SystemEvent.SECTION_CHANGED</code> event by invoking the view component&#8217;s <code>update()</code> method passing along the Model&#8217;s <code>currentSection</code> property. This causes the <code>NavButton</code> instances to update their display states to reflect the section selected.</p>
<h3>9. The SectionContainerMediator class</h3>
<p>The <code>SectionContainerMediator</code> is set up in a fashion similar to <code>NavigationMediator</code>. Here, we override the <code>onRegister()</code> handler to invoke the <code>init()</code> method of the view component passing the <code>sectionsHash</code> property of the <code>SiteModel</code> instance. It also maps <code>sectionChangeHandler()</code> to handle the <code>SystemEvent.SECTION_CHANGED</code> framework event.</p>
<p>As in <code>NavigationMediator</code>, the <code>sectionChangeHandler()</code> invokes the <code>update()</code> method of the view container passing the <code>currentSection</code> property of the <code>SiteModel</code> instance. This causes the <code>SectionContainer</code> view component to update the display of its content according to the section selected.</p>
<div class="codeblock">
<pre>
package com.hubflanger.robotlegsdemo.view
{
  import com.hubflanger.robotlegsdemo.model.SiteModel;
  import com.hubflanger.robotlegsdemo.view.components.SectionContainer;
  import com.hubflanger.robotlegsdemo.events.SystemEvent;

  import org.robotlegs.mvcs.Mediator;

  public class SectionContainerMediator extends Mediator
  {
    [Inject]
    public var model:SiteModel;

    [Inject]
    public var container:SectionContainer;

    public function SectionContainerMediator()
    {
      //
    }

    override public function onRegister():void
    {
      container.init(model.sectionsHash);
      eventMap.mapListener(eventDispatcher, SystemEvent.SECTION_CHANGED, sectionChangeHandler);
    }

    private function sectionChangeHandler(event:SystemEvent):void
    {
      container.update(model.currentSection);
    }
  }
}
</pre>
</div>
<h3>Conclusion</h3>
<p>There you have it &#8211; a simple Robotlegs implementation in a nutshell. In addition to the features used in this demo, there are many more available to you which I have not mentioned. Please consult the <a href="http://wiki.github.com/robotlegs/robotlegs-framework/best-practices">Robotlegs documentation</a> for more details.</p>
<p>As someone who has worked with PureMVC extensively, I find Robotlegs a joy to use. Its dependency injection solution is elegant and removes a lot of the clunkiness that one often has to deal with in PureMVC, such as casting your datatypes:</p>
<div class="codeblock">
<pre>
var proxy:MyProxy = facade.retrieveProxy( MyProxy.NAME ) as MyProxy;
</pre>
</div>
<p>Also, unlike PureMVC, all events are Flash Events and there isn&#8217;t the confusion of when one must use a Notification or an Event. Although in Robotlegs, one must still distinguish between framework events and user events dispatched by the view components, it&#8217;s much easier to grasp conceptually, in my opinion. That said, I highly recommend that you give Robotlegs a try.</p>
]]></content:encoded>
			<wfw:commentRss>http://hubflanger.com/a-robotlegs-flash-site-tutorial/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Building Flash Projects with Ant and Flex Builder – Part 5</title>
		<link>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-5/</link>
		<comments>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-5/#comments</comments>
		<pubDate>Fri, 27 Nov 2009 00:24:10 +0000</pubDate>
		<dc:creator>Peng</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Flex Builder]]></category>
		<category><![CDATA[JSFL]]></category>

		<guid isPermaLink="false">http://hubflanger.com/?p=287</guid>
		<description><![CDATA[In this final installment of my series of tutorials on using Ant with Flex Builder, I&#8217;ll show you how to create a Preloader asset in the Flash IDE and export that as a SWC to be used in your Actionscript source code.
1. Download tutorial files
To begin this tutorial, please make sure you have set up [...]]]></description>
			<content:encoded><![CDATA[<p>In this final installment of my series of tutorials on using Ant with Flex Builder, I&#8217;ll show you how to create a Preloader asset in the Flash IDE and export that as a SWC to be used in your Actionscript source code.</p>
<h3>1. Download tutorial files</h3>
<p>To begin this tutorial, please make sure you have set up your workspace as suggested in <a href="/building-flash-projects-with-ant-and-flex-builder-part-1/#settingUpYourWorkspace">Part 1</a>.</p>
<p><a href="/demos/ant_demo5/">View Demo</a></p>
<p><a href="http://github.com/hubflanger/AS3_Ant_Tutorial_5">Download Source Files</a></p>
<p><span id="more-287"></span></p>
<h3>2. Examine preloaderAsset.fla</h3>
<p>The <code>preloaderAsset.fla</code> has in its library a movieclip symbol named <code>preloader</code>, linked to a class <code>PreloaderAsset</code>. Note that there is no physical Actionscript file named &#8220;PreloaderAsset.as&#8221;. This class will be created by the Flash compiler when we run the <code>compilePreloaderSWC</code> JSFL script. </p>
<h3>3. Examine the compilePreloaderSWC JSFL</h3>
<p>This script retrieves the <code>preloader</code> library symbol and exports it as a SWC to a designated location in your file system. Update the path for <code>libs/PreloaderAsset.swc</code> to reference your project directory.</p>
<div class="codeblock">
<pre>
fl.getDocumentDOM().library.selectItem("preloader", true, true);
var currentSelection = fl.getDocumentDOM().library.getSelectedItems();
currentSelection[0].exportSWC("file:///Users/peng/Workspace/FlexBuilder/Hubflanger/AS3_Ant_Tutorial_5/libs/PreloaderAsset.swc");
</pre>
</div>
<h3>4. Examine the compilePreloaderSWC Task</h3>
<p>The <code>compilePreloaderSWC</code> task invokes the <code>compilePreloaderSWC.jsfl</code> script and compiles a SWC named <code>PreloaderAsset.swc</code> into the <code>libs</code> folder of your project directory using the Flash IDE.</p>
<div class="codeblock">
<pre>
&lt;target name="compilePreloaderSWC" description="Compile the Preloader SWC with the Flash IDE"&gt;
  &lt;echo&gt;Flash IDE Compiler for file ${preloaderFLA}&lt;/echo&gt;
  &lt;echo message="|*|*|*| class cache clear | source save | compiler start |*|*|*|"/&gt;
  &lt;exec executable="open"&gt;
    &lt;arg line="${compilePreloaderSWC_jsfl} ${preloaderFLA}"/&gt;
  &lt;/exec&gt;
&lt;/target&gt;
</pre>
</div>
<h3>5. Examine Preloader.as</h3>
<p>Add the SWC into your classpath using the project&#8217;s <code>Properties->Actionscript Build Path->Library Path</code> panel. With the SWC added to the library path, the <code>Preloader</code> class can now reference the <code>PreloaderAsset</code> class and create an instance of the <code>PreloaderAsset</code> object. This allows you to add the visual asset into your <code>Preloader</code> display container. The <code>Preloader</code> class also provides functionality to update the properties of the <code>PreloaderAsset</code> instance.</p>
<div class="codeblock">
<pre>
package
{
  import flash.display.*;
  import flash.events.*;
  import flash.text.*;

  public class Preloader extends Sprite
  {
    private var _asset:PreloaderAsset;

    public function Preloader()
    {
      _asset = new PreloaderAsset();
      addChild( _asset );
    }

    public function updateProgress( bytesLoaded:uint, bytesTotal:uint ):void
    {
      var ratio:Number = bytesLoaded / bytesTotal;
      _asset.bar.scaleX = ratio;
      _asset.progessTxt.text = bytesLoaded + " kb / " + bytesTotal + " kb";
    }
  }
}
</pre>
</div>
<h3>6. Examine Demo5.as</h3>
<p>The document class <code>Demo5</code> creates a <code>Preloader</code> instance and a <code>Loader</code> instance to load an external SWF. It responds to load progress events from the <code>Loader</code> by and calling the  <code>updateProgress()</code> method of the <code>Preloader</code> instance.</p>
<div class="codeblock">
<pre>
package
{
  import flash.net.URLRequest;
  import flash.display.*;
  import flash.events.*;

  import Preloader;

  public class Demo5 extends Sprite
  {
    private var preloader:Preloader;
    private var loader:Loader;

    public function Demo5()
    {
      preloader = new Preloader();
      preloader.x = 150;
      preloader.y = 150;
      addChild( preloader );

      loader = new Loader();
      loader.contentLoaderInfo.addEventListener( Event.COMPLETE, loadCompleteHandler );
      loader.contentLoaderInfo.addEventListener( ProgressEvent.PROGRESS, loadProgressHandler );
      loader.load( new URLRequest( "externalAssets.swf" ));
    }

    private function loadProgressHandler( evt:ProgressEvent ):void
    {
      preloader.updateProgress( evt.bytesLoaded, evt.bytesTotal );
    }

    private function loadCompleteHandler( evt:Event ):void
    {
      removeChild( preloader );
      evt.target.removeEventListener( Event.COMPLETE, loadCompleteHandler );
      evt.target.removeEventListener( ProgressEvent.PROGRESS, loadProgressHandler );
      addChild( loader );
    }
  }
}
</pre>
</div>
<h3>7. Wrapping it all up</h3>
<p>The <code>compileMain</code> task includes the <code>PreloaderAsset.swc</code> by adding it to the compiler&#8217;s <code>library-path</code> option. This option will merge all classes embedded in the SWC into your SWF.</p>
<div class="codeblock">
<pre>
&lt;compiler .library-path dir="${LIB_DIR}" append="true"&gt;
  &lt;include name="PreloaderAsset.swc" /&gt;
&lt;/compiler&gt;
</pre>
</div>
<p>I hope you&#8217;ve found this series of tutorial helpful in optimizing your Flash-Actionscript development workflow. Please leave any  requests and suggestions in the comments.</p>
]]></content:encoded>
			<wfw:commentRss>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-5/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Building Flash Projects with Ant and Flex Builder – Part 4b</title>
		<link>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-4b/</link>
		<comments>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-4b/#comments</comments>
		<pubDate>Mon, 03 Aug 2009 04:52:34 +0000</pubDate>
		<dc:creator>Peng</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Flex Builder]]></category>
		<category><![CDATA[JSFL]]></category>

		<guid isPermaLink="false">http://hubflanger.com/?p=251</guid>
		<description><![CDATA[Part 4b of the Ant series expands on Part 4a by adding a Flash UI Component to the SWC. Please review Part 4a before proceeding with this tutorial.
1. Download tutorial files
To begin this tutorial, please make sure you have set up your workspace as suggested in Part 1.
View Demo
Download Source Files

2. Examine assets.fla
We begin by [...]]]></description>
			<content:encoded><![CDATA[<p>Part 4b of the Ant series expands on <a href="/building-flash-projects-with-ant-and-flex-builder-part-4a">Part 4a</a> by adding a Flash UI Component to the SWC. Please review <a href="/building-flash-projects-with-ant-and-flex-builder-part-4a">Part 4a</a> before proceeding with this tutorial.</p>
<h3>1. Download tutorial files</h3>
<p>To begin this tutorial, please make sure you have set up your workspace as suggested in <a href="/building-flash-projects-with-ant-and-flex-builder-part-1/#settingUpYourWorkspace">Part 1</a>.</p>
<p><a href="/demos/ant_demo_4b/">View Demo</a></p>
<p><a href="http://github.com/hubflanger/AS3_Ant_Tutorial_4b">Download Source Files</a></p>
<p><span id="more-251"></span></p>
<h3>2. Examine assets.fla</h3>
<p>We begin by dragging an instance of the <code>Button</code> UI Component from the <em>Components Panel</em>. This creates a <code>Button</code> symbol in the library. Note that the <code>Button</code> symbol is linked to the <code>fl.controls.Button</code> class. The <em>Publish Settings</em> of the FLA are set to compile the SWF to the <code>../libs/</code> directory. Under the <em>Flash</em> tab, note that the <em>Export SWC</em> option is checked. This causes the Flash compiler to output a companion SWC whenever a SWF is being published.</p>
<h3>3. Examine compileAssetsSWC.jsfl</h3>
<p>As in previous examples, the <code>compileAssetsSWC.jsfl</code> script opens the <code>assets</code> FLA and tells it to compile its SWF. </p>
<h3>4. Examine the compileAssetsSWC task in build.xml</h3>
<p>As in previous examples, the <code>compileAssetsSWC</code> task calls the <code>compileAssetsSWC.jsfl</code> script passing along a reference to the <code>assets</code> FLA. Run the task by double-clicking <code>compileAssetsSWC</code> in the Ant panel in Flex Builder. Due to the publish settings, an <code>assets.swc</code> file will be published to the <code>libs</code> folder along with <code>assets.swf</code>. We can ignore <code>assets.swf</code> as it won&#8217;t be needed for this tutorial.</p>
<div class="codeblock">
<pre>
&lt;target name="compileAssetsSWC" description="Compile the assets SWC with the Flash IDE"&gt;
  &lt;echo&gt;Flash IDE Compiler for file ${assetsFLA}&lt;/echo&gt;
  &lt;echo message="|*|*|*| class cache clear | source save | compiler start |*|*|*|"/&gt;
  &lt;exec executable="open"&gt;
    &lt;arg line="${compileAssetsSWC_jsfl} ${assetsFLA}"/&gt;
  &lt;/exec&gt;
&lt;/target&gt;
</pre>
</div>
<h3>5. Adding assets.swc to your Classpath</h3>
<p>Add the <code>assets</code> SWC to your classpath as described in <a href="/building-flash-projects-with-ant-and-flex-builder-part-4a/#step5">Step 5</a> of tutorial <a href="/building-flash-projects-with-ant-and-flex-builder-part-4a">Part 4a</a>.</p>
<h3>6. Examine Demo4.as</h3>
<p>In addition to <code>Square</code> instance, <code>Demo4.as</code> creates an instance of the <code>Button</code> component and adds it to the stage. </p>
<div class="codeblock">
<pre>
package
{
  import flash.display.*;
  import fl.controls.Button;

  public class Demo4 extends Sprite
  {
    private var square:Square;
    private var button:Button;

    public function Demo4()
    {
      square = new Square();
      square.x = 200;
      square.y = 100;
      addChild( square );

      button = new Button();
      button.x = 200;
      button.y = 250;
      addChild( button );
    }
  }
}
</pre>
</div>
<h3>7. Adding assets.swc to the MXMLC compiler</h3>
<p>As in <a href="/building-flash-projects-with-ant-and-flex-builder-part-4a">Part 4a</a>, we add a reference to <code>assets.swc</code> for the MXMLC compiler with the code snippet below, in <code>build.xml</code>. Run the <code>compileProject</code> task and load <code>index.html</code> in your web browser. You&#8217;ll see a green square and a <code>Button</code> component in your SWF.</p>
<div class="codeblock">
<pre>
&lt;compiler.library-path dir="${LIB_DIR}" append="true"&gt;
  &lt;include name="assets.swc" /&gt;
&lt;/compiler.library-path&gt;
</pre>
</div>
<h3>Coming up</h3>
<p>In the next and <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-5/">final installment</a> of this series of tutorials on Ant, we shall explore using a SWC to create a Preloader for your application.</p>
]]></content:encoded>
			<wfw:commentRss>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-4b/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Building Flash Projects with Ant and Flex Builder &#8211; Part 4a</title>
		<link>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-4a/</link>
		<comments>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-4a/#comments</comments>
		<pubDate>Mon, 03 Aug 2009 03:33:30 +0000</pubDate>
		<dc:creator>Peng</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Flex Builder]]></category>
		<category><![CDATA[JSFL]]></category>

		<guid isPermaLink="false">http://hubflanger.com/?p=161</guid>
		<description><![CDATA[First off, if you&#8217;ve been waiting for this installment of my series of tutorials on Ant, I offer my sincere apologies. I&#8217;ve been sidetracked by iPhone development and haven&#8217;t been able to find time to finish off these tutorials. As promised, here&#8217;s a follow up to my previous tutorials.
In Part 4a, I shall show you [...]]]></description>
			<content:encoded><![CDATA[<p>First off, if you&#8217;ve been waiting for this installment of my series of tutorials on Ant, I offer my sincere apologies. I&#8217;ve been sidetracked by iPhone development and haven&#8217;t been able to find time to finish off these tutorials. As promised, here&#8217;s a follow up to my previous tutorials.</p>
<p>In Part 4a, I shall show you how to compile a Flash library symbol as a SWC, add this SWC to your Actionscript classpath and compile your application with the Flex MXMLC compiler.</p>
<h3>1. Download tutorial files</h3>
<p>To begin this tutorial, please make sure you have set up your workspace as suggested in <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-1/#settingUpYourWorkspace">Part 1</a>.</p>
<p><a href="http://hubflanger.com/demos/ant_demo_4a/">View Demo</a></p>
<p><a href="http://github.com/hubflanger/AS3_Ant_Tutorial_4a">Download Source Files</a></p>
<p><span id="more-161"></span></p>
<h3>2. Examine assets.fla</h3>
<p>In <code>fla/assets.fla</code>, you&#8217;ll find in the library, a simple square graphic linked to a class named <code>Square</code>. </p>
<h3>3. Examine compileSquareSWC.jsfl</h3>
<p>This JSFL script targets the <code>square</code> symbol in the library, and exports it as a SWC into the specified directory. In this case, my target output directory is <code>file:///Users/peng/Workspace/FlexBuilder/Hubflanger/<br />AS3_Ant_Tutorial_4a/libs/</code>. You should enter the correct path to the <code>libs</code> folder in your project.</p>
<div class="codeblock">
<pre>
fl.getDocumentDOM().library.selectItem("square", true, true);
var currentSelection = fl.getDocumentDOM().library.getSelectedItems();
currentSelection[0].exportSWC("file:///Users/peng/Workspace/FlexBuilder/Hubflanger/AS3_Ant_Tutorial_4a/libs/square.swc");
</pre>
</div>
<h3>4. Examine the compileSquareSWC task in build.xml</h3>
<p>The <code>build</code> file contains a task named <code>compileSquareSWC</code> which calls the <code>compileSquareSWC.jsfl</code> script passing along a reference to the <code>assets</code> FLA. Run the task by double-clicking <code>compileSquareSWC</code> in the Ant panel in Flex Builder. You&#8217;ll see that a SWC named <code>square</code> has been exported to the <code>libs</code> folder.</p>
<div class="codeblock">
<pre>
&lt;target name="compileSquareSWC" description="Compile the square SWC with the Flash IDE"&gt;
  &lt;echo&gt;Flash IDE Compiler for file ${assetsFLA}&lt;/echo&gt;
  &lt;echo message="|*|*|*| class cache clear | source save | compiler start |*|*|*|"/&gt;
  &lt;exec executable="open"&gt;
    &lt;arg line="${compileSquareSWC_jsfl} ${assetsFLA}"/&gt;
  &lt;/exec&gt;
&lt;/target&gt;
</pre>
</div>
<p><a name="step5"></a></p>
<h3>5. Adding square.swc to your Classpath</h3>
<p>Before you can create a reference to the <code>Square</code> class, you need to add the SWC to your classpath. To do so, first right-click on your project and open the <em>Properties</em> panel. In <em>ActionScript Build Path</em>, select the <em>Library Path</em> tab. Click the <em>Add SWC</em> button, navigate to the <code>libs</code> folder and select the <code>square.swc</code> file. Alternatively, you can click the <em>Add SWC Folder</em> button and select the <code>libs</code> folder. This will add all the SWCs in that folder to your classpath.</p>
<p>By adding the SWC to your classpath in Flex Builder, you&#8217;ll be able to reference the <code>Square</code> class in your Actionscript classes along with code completion.</p>
<h3>6. Examine Demo4.as</h3>
<p><code>Demo4.as</code> creates an instance of the <code>Square</code> object and adds it to the stage. </p>
<div class="codeblock">
<pre>
package
{
  import flash.display.*;

  public class Demo4 extends Sprite
  {
    private var square:Square;

    public function Demo4()
    {
      square = new Square();
      square.x = 200;
      square.y = 100;
      addChild( square );
    }
  }
}
</pre>
</div>
<h3>7. Adding square.swc to the MXMLC compiler</h3>
<p>In order to compile the application, we also need to add a reference to <code>square.swc</code> for the MXMLC compiler. The code snippet below found in <code>build.xml</code> does just that. Run the <code>compileMain</code> task and load <code>index.html</code> in your web browser. You&#8217;ll see a green square in your SWF. Similar to <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-3/">Part 3</a>, the <code>compileProject</code> task allows you to execute both <code>compileMain</code> and <code>compileSquareSWC</code> in sequence with a simple double-click.</p>
<div class="codeblock">
<pre>
&lt;compiler.library-path dir="${LIB_DIR}" append="true"&gt;
  &lt;include name="square.swc" /&gt;
&lt;/compiler.library-path&gt;
</pre>
</div>
<h3>Coming up</h3>
<p>In <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-4b/">Part 4b</a>, we&#8217;ll see how we can compile Flash UI Components to a SWC and reference them in our Actionscript classes.</p>
]]></content:encoded>
			<wfw:commentRss>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-4a/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Building Flash Projects with Ant and Flex Builder &#8211; Part 3</title>
		<link>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-3/</link>
		<comments>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-3/#comments</comments>
		<pubDate>Tue, 17 Feb 2009 02:58:13 +0000</pubDate>
		<dc:creator>Peng</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Flex Builder]]></category>
		<category><![CDATA[JSFL]]></category>

		<guid isPermaLink="false">http://hubflanger.com/?p=160</guid>
		<description><![CDATA[In Part 3 of this tutorial, we shall use a combination of the MXMLC compiler and JSFL script to compile an external SWF which will be loaded into your main SWF.
1. Download tutorial files
To begin this tutorial, please make sure you have set up your workspace as suggested in Part 1.
View Demo
Download Source Files

2. Examine [...]]]></description>
			<content:encoded><![CDATA[<p>In Part 3 of this tutorial, we shall use a combination of the MXMLC compiler and JSFL script to compile an external SWF which will be loaded into your main SWF.</p>
<h3>1. Download tutorial files</h3>
<p>To begin this tutorial, please make sure you have set up your workspace as suggested in <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-1/#settingUpYourWorkspace">Part 1</a>.</p>
<p><a href="http://hubflanger.com/demos/ant_demo3/">View Demo</a></p>
<p><a href="http://github.com/hubflanger/AS3_Ant_Tutorial_3">Download Source Files</a></p>
<p><span id="more-160"></span></p>
<h3>2. Examine externalAssets.fla</h3>
<p>In <code>fla/externalAssets.fla</code>, you&#8217;ll find a bitmap image in the first frame of the main timeline. This FLA is set up to publish a SWF named <code>externalAssets.swf</code> into the <code>bin-debug</code> folder. </p>
<h3>3. Examine compileSWF.jsfl</h3>
<p>You&#8217;ll notice that this JSFL script is exactly the same as the one in <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-1/#compileSWF_JSFL">Part 1</a>. As we shall soon see, this script is completely reusable and we shall use it to compile the <code>externalAssets.swf</code>.</p>
<h3>4. Examine the compileAssetsSWF task in build.xml</h3>
<p>The <code>build</code> file contains a task named <code>compileAssetsSWF</code> which is similar to the task named <code>compileMain</code> previously mentioned <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-1/">Part 1</a> of this tutorial. It reuses the <code>compileSWF.jsfl</code> script to compile a SWF by passing in <code>assetsFLA</code> as its argument.</p>
<div class="codeblock">
<pre>
&lt;target name="compileAssetsSWF" description="Compile the Assets SWF with the Flash IDE"&gt;
  &lt;echo&gt;Flash IDE Compiler for file ${assetsFLA}&lt;/echo&gt;
  &lt;echo message="|*|*|*| class cache clear | source save | compiler start |*|*|*|"/&gt;
  &lt;exec executable="open"&gt;
    &lt;arg line="${compileSWF_jsfl} ${assetsFLA}"/&gt;
  &lt;/exec&gt;
&lt;/target&gt;
</pre>
</div>
<h3>5. Examine Demo3.as</h3>
<p><code>Demo3.as</code> creates a Loader instance which loads in an external SWF called <code>externalAssets.swf</code>. The <code>loadCompleteHandler</code> then adds the Loader instance onto the main stage.</p>
<div class="codeblock">
<pre>
package
{
  import flash.display.*;
  import flash.events.Event;
  import flash.net.URLRequest;

  public class Demo3 extends Sprite
  {
    private var loader:Loader;

    public function Demo3()
    {
      loader = new Loader();
      loader.contentLoaderInfo.addEventListener( Event.COMPLETE, loadCompleteHandler );
      loader.load( new URLRequest( "externalAssets.swf" ));
    }    

    private function loadCompleteHandler( evt:Event ):void
    {
      evt.target.removeEventListener( Event.COMPLETE, loadCompleteHandler );
      addChild( loader );
    }
  }
}
</pre>
</div>
<h3>6. Examine the compileMain task in build.xml</h3>
<p>We also have a <code>compileMain</code> task which is the same as the one in <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-2/#compileMain">Part 2</a> except that it passes in Demo3.as as the argument to the MXMLC compiler.</p>
<div class="codeblock">
<pre>
&lt;target name="compileMain"&gt;
  &lt;echo&gt;Compiles Demo3.as file and outputs demo3.swf&lt;/echo&gt;
  &lt;mxmlc file="${SRC_DIR}/Demo3.as" output="${DEPLOY_DIR}/demo3.swf"
    actionscript-file-encoding="UTF-8"
    incremental="false"
    debug="true"
    default-frame-rate="31"
    default-background-color="0xCCCCCC"&gt;

    &lt;load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/&gt;
    &lt;source-path path-element="${FLEX_HOME}/frameworks"/&gt;
    &lt;source-path path-element="${SRC_DIR}" /&gt;

    &lt;!-- Set size of output SWF file. --&gt;
    &lt;default-size width="550" height="400" /&gt;
  &lt;/mxmlc&gt;
&lt;/target&gt;
</pre>
</div>
<h3>7. Examine the compileProject task in build.xml</h3>
<p>Finally, we have a composite task named <code>compileProject</code> which allows you to execute its dependent tasks ie. <code>compileMain</code> and <code>compileAssetsSWF</code> in sequence with just a double-click.</p>
<div class="codeblock">
<pre>
&lt;target name="compileProject" depends="compileAssetsSWF, compileMain" /&gt;
</pre>
</div>
<h3>Coming up</h3>
<p>As you can see, Ant tasks are highly flexible &#8211; allowing you to customize your workflow by combining varies different techniques, whether you prefer the Flash IDE or the MXMLC compiler. In <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-4a/">Part 4</a>, we shall discuss using Ant to compile SWCs and how to add SWCs to your workflow.</p>
]]></content:encoded>
			<wfw:commentRss>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-3/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Building Flash Projects with Ant and Flex Builder &#8211; Part 2</title>
		<link>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-2/</link>
		<comments>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-2/#comments</comments>
		<pubDate>Tue, 17 Feb 2009 02:00:00 +0000</pubDate>
		<dc:creator>Peng</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Flex Builder]]></category>
		<category><![CDATA[JSFL]]></category>

		<guid isPermaLink="false">http://hubflanger.com/?p=159</guid>
		<description><![CDATA[In Part 2 of this tutorial, we&#8217;ll compile an ActionScript 3 only project simply by launching the MXMLC compiler with an Ant task in Flex Builder.
1. Download tutorial files
To begin this tutorial, please make sure you have set up your workspace as suggested in Part 1.
View Demo
Download Source Files

2. Examine Demo2.as
Demo2.as is exactly the same [...]]]></description>
			<content:encoded><![CDATA[<p>In Part 2 of this tutorial, we&#8217;ll compile an ActionScript 3 only project simply by launching the MXMLC compiler with an Ant task in Flex Builder.</p>
<h3>1. Download tutorial files</h3>
<p>To begin this tutorial, please make sure you have set up your workspace as suggested in <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-1/#settingUpYourWorkspace">Part 1</a>.</p>
<p><a href="http://hubflanger.com/demos/ant_demo2/">View Demo</a></p>
<p><a href="http://github.com/hubflanger/AS3_Ant_Tutorial_2">Download Source Files</a></p>
<p><span id="more-159"></span></p>
<h3>2. Examine Demo2.as</h3>
<p><code>Demo2.as</code> is exactly the same as <code>Demo1.as</code> in <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-1/">Part 1</a> of this tutorial. Except this time around, we do not have an FLA linked to <code>Demo2</code> as its document class.</p>
<div class="codeblock">
<pre>
package
{
  import flash.display.Sprite;
  import flash.text.TextField;
  import flash.text.TextFormat;

  public class Demo2 extends Sprite
  {
    public function Demo2()
    {
      var format:TextFormat = new TextFormat();
      format.font = "Arial";
      format.size = 16;
      format.color = 0x000000;

      var label:TextField = new TextField();
      label.width = 500;
      label.defaultTextFormat = format;
      label.text = "Welcome to my ANT Demo!";
      label.x = 100;
      label.y = 150;
      addChild( label );
    }
  }
}
</pre>
</div>
<p><a name="compileMain"></a></p>
<h3>3. Examine build.xml</h3>
<p>The <code>compileMain</code> task here launches the MXMLC compiler with the <code>Demo2.as</code> file as its argument and outputs <code>demo2.swf</code>.</p>
<div class="codeblock">
<pre>
&lt;target name="compileMain"&gt;
  &lt;echo&gt;Compiles Demo2.as file and outputs demo2.swf&lt;/echo&gt;
  &lt;mxmlc file="${SRC_DIR}/Demo2.as" output="${DEPLOY_DIR}/demo2.swf"
    actionscript-file-encoding="UTF-8"
    incremental="false"
    debug="true"
    default-frame-rate="31"
    default-background-color="0xCCCCCC"&gt;

    &lt;load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/&gt;
    &lt;source-path path-element="${FLEX_HOME}/frameworks"/&gt;
    &lt;source-path path-element="${SRC_DIR}" /&gt;

    &lt;!-- Set size of output SWF file. --&gt;
    &lt;default-size width="550" height="400" /&gt;
  &lt;/mxmlc&gt;
&lt;/target&gt;
</pre>
</div>
<h3>Coming up</h3>
<p>This is a quick and painless one, isn&#8217;t it? In <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-3/">Part 3</a>, we&#8217;ll use a combination of the MXMLC compiler and JSFL script to compile an external SWF which will be loaded into your main SWF.</p>
]]></content:encoded>
			<wfw:commentRss>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-2/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Building Flash Projects with Ant and Flex Builder &#8211; Part 1</title>
		<link>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-1/</link>
		<comments>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-1/#comments</comments>
		<pubDate>Mon, 02 Feb 2009 03:00:46 +0000</pubDate>
		<dc:creator>Peng</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Ant]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Flex Builder]]></category>
		<category><![CDATA[JSFL]]></category>

		<guid isPermaLink="false">http://hubflanger.com/?p=116</guid>
		<description><![CDATA[As more Flash developers migrate towards using tools like Flex Builder and FDT for code editing, some of us have found that switching between the Flash IDE and Flex Builder doesn&#8217;t necessarily present the most seamless workflow. Compiling with the Flash IDE is slow and cumbersome; building an entire Flash project with code in Flex [...]]]></description>
			<content:encoded><![CDATA[<p>As more Flash developers migrate towards using tools like Flex Builder and FDT for code editing, some of us have found that switching between the Flash IDE and Flex Builder doesn&#8217;t necessarily present the most seamless workflow. Compiling with the Flash IDE is slow and cumbersome; building an entire Flash project with code in Flex Builder doesn&#8217;t integrate nicely the designer&#8217;s workflow either. Until Flash Catalyst becomes available and magically cures all our designer-developer workflow headaches, what we need is a way to leverage each tool for what it does best, ie. the Flash IDE for drawing and layout, and Flex Builder for code.</p>
<p>Apache Ant is a software tool for automating software build processes implemented using the Java language. Ant uses XML to describe the build process and its dependencies, so no knowledge of Java is necessary for  running Ant in your Flex Builder environment. By default the XML file is named build.xml.</p>
<p>In this series of tutorials, I will show you how to use Ant to create a workflow between the Flash IDE and Flex Builder. In Part 1 of this tutorial, we shall use Ant and JSFL to launch a FLA to publish a SWF.</p>
<p><span id="more-116"></span><br />
JSFL is a Javascript-based scripting language for scripting the Flash IDE, allowing you to do things such as publish a SWF, etc. just by launching a script from the command line. Documentation for JSFL can be found here: <a href="http://livedocs.adobe.com/flash/9.0/main/flash_cs3_extending.pdf">http://livedocs.adobe.com/flash/9.0/main/flash_cs3_extending.pdf</a>. </p>
<p>Combined with Ant, they provide a powerful toolset for the aspiring Flash/Actionscript developer. </p>
<p><a name="settingUpYourWorkspace"></a></p>
<h3>1. Setting up your workspace</h3>
<p>The standalone Flex Builder install is built on top of a stripped down version of Eclipse and does not come with built-in support for Ant. To get Ant support in the Flex Builder, follow the instructions in these tutorials:</p>
<p><a href="http://www.peterelst.com/blog/2006/09/03/flex-builder-2-ant-support/" target="_blank">http://www.peterelst.com/blog/2006/09/03/flex-builder-2-ant-support/</a></p>
<p><a href="http://blog.jodybrewster.net/2008/04/09/installing-ant-in-flex-builder-3/" target="_blank">http://blog.jodybrewster.net/2008/04/09/installing-ant-in-flex-builder-3/</a></p>
<p>If you&#8217;re using FDT or the Flex Builder plug-in for Eclipse, the standard Eclipse install comes with built-in support for Ant, so you&#8217;re good to go.</p>
<h3>2. Download tutorial files</h3>
<p>This tutorial assumes a working knowledge of Flex Builder. You should already know how to create an Actionscript project in Flex Builder. The directory structure is set up like a typical project in Flex Builder, with <code>bin-debug</code> as the output folder, <code>src</code> containing the Actionscript files and <code>fla</code> containing the FLAs. </p>
<p><a href="http://hubflanger.com/demos/ant_demo1/">View Demo</a></p>
<p><a href="http://github.com/hubflanger/AS3_Ant_Tutorial_1">Download Source Files</a></p>
<h3>3. Examine demo1.fla</h3>
<p><code>demo1.fla</code> is a simple FLA which points to Demo1.as as its document class. It is set up to publish a SWF named <code>demo1.swf</code> to the <code>bin-debug</code> folder.</p>
<p>The Demo1 class creates a textField containing &#8220;Welcome to my Ant Demo!&#8221; and adds it to the stage.</p>
<p><a name="compileSWF_JSFL"></a></p>
<h3>4. Examine compileSWF.jsfl</h3>
<p>The JSFL script for launching <code>demo1.fla</code> and publishing <code>demo1.swf</code> resides in the <code>jsfl</code> folder. It starts off by clearing the ASO cache and Flash IDE&#8217;s Output Panel. Then it saves the FLA and publishes the SWF.</p>
<div class="codeblock">
<pre>
function clearASOCache( path ) {
  if (!FLfile.exists( path )) {
    fl.trace( path + "does not exist" );
    return;
  }
  FLfile.remove( path );
}

clearASOCache ( fl.configURI + "Classes/aso" );
fl.outputPanel.clear();
fl.getDocumentDOM().save();
fl.getDocumentDOM().publish();
</pre>
</div>
<h3>5. Examine build.xml</h3>
<p>This Ant build file contains a couple of references to <code>demo1.fla</code> and <code>compileSWF.jsfl</code> named <code>demoFLA</code> and <code> compileSWF_jsfl</code> respectively. These properties provide shortcuts to commonly referenced resources in your project and allows you define them in a single convenient location.</p>
<p>The <code>target</code> named <code>compileMain</code> is the Ant task that calls the <code>compileSWF_jsfl</code> script, passing it the property <code>demoFLA</code>. The JSFL script then takes over by launching the FLA and compiling the SWF.</p>
<div class="codeblock">
<pre>
&lt;project name="Flex Ant Tasks Demo1" default="compileMain" basedir="."&gt;&gt;
  &lt;property name="demoFLA" value="fla/demo1.fla" /&gt;
  &lt;property name="compileSWF_jsfl" value="jsfl/compileSWF.jsfl" /&gt;

  &lt;!-- This task launches the compileSWF.jsfl script to compile demo1.swf using the Flash IDE --&gt;
  &lt;target name="compileMain" description="Compile the demo1 SWF with the Flash IDE"&gt;
    &lt;echo&gt;Flash IDE Compiler for file ${mainFLA}&lt;/echo&gt;
    &lt;echo message="|*|*|*| class cache clear | source save | compiler start |*|*|*|"/&gt;
    &lt;exec executable="open"&gt;
      &lt;arg line="${compileSWF_jsfl} ${demoFLA}"/&gt;
    &lt;/exec&gt;
  &lt;/target&gt;
&lt;/project&gt;
</pre>
</div>
<h3>6. Using the Outline Panel</h3>
<p>Launch the Outline Panel by selecting Window->Other Views->General->Outline from the top menu. In the Outline Panel, you&#8217;ll be able to browse the list of properties and targets defined in your build file. Clicking an item in the list will cause the the editor jump to the line where that particular item is defined, making it quick and easy to navigate and edit an Ant build file (<a href="http://hubflanger.com/wp-content/uploads/ant-tutorial-part1-fig1.jpg">fig. 1</a>).</p>
<h3>7. Using the Ant Panel</h3>
<p>Next, we launch the Ant Panel by selecting Window->Other Views->Ant->Ant in the top menu. To see the list of Ant tasks available within <code>build.xml</code>, just drag the file into the Ant Panel (<a href="http://hubflanger.com/wp-content/uploads/ant-tutorial-part1-fig2.jpg">fig. 2</a>). Now, whenever you need to execute an Ant task, just double-click the task or right-click on it and select Run As->Ant Build.</p>
<p>That&#8217;s it. As you can see, it&#8217;s quite easy to get started with Ant. Even better, Ant is a tool that grows with your project, becoming more powerful and complex as your project demands it. </p>
<p>Before we proceed to the next part of this tutorial, I would like to thank the kind folks at the New York City Flash User Group, <a href="http://flashcodersny.org/" target="_blank">FlashCodersNY</a>, for sharing their knowledge on Ant. This tutorial would not be possible without their generosity.</p>
<h3>Coming up</h3>
<p>In <a href="http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-2/">Part 2</a> of this tutorial, we shall use Flex Ant Tasks to compile a SWF with the MXMLC compiler.</p>
]]></content:encoded>
			<wfw:commentRss>http://hubflanger.com/building-flash-projects-with-ant-and-flex-builder-part-1/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>Stage RESIZE and the stageWidth and stageHeight Bug</title>
		<link>http://hubflanger.com/stage-resize-and-the-stagewidth-and-stageheight-properties/</link>
		<comments>http://hubflanger.com/stage-resize-and-the-stagewidth-and-stageheight-properties/#comments</comments>
		<pubDate>Mon, 22 Sep 2008 16:53:56 +0000</pubDate>
		<dc:creator>Peng</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Flash Player]]></category>
		<category><![CDATA[IE]]></category>
		<category><![CDATA[RESIZE]]></category>
		<category><![CDATA[Safari]]></category>
		<category><![CDATA[stage]]></category>
		<category><![CDATA[stageHeight]]></category>
		<category><![CDATA[stageWidth]]></category>

		<guid isPermaLink="false">http://hubflanger.com/using-the-stagewidth-and-stageheight-properties-2/</guid>
		<description><![CDATA[A while ago, I came across a situation where my Flash application would launch but the stage.stageWidth and stage.stageHeight properties would always return 0 within my document class&#8217;s constructor. As I needed to access those properties at runtime and I did not want to hardcode those values to a pair of variables, it drove me [...]]]></description>
			<content:encoded><![CDATA[<p>A while ago, I came across a situation where my Flash application would launch but the <code>stage.stageWidth</code> and <code>stage.stageHeight</code> properties would always return 0 within my document class&#8217;s constructor. As I needed to access those properties at runtime and I did not want to hardcode those values to a pair of variables, it drove me to seek an answer to this problem.</p>
<p>Turns out that when the <code>stage</code> is initialized, its <code>stageWidth</code> and <code>stageHeight</code> properties are 0 until a <code>Stage RESIZE</code> event is triggered. This event is dispatched when the <code>scaleMode</code> property of the <code>Stage</code> object is set to <code>StageScaleMode.NO_SCALE</code> and the SWF file is resized ie. when the stage is rendered by the Flash Player. So if you need to add a display object onto the <code>stage</code> and its positioning is dependent on the <code>stageWidth</code> or <code>stageHeight</code> properties at runtime, it&#8217;s best handled by a listener that is subscribed to the <code>Stage RESIZE</code> event.<span id="more-102"></span></p>
<p>Interestingly, despite universal claim that the Flash Player behaves exactly the same on all browsers, this problem only appears in a couple of browser/plugin configurations, namely FireFox/OSX and IE/Win. And strangely, on Safari and Firefox/Win, the <code>RESIZE</code> event is not even dispatched on page load, and neither does the Flash Player register the <code>stageWidth</code> and <code>stageHeight</code> properties as being 0. I have not tested the problem on other platforms but you are certainly welcome to do so yourselves and report your observations in the comments section. Eventually, it would be nice if we can get a straight answer from Adobe concerning this bug.</p>
<p>In the following demo code, I&#8217;ve attached a <code>Sprite</code> containing a <code>Rectangle</code> graphic and a <code>TextField</code>, to the <code>stage</code> once before the <code>RESIZE</code> event and once, after. You can see the results <a href="/demos/stage_resize/">here</a>.</p>
<div class="codeblock">
<pre>
package
{
  import flash.text.*;
  import flash.display.*;
  import flash.events.*;

  public class Demo extends Sprite
  {
    private var rect1:Sprite;
    private var rect2:Sprite;

    public function Demo()
    {
      rect1 = createNewRect("Before stage resize event.");
      rect1.x = 0;
      rect1.y = 0;
      addChild(rect1);

      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
      stage.addEventListener(Event.RESIZE, resizeHandler);
    }

    private function createNewRect(str:String):Sprite
    {
      var rect:Sprite = new Sprite();
      rect.graphics.beginFill(0x99CCFF);
      rect.graphics.drawRect(0, 0, 200, 100);
      rect.graphics.endFill();

      var fmt:TextFormat = new TextFormat();
      fmt.font = "Arial";
      fmt.size = 12;

      var tf:TextField = new TextField();
      tf.width = 200;
      tf.height = 100;
      tf.multiline = true;
      tf.defaultTextFormat = fmt;
      tf.text = str + "\n" + "stage.stageWidth: " + stage.stageWidth + "\n" +
            "stage.stageHeight: " + stage.stageHeight;

      rect.addChild(tf);
      return rect;
    }

    private function resizeHandler( event:Event ):void
    {
      if (rect2 != null &#038;&#038; contains(rect2)) {
        removeChild(rect2);
      }

      rect2 = createNewRect("After stage resize event.");
      rect2.x = (stage.stageWidth - rect2.width) / 2;
      rect2.y = (stage.stageHeight - rect2.height) / 2;
      addChild(rect2);
    }
  }
}
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://hubflanger.com/stage-resize-and-the-stagewidth-and-stageheight-properties/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Cross-Domain Scripting Voodoo</title>
		<link>http://hubflanger.com/cross-domain-scripting-voodoo/</link>
		<comments>http://hubflanger.com/cross-domain-scripting-voodoo/#comments</comments>
		<pubDate>Mon, 07 Jul 2008 03:19:44 +0000</pubDate>
		<dc:creator>Peng</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[cross-domain scripting]]></category>

		<guid isPermaLink="false">http://hubflanger.com/?p=39</guid>
		<description><![CDATA[If you&#8217;re thinking of hosting your SWFs on a content delivery network to improve the performance of your Flash application, or attempting to load a third-party SWF hosted on another domain into your  application, be aware that loading and scripting SWFs from another domain posts a whole set of security issues, namely that of [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re thinking of hosting your SWFs on a content delivery network to improve the performance of your Flash application, or attempting to load a third-party SWF hosted on another domain into your  application, be aware that loading and scripting SWFs from another domain posts a whole set of security issues, namely that of Cross-Domain Scripting. Due to the Flash Player 9&#8217;s security sandbox, when you load a SWF from another domain into a SWF hosted on your domain, by default, you will not be able to operate on the child SWF without it specifically granting permission.</p>
<p>Before proceeding with this tutorial, I highly recommend that you to read the <a href="http://www.adobe.com/devnet/flashplayer/articles/flash_player_9_security.pdf">Adobe Flash Player 9 Security White Paper</a>. This 51-page document, although thorough in many aspects, unfortunately left out crucial details that one would need in order to successfully perform cross-domain scripting. Another indispensable reference would be Colin Moock&#8217;s <a href="http://www.amazon.com/Essential-ActionScript-3-0/dp/0596526946/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1217209517&amp;sr=1-1" target="_blank"><em>Essential ActionScript 3.0</em></a>, in particular, Chapter 19 on <em>Flash Player Security Restrictions</em> and Chapter 28 on <em>Loading External Display Assets</em>.</p>
<p>Let&#8217;s get started!</p>
<p><span id="more-39"></span><br />
In this tutorial, we will load a SWF named <code>domainB.swf</code> from the domain <code>http://sub.hubflanger.com</code> into a SWF named <code>domainA.swf</code> located at <code>http://hubflanger.com</code>. In the Adobe Flash Player 9 security sandbox, a subdomain is treated like any domain separate from its parent domain, so cross-domain security policies apply. Here, we shall assume that <code>domainA.swf</code> does not have access to any of <code>domainB.swf</code>&#8217;s classes during compilation.</p>
<p><a href="http://hubflanger.com/demos/cross_domain_scripting/">View Demo</a></p>
<p><a href="http://github.com/hubflanger/CrossDomainScripting_Tutorial">Download Source Files</a></p>
<h3>1. Setting up your URL policy file</h3>
<p>The URL policy file named <code>crossdomain.xml</code> is located, by default, in the root directory of the target server (http://sub.hubflanger.com). This policy file gives the parent SWF permission to load the child SWF.</p>
<div class="codeblock">
<pre>&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;cross-domain-policy&gt;
  &lt;allow-access-from domain="*" /&gt;
&lt;/cross-domain-policy&gt;</pre>
</div>
<h3>2. Examining domainB.fla</h3>
<p>In <code>domainB.fla</code>, the document class is linked to the class <code>com.hubflanger.crossdomain.DomainB</code>. In the constructor of the <code>DomainB</code> class, the <code>Security.allowDomain("*");</code> statement enables scripting of this SWF from another domain (in this case, &#8220;*&#8221; denotes any domain). The class also has a public method named <code>sayHello()</code> which we will call from <code>domainA.swf</code> when <code>domainB.swf</code> is loaded.</p>
<div class="codeblock">
<pre>package com.hubflanger.crossdomain
{
  import flash.text.TextField;
  import flash.display.MovieClip;
  import flash.system.Security;

  public class DomainB extends MovieClip
  {
    public var myText1:TextField;

    public function DomainB()
    {
      Security.allowDomain("*");
    }

    public function sayHello( str:String ):void
    {
      myText1.text = str;
    }
  }
}</pre>
</div>
<p>On the stage, a dynamic textField named <code>myText1</code> will display a text string passed to the <code>sayHello()</code> method.</p>
<p>In the library panel, a symbol named <code>innerClip</code> is linked to the class <code>com.hubflanger.crossdomain.InnerClip</code>. The <code>InnerClip</code> class has a public method named <code>sayHello()</code> which we will call from <code>domainA.swf</code> as well.</p>
<div class="codeblock">
<pre>package com.hubflanger.crossdomain
{
  import flash.text.TextField;
  import flash.display.MovieClip;

  public class InnerClip extends MovieClip
  {
    public var myText2:TextField;

    public function InnerClip()
    {
      //
    }

    public function sayInnerHello( str:String ):void
    {
      myText2.text = str;
    }
  }
}</pre>
</div>
<p>The <code>innerClip</code> symbol also contains a dynamic textField <code>myText2</code> which will display a text string passed to the <code>sayInnerHello()</code> method.</p>
<h3>2. Examining domainA.fla</h3>
<p>The <code>domainA.fla</code> is linked to the document class <code>DomainA</code>. To import <code>domainB.swf</code>&#8217;s classes into <code>domainA.swf</code>&#8217;s application domain at runtime, we use a <code>LoaderContext</code> object when issuing the request to load <code>domainB.swf</code>. This makes <code>domainB.swf</code>&#8217;s classes directly accessible to <code>domainA.swf</code>.</p>
<p>In the <code>initHandler()</code> listener, we reference the <code>DomainB</code> class by calling the <code>getDefinition()</code> method of the <code>Loader</code>&#8217;s <code>applicationDomain</code> property by passing in the classpath <code>com.hubflanger.crossdomain.DomainB</code>. We can then gain access to <code>domainB.swf</code>&#8217;s <code>sayHello()</code> method by casting the <code>Loader</code>&#8217;s content to the <code>DomainB</code> type.</p>
<p>Similarly, we gain a reference to the <code>InnerClip</code> class and then create an <code>InnerClip</code> instance via this reference. We then call the <code>sayInnerHello()</code> method belonging to this instance.</p>
<div class="codeblock">
<pre>package
{
  import flash.display.*;
  import flash.net.*;
  import flash.events.*;
  import flash.system.*;

  public class DomainA extends MovieClip
  {
	private static const PACKAGE:String = "com.hubflanger.crossdomain.";

    public function DomainA()
    {
      var loader:Loader = new Loader();
      loader.contentLoaderInfo.addEventListener( Event.INIT, initHandler );
      loader.contentLoaderInfo.addEventListener( IOErrorEvent.IO_ERROR, ioErrorHandler );
      loader.contentLoaderInfo.addEventListener( SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler );
      addChild(loader);

      var loaderContext:LoaderContext = new LoaderContext( false, ApplicationDomain.currentDomain );
      loaderContext.applicationDomain =  ApplicationDomain.currentDomain;
      loader.load( new URLRequest( "http://sub.hubflanger.com/crossdomain/domainB.swf" ), loaderContext );
    }

    private function initHandler( evt:Event ):void
    {
      var packagePath:String = "com.hubflanger.crossdomain.";

      var appDomain:ApplicationDomain = evt.target.applicationDomain;

      var domainBRef:Class = appDomain.getDefinition( PACKAGE + "DomainB" )  as  Class;
      var domainB:Object = domainBRef( evt.target.content );
      domainB.sayHello( "Hello World!" );

      var innerClipRef:Class = appDomain.getDefinition( PACKAGE + "InnerClip" )  as  Class;
      var innerClip:Object = new innerClipRef();
      innerClip.sayInnerHello( "Inner clip says Hello!" );
      addChild( innerClip as MovieClip );
    }

    private function ioErrorHandler( e:IOErrorEvent ):void
    {
      trace( e.text );
    }

    private function securityErrorHandler( e:SecurityErrorEvent ):void
    {
      trace( e.text );
    }
  }
}</pre>
</div>
<p>That&#8217;s it. I hope this tutorial helped to clarify the confusion surrounding the daunting task of Cross-Domain Scripting. Happy coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://hubflanger.com/cross-domain-scripting-voodoo/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Building a Flash site using PureMVC</title>
		<link>http://hubflanger.com/building-a-flash-site-using-puremvc/</link>
		<comments>http://hubflanger.com/building-a-flash-site-using-puremvc/#comments</comments>
		<pubDate>Mon, 14 Apr 2008 03:55:44 +0000</pubDate>
		<dc:creator>Peng</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[PureMVC]]></category>
		<category><![CDATA[Tutorials]]></category>

		<guid isPermaLink="false">http://hubflanger.com/?p=37</guid>
		<description><![CDATA[At a recent FlashCodersNY meeting where the discussion centered around the subject of the MVC (Model-View-Controller) design pattern, it struck me that a lot of Flash developers, especially those coming from design backgrounds, did not see the value in using the MVC design pattern.
Well, I&#8217;m not here to make the case for using MVC but [...]]]></description>
			<content:encoded><![CDATA[<p>At a recent <a href="http://flashcodersny.org" target="_blank">FlashCodersNY</a> meeting where the discussion centered around the subject of the MVC (Model-View-Controller) design pattern, it struck me that a lot of Flash developers, especially those coming from design backgrounds, did not see the value in using the MVC design pattern.</p>
<p>Well, I&#8217;m not here to make the case for using MVC but if you have spent enough time struggling with structuring an application so that it&#8217;s clearly represented by a set of well-defined relationships and responsibilities, you would&#8217;ve likely tried to implement some kind of MVC pattern. Now, some design pattern is certainly better none. Trouble is, every developer has his or her own approach to MVC. When a team of developers are working on the same project, things can get confusing pretty quickly if there are no common standards to adhere to.</p>
<p><span id="more-37"></span><br />
This brings us to the <a href="http://puremvc.org" target="_blank">PureMVC</a> framework. Created by Cliff Hall, this framework provides a set of well-defined protocols for implementing the MVC design pattern with your application, rendering the grunt work of manually hooking up an MCV structure a thing of the past. However, great as <a href="http://puremvc.org" target="_blank">PureMVC</a> may be, it does not present an easy learning curve for some, especially those who are just getting started with OOP and design patterns.</p>
<p>In this tutorial, I will show you how to build a Flash site using PureMVC. If you&#8217;re familiar with the Flash IDE and have some experience with OOP and writing classes, you&#8217;re pretty much ready to go. </p>
<p><a href="/demos/puremvc_flashsite/">View Demo</a></p>
<p><a href="http://github.com/hubflanger/PureMVC_Flash_Site">Download Source Files</a></p>
<h3>1. Creating the Flash assets</h3>
<p>Open <code>fla/PureMVCSite.fla</code> in the Flash IDE. In the Library Panel, you&#8217;ll see that I have created various assets for our Flash site: </p>
<ul>
<li>A <code>site</code> movieclip that serves as a container clip with the UI elements laid out in the desired fashion</li>
<li>A <code>header</code> movieclip containing a dynamic textfield for the site header</li>
<li>A <code>nav</code> movieclip containing 3 <code>navButton</code> instances
</li>
<li>A <code>body</code> movieclip containing a dynamic multiline textfield for the body content</li>
</ul>
<p>The <code>site</code> movieclip symbol is linked to the class <code>Site</code>. The <code>nav</code> movieclip symbol is linked to the class <code>MainNav</code>. Both these classes belong to the package <code>com.hubflanger.puremvc.view.component</code>. In the PureMVC world, these are known as &#8220;view components&#8221;, not to be confused with the built-in Flash components. These components communicate with the PureMVC framework via their associated <em>Mediators</em>, allowing them to be &#8220;loosely-coupled&#8221;, thereby granting you great flexibility in changing their behavior without impacting the rest of your application.</p>
<p>In the <strong>ActionScript 3.0 Setting</strong> of the <strong>Publish Settings</strong>, you&#8217;ll see that <strong>Classpath</strong> has been set to point to &#8220;<code>../src</code>&#8220;. This tells the Flash compiler that the <code>as</code> folder is where you&#8217;ll look for the class files for this application.</p>
<h3>2. Examining the PureMVC package</h3>
<p>The PureMVC package <code>org.puremvc.as3</code> (version 2.0.3) is located at <code>src/org/puremvc/as3</code> and has been included for your convenience. The AS3 port of the PureMVC framework is hosted <a href="http://puremvc.org/component/option,com_wrapper/Itemid,160/" target="_blank">here</a>. I strongly encourage you to spend some time reading the online <a href="http://puremvc.org/component/option,com_wrapper/Itemid,35/" target="_blank">documentation</a> if possible.</p>
<p>At any time during this tutorial, if you feel the need for a clearer understanding of PureMVC terminologies such as <em>Mediator</em>, <em>Proxy</em> or <em>Notification</em>, please feel free to refer to these classes. Cliff Hall has done an excellent job of commenting them and the comments will provide a clear picture of each class&#8217; role in the framework.</p>
<h3>3. Examining PureMVCSite.as and ApplicationFacade.as</h3>
<p>The main timeline of <code>PureMVCSite.fla</code> is linked to the document class <code>PureMVCSite</code> which is initialized when the application starts. <code>PureMVCSite.as</code> resides at the root of the <code>as</code> folder. When the application launches, <code>PureMVCSite</code> creates a Singleton instance of <code>ApplicationFacade</code>. The <code>ApplicationFacade</code> is the entry point to the PureMVC framework. When you instantiate <code>ApplicationFacade</code>, a whole slew of events take place behind the scenes to wire up your application with the PureMVC framework.</p>
<div class="codeblock">
<pre>
package
{
  import com.hubflanger.puremvcsite.ApplicationFacade;
  import flash.display.Sprite;

  public class PureMVCSite extends Sprite
  {
    private var facade:ApplicationFacade;

    public function PureMVCSite()
    {
      facade = ApplicationFacade.getInstance();
      facade.startup( this.stage );
    }
  }
}
</pre>
</div>
<p>Let&#8217;s first examine the static constants defined at the beginning of this class. <code>STARTUP</code><code>, </code><code>INITIALIZE_SITE</code> and <code>SECTION_CHANGED</code> represent the <em>Notification</em> names of the events that our application will be responding to. A <em>Notification</em> is the default messaging deployed by PureMVC to inform the framework of an event that has been dispatched. In PureMVC land, sending a <em>Notification</em> is synonymous with broadcasting an event. Only difference is, it does a little more than just broadcasting it to everyone, whether they want to hear it or not. PureMVC finds the select audience who are &#8220;ticket holders&#8221; to an event, and drives them to the venue. I will explain this in greater detail later.</p>
<div class="codeblock">
<pre>
package com.hubflanger.puremvcsite
{
  import org.puremvc.as3.interfaces.IFacade;
  import org.puremvc.as3.patterns.facade.Facade;
  import com.hubflanger.puremvcsite.controller.StartupCommand;

  public class ApplicationFacade extends Facade implements IFacade
  {
    public static const STARTUP:String      = "startup";
    public static const INITIALIZE_SITE:String  = "initializeSite";
    public static const SECTION_CHANGED:String  = "sectionChanged";

    public static function getInstance() : ApplicationFacade
    {
      if ( instance == null ) instance = new ApplicationFacade();
      return instance as ApplicationFacade;
    }

    override protected function initializeController() : void
    {
      super.initializeController();
      registerCommand( STARTUP, StartupCommand );
    }

    public function startup( stage:Object ):void
    {
      sendNotification( STARTUP, stage );
    }
  }
}
</pre>
</div>
<p><code>ApplicationFacade</code> overrides <code>initializeController()</code> to register <code>StartupCommand</code> with the <code>STARTUP</code> <em>Notification</em>. Behind the scenes, the <em>Controller</em> adds <code>StartupCommand</code> to its <code>commandMap</code> array and notes that <code>StartupCommand</code> is interested in listening for the <code>STARTUP</code> notification event.</p>
<p>The <code>startup()</code> method in <code>ApplicationFacade</code> is then explicitly called by <code>PureMVCSite</code>, passing in a reference to the <code>Stage</code>. This creates a <em>Notification</em> object with the name &#8220;startUp&#8221; and a reference to the <code>Stage</code> assigned to the its <code>body</code> property.</p>
<h3>4. Examining StartupCommand.as</h3>
<p>Upon receiving the <em>Notification</em>, the <em>Controller</em> iterates through its <code>commandMap</code> and retrieves <code>StartupCommand</code> as an object that is interested in the <code>STARTUP</code> notification. This results in the <code>execute()</code> method in <code>StartupCommand</code> being called.</p>
<div class="codeblock">
<pre>
package com.hubflanger.puremvcsite.controller
{
  import flash.display.Stage;
  import org.puremvc.as3.interfaces.ICommand;
  import org.puremvc.as3.interfaces.INotification;
  import org.puremvc.as3.patterns.command.SimpleCommand;
  import com.hubflanger.puremvcsite.ApplicationFacade;
  import com.hubflanger.puremvcsite.view.StageMediator;
  import com.hubflanger.puremvcsite.model.SiteDataProxy;

  public class StartupCommand extends SimpleCommand implements ICommand
  {
    override public function execute( note:INotification ) : void
    {
      var stage:Stage = note.getBody() as Stage;
      facade.registerMediator( new StageMediator( stage ) );
      facade.registerProxy( new SiteDataProxy() );
    }
  }
}
</pre>
</div>
<p>The <code>execute()</code> method in <code>StartupCommand</code> retrieves the reference to the <code>Stage</code> from the <em>Notification</em> and passes that along to an instance of the <code>StageMediator</code> being created. It also creates an instance of <code>SiteDataProxy</code>. </p>
<p><code>facade</code> is a built-in property of the <em>Mediator</em> and <em>Proxy</em> base classes from which <code>StageMediator</code> and <code>SiteDataProxy</code> extends respectively. It refers to the <code>ApplicationFacade</code> instance which extends the <em>Facade</em> base class. </p>
<p><code>facade.registerMediator()</code> registers the newly created <em>Mediator</em> instance with the <em>View</em> which stores it in its <code>mediatorMap</code>. The <em>Mediator</em> instance can be retrieved during runtime via a simple reference of its static <code>NAME</code> property using <code>facade.retrieveMediator()</code>.</p>
<p>Similarly, <code>facade.registerProxy()</code> registers the newly created <em>Proxy</em> instance with the <em>Model</em> which stores it in its <code>proxyMap</code>. The <em>Proxy</em> instance can also be retrieved by passing its <code>NAME</code> property to the <code>facade.retrieveProxy()</code> method.</p>
<p>At this point, you&#8217;ll probably start to notice a pattern here. The <em>Model</em>, <em>View</em> and <em>Controller</em> all have methods and properties that mirror each other, tying the <em>Proxy</em> to the <em>Model</em>, the <em>Mediator</em> to the <em>View</em> and the <em>Command</em> to the <em>Controller</em>. You&#8217;ll also notice that the <em>Facade</em> indeed provides a &#8220;shortcut&#8221; to accessing various parts of your application within the PureMVC framework. Nobody talks to the <em>Model</em>, <em>View</em> or <em>Controller</em> directly. Everybody goes through the middle man named <em>Facade</em>.</p>
<h3>5. Examining StageMediator.as</h3>
<p>The <code>StageMediator</code> facilitates the communication between the <code>Stage</code> and the PureMVC framework. The <code>Stage</code> instance is referenced via the <code>viewComponent</code> property inherited from the <em>Mediator</em> base class. In PureMVC convention, it is also commonplace to create an accessor method such as &#8220;<code>get stage()</code>&#8220;. Two very important methods of the <em>Mediator</em> instance are the <code>listNotificationInterests()</code> method and the <code>handleNotification()</code> method, which every <em>Mediator</em> subclass must override. </p>
<p><code>listNotificationInterests()</code> returns an array of <em>Notification</em> names as defined in <code>ApplicationFacade</code>, representing events that this particular <em>Mediator</em> is interested in. When the <em>View</em> runs through its list of <em>Observers</em>, it checks each <em>Mediator</em> against its <em>Notification</em> interests. If there is a match pertaining to a specific <em>Notification</em>, the <code>handleNotification()</code> method of that <em>Mediator</em> is called. This is what I was referring to earlier by the select audience who are &#8220;ticket holders&#8221; to an event. In this case, our <code>StageMediator</code> is interested in the <code>INITIALIZE_SITE</code> <em>Notification</em>.</p>
<p>The <em>Mediator</em> base class extends <em>Notifier</em> which means that in addition to responding to <em>Notification</em>s, it is also capable of sending out <em>Notification</em>s via the <code>sendNotification()</code> method. In other words, it can dispatch events. Although, unlike a MovieClip, it can&#8217;t dispatch any Flash Events, instead, it dispatches <em>Notification</em> objects.</p>
<div class="codeblock">
<pre>
package com.hubflanger.puremvcsite.view
{
  import com.hubflanger.puremvcsite.ApplicationFacade;
  import com.hubflanger.puremvcsite.view.component.Site;
  import flash.display.Stage;
  import flash.events.MouseEvent;
  import org.puremvc.as3.interfaces.*;
  import org.puremvc.as3.patterns.mediator.Mediator;

  public class StageMediator extends Mediator implements IMediator
  {
    public static const NAME:String = "StageMediator";

    public function StageMediator( viewComponent:Object )
    {
      super( NAME, viewComponent );
    }

    override public function listNotificationInterests():Array
    {
      return [
          ApplicationFacade.INITIALIZE_SITE
          ];
    }

    override public function handleNotification( note:INotification ):void
    {
      switch ( note.getName() )
      {
        case ApplicationFacade.INITIALIZE_SITE:
          initializeSite();
          break;
      }
    }

    private function initializeSite():void
    {
      var site:Site = new Site();
      facade.registerMediator( new SiteMediator( site ) );
      facade.registerMediator( new NavMediator( site.nav ) );
      stage.addChild( site );

      var navMediator:NavMediator = facade.retrieveMediator( NavMediator.NAME ) as NavMediator;
      sendNotification( ApplicationFacade.SECTION_CHANGED, navMediator.currentSection );
    }

    protected function get stage():Stage
    {
    return viewComponent as Stage;
    }
  }
}
</pre>
</div>
<h3>6. Examining SiteDataProxy.as</h3>
<p><code>SiteDataProxy</code> represents the data model for the application. It loads in dynamic data via xml and then parses and stores that information in a built-in property named &#8220;<code>data</code>&#8220;. Like the <em>Mediator</em>, the <em>Proxy</em> object also extends <em>Notifier</em> which makes it capable of sending out <em>Notification</em>s via the <code>sendNotification()</code> method. Unlike the <em>Mediator</em>, the <em>Proxy</em> does not have <em>Notification</em> interests and one can and should only update the <em>Proxy</em> via a <em>Command</em>.</p>
<div class="codeblock">
<pre>
package com.hubflanger.puremvcsite.model
{
  import com.hubflanger.puremvcsite.ApplicationFacade;
  import flash.events.Event;
  import flash.net.URLLoader;
  import flash.net.URLRequest;
  import org.puremvc.as3.interfaces.IProxy;
  import org.puremvc.as3.patterns.proxy.Proxy;

  public class SiteDataProxy extends Proxy implements IProxy
  {
    public static const NAME:String = "SiteDataProxy";
    public var navIDs:Array;

    public function SiteDataProxy( )
    {
      super( NAME, new Object() );

      var loader:URLLoader = new URLLoader();
      loader.addEventListener( Event.COMPLETE, onDataLoaded );

      try {
        loader.load( new URLRequest( "data.xml" ));
      } catch ( error:Error ) {
        trace( "Unable to load requested document." );
      }
    }

    private function onDataLoaded( evt:Event ):void
    {
      var xml:XML = new XML( evt.target.data );
      xml.ignoreWhitespace = true;

      data.header = xml.header.children().toXMLString();

      var sections:XMLList = xml.sections.section;
      navIDs = new Array();

      for ( var i:uint=0; i&lt;sections.length(); i++ )
      {
        var section:XML = sections[ i ];
        var id:String = section.@id;
        navIDs[ i ] = id;

        var vo:SectionVO = new SectionVO( id,
                          section.@label,
                          section.content );
        data[ id ] = vo;
      }

      sendNotification( ApplicationFacade.INITIALIZE_SITE );
    }
  }
}
</pre>
</div>
<p>When <code>SiteDataProxy</code> is done parsing the xml data, it sends out a <code>INITIALIZE_SITE</code> <em>Notification</em>, resulting in the <code>handleNotification()</code> method of <code>StageMediator</code> being called. This in turn calls the <code>initializeSite()</code> method which initializes the <code>SiteMediator</code> and <code>NavMediator</code> instances. These two <em>Mediators</em> serve to facilitate communication between the <code>Site</code> movieclip and the <code>MainNav</code> movieclip with the framework.</p>
<h3>7. Examining SiteMediator.as</h3>
<p><code>SiteMediator</code> retrieves data from <code>SiteDataProxy</code> and calls <code>site.init()</code> to initialize the header text. It also declares an interest in the <code>SECTION_CHANGED</code> <em>Notification</em> event and calls <code>site.updateBody()</code> to update its content when such an event is dispatched.</p>
<div class="codeblock">
<pre>
package com.hubflanger.puremvcsite.view
{
  import com.hubflanger.puremvcsite.ApplicationFacade;
  import com.hubflanger.puremvcsite.model.*;
  import com.hubflanger.puremvcsite.view.component.Site;
  import org.puremvc.as3.interfaces.*;
  import org.puremvc.as3.patterns.mediator.Mediator;

  public class SiteMediator extends Mediator implements IMediator
  {
    public static const NAME:String = "SiteMediator";
    private var _siteDataProxy:SiteDataProxy;

    public function SiteMediator( viewComponent:Object )
    {
      super( NAME, viewComponent );

      _siteDataProxy = facade.retrieveProxy( SiteDataProxy.NAME ) as SiteDataProxy;
      var data:Object = _siteDataProxy.getData();
      site.init( data.header );
    }

    override public function listNotificationInterests():Array
    {
      return [
          ApplicationFacade.SECTION_CHANGED
          ];
    }

    override public function handleNotification( note:INotification ):void
    {
      switch ( note.getName() ) {
        case ApplicationFacade.SECTION_CHANGED:
          update( note.getBody() as String );
          break;
      }
    }

    private function update( s:String ):void
    {
      var data:Object = _siteDataProxy.getData();
      var vo:SectionVO = data[ s ];
      var content:XMLList = vo.content;

      site.updateBody( content.toXMLString() );
    }

    protected function get site():Site
    {
      return viewComponent as Site;
    }
  }
}
</pre>
</div>
<h3>8. Examining NavMediator.as and MainNav.as</h3>
<p><code>NavMediator</code> retrieves navigation id and label info from <code>SiteDataProxy</code> and passes that along to the <code>MainNav</code> instance, allowing <code>MainNav</code> to initialize its <code>navButton</code> instances. <code>MainNav</code> registers itself as an event listener of <code>MOUSE_DOWN</code> events triggered by the <code>navButton</code> instances. </p>
<p><code>NavMediator</code> in turn registers itself as an event listener of the <code>NAV_BUTTON_PRESSED</code> UIEvent bubbled up by the <code>MainNav</code> instance. Upon receiving such an event, <code>NavMediator</code> checks it against its <code>currentSection</code> variable to determine if a <code>SECTION_CHANGED</code> <em>Notification</em> should be sent.</p>
<p>When the <code>SECTION_CHANGED</code> <em>Notification</em> is sent, <code>SiteMediator</code> will respond and update the content in the <code>body</code> movieclip, and <code>NavMediator</code> will update its <code>navButton</code> instances to display the correct state depending on each button&#8217;s id.</p>
<div class="codeblock">
<pre>
package com.hubflanger.puremvcsite.view
{
  import com.hubflanger.puremvcsite.ApplicationFacade;
  import com.hubflanger.puremvcsite.model.*;
  import com.hubflanger.puremvcsite.view.component.MainNav;
  import com.hubflanger.puremvcsite.view.event.UIEvent;
  import org.puremvc.as3.interfaces.*;
  import org.puremvc.as3.patterns.mediator.Mediator;

  public class NavMediator extends Mediator implements IMediator
  {
    public static const NAME:String = "NavMediator";
    private var _siteDataProxy:SiteDataProxy;
    public var currentSection:String;

    public function NavMediator( viewComponent:Object )
    {
      super( NAME, viewComponent );

      _siteDataProxy = facade.retrieveProxy( SiteDataProxy.NAME ) as SiteDataProxy;
      nav.addEventListener( UIEvent.NAV_BUTTON_PRESSED, onNavButtonPressed );

      var data:Object = _siteDataProxy.getData();
      var navIDs:Array = _siteDataProxy.navIDs;
      var navLabels:Array = new Array();

      currentSection = navIDs[ 0 ];

      for ( var i:uint=0; i&lt;navIDs.length; i++ )
      {
        var id:String = navIDs[ i ];
        var vo:SectionVO = data[ id ];
        navLabels[ id ] = vo.label;
      } 

      nav.init( navIDs, navLabels );
    }

    override public function listNotificationInterests():Array
    {
      return [
          ApplicationFacade.SECTION_CHANGED
          ];
    }

    override public function handleNotification( note:INotification ):void
    {
      switch ( note.getName() ) {

        case ApplicationFacade.SECTION_CHANGED:
          nav.update( note.getBody() as String );
          break;
      }
    }

    private function onNavButtonPressed( evt:UIEvent ):void
    {
      if ( evt.id != currentSection ) {
        currentSection = evt.id;
        sendNotification( ApplicationFacade.SECTION_CHANGED, evt.id );
      }
    }

    protected function get nav():MainNav
    {
      return viewComponent as MainNav;
    }
  }
}
</pre>
</div>
<p></p>
<div class="codeblock">
<pre>
package com.hubflanger.puremvcsite.view.component
{
  import com.hubflanger.puremvcsite.view.event.UIEvent;
  import flash.display.MovieClip;
  import flash.events.*;

  public class MainNav extends MovieClip
  {
    public var btn0:MovieClip;
    public var btn1:MovieClip;
    public var btn2:MovieClip;
    private var navButtons:Array;

    public function MainNav()
    {
      navButtons = [ btn0, btn1, btn2 ];
    }

    public function init( navIDs:Array, labels:Array ):void
    {
      for ( var i:uint=0; i&lt;navIDs.length; i++ )
      {
        var id:String = navIDs[ i ];
        var btn:MovieClip = navButtons[ i ];
        btn.id = id;
        btn.txt.text = labels[ id ];
        btn.buttonMode = true;
        btn.mouseChildren = false;
        btn.addEventListener( MouseEvent.MOUSE_DOWN, onMouseDownHandler );
      }
    }

    public function update( s:String ):void
    {
      for ( var i:uint=0; i&lt;navButtons.length; i++ )
      {
        var btn:MovieClip = navButtons[ i ];

        if ( btn.id == s ) {
          btn.txt.textColor = 0x4B1E18;
        } else {
          btn.txt.textColor = 0xFFFFFF;
        }
      }
    }

    private function onMouseDownHandler( evt:Event ):void
    {
      dispatchEvent( new UIEvent( UIEvent.NAV_BUTTON_PRESSED, evt.target.id ));
    }
  }
}
</pre>
</div>
<h3>9. In Closing</h3>
<p>This is pretty much the gist of what happens within a PureMVC Flash application. It is my hope that this real-world example will help you get a jump start on using the PureMVC framework for your Flash projects. I also hope this tutorial managed to demonstrate the value and power of the MVC design pattern. As you start developing applications of greater complexity, using a framework such as PureMVC will help immensely in keeping your classes loosely-coupled, and easier to scale and maintain. Happy coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://hubflanger.com/building-a-flash-site-using-puremvc/feed/</wfw:commentRss>
		<slash:comments>54</slash:comments>
		</item>
	</channel>
</rss>
