Fork me on GitHub

Archive for the ‘Documentation’ Category

Deep linking with SWFAddress 2.5

The BirdBase Demo Site has been updated to use the latest – development version – of SWFAddress.

If you see errors like this:

[Fault] exception, information=ArgumentError: Error #1063: Argument count mismatch on com.asual.swfaddress::SWFAddress$/_setValue(). Expected 2, got 1.
at Function/http://adobe.com/AS3/2006/builtin::apply()
at flash.external::ExternalInterface$/_callIn()
at Function/()

Then update your SWFAddress Actionscript and Javascript from either the Demo Site on Github or the Asual repository here.

The BirdBase Demo Site has been updated to use the latest BirdBase lib, 0.8.2, and we will push the changes into the BirdBase repo shortly.

Tips: Updating Strings Dynamically

Loading the strings initially

A commenter just asked, ‘Docs say “The TextService supports runtime dynamic reloading of strings, so if these are reloaded, in say, a different language, all your IHaveUpdateableText instances will be reformatted and updated immediately.”
How do I reload strings dynamically?’

Good question. Let’s start by seeing how the strings are loaded in the first place.

The strings are kept – initially – in the configuration.yml file. It’s convenient and straightforward, and the section looks something like this:

strings:
    home_title:     "Home Section"
    media_title:    "Media Section"
    news_title:     "News Section"

The configuration is loaded into the ConfigurationService by the D_Services command in org.birdbase.framework.controller.core.

Once the configuration is loaded successfully, we parse the YML into a dictionary and deliver it to various objects:

(ConfigurationService)

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
private function handleComplete( e:Event ) : void
{
	try
	{
		var d:Dictionary = YAML.decode( e.target.data ) as Dictionary;
 
		setConfiguration( d )
		setStrings( d );
		setPreferences( d );
		setNavigation( d );
 
		eventDispatcher.dispatchEvent( new StateEvent( StateEvent.ACTION, BootManagement.CONFIGURING_SERVICES_COMPLETE ) );
	}
	catch( e:Error )
	{
		fatal( e.message );
		eventDispatcher.dispatchEvent( new StateEvent( StateEvent.ACTION, BootManagement.CONFIGURING_SERVICES_FAILED ) );
	}
}

Line 104 above calls the setStrings function which basically sends the strings chunk of the parsed YML to the TextService:

78
textService.strings = d.strings;

The TextService then updates any updateable components that are registered. And that’s it.

So, the way to update the strings dynamically is to simply set them on the TextService instance. But how do we load a new file in?

Loading a new YML file of strings

The new YML should look exactly like the strings section in the configuration.yml, although the values will be different:

strings:
    home_title:     "Accueil"
    media_title:    "Medias"
    news_title:     "Nouvelles"

So we ought to have an URLLoader to load this for us.

[Inject]
public var textService:ITextService;
 
var loader:URLLoader = new URLLoader();
loader.addEventListener( Event.COMPLETE, handleComplete );
loader.load( new URLRequest( "<path/to/my/new/strings/file.yml>" ) );
 
function handleComplete( e:Event ):void
{
	var d:Dictionary = YAML.decode( e.target.data ) as Dictionary;
	textService.strings = d.strings;
}

And the TextService will update all your registered components.

Understanding BirdBase. #2: Navigator

Deep-linking in BirdBase is provided by integrating the navigator-as3 library, written by Eric-Paul Lecluse.

The navigator gives us a number of useful things:

  1. Ability to link one or more URL strings to an application view.
  2. A complete transition management to deal with moving from state to state.
  3. A way to change the state of the current view.

Firstly, we may wish to map the URL “/news” to the NewsView. Easy. But suppose we want to map “/news/1″ and “/news/2″ to the NewsView as well? In our configuration, we can simply pass in an array: [ "/news", "/news/*" ] which covers all of those URLs.

Secondly, how does the transition management prove useful? Well, simply switching between views is possible, but may not be desirable, or there may be processing required during the switch, say some animation occurs. Well, navigator-as3 has a few interfaces that may be implemented.

com.epologee.navigator.behaviors.IHasStateTransition describes two methods, transitionIn and transitionOut. These are probably best implemented on the Mediator and are called by the Navigator when it wants to show or hide the view. There is one argument to both of these methods, a callback function. Your transition code lives in these methods and then the callback is fired to let the Navigator know that it may carry on.

Example of transitionOut method:

override public function transitionOut( callOnComplete:Function ):void
{
	// put your code here
 
	// fade view out
 
	// cleanup
 
	// fire callback
 
	callOnComplete.call();
}

There is further information on the navigator-as3 here. It’s worth noting that Eric-Paul’s RobotLegs integration is in progress right now, and BirdBase DOES NOT use it anyway as per EP’s instructions. As BirdBase allows us to do view mapping directly in the configuration, BirdBase simply instantiates the elements of the navigator directly and maps Views and Mediators directly into the navigator.

Understanding BirdBase. #1: Bootstrap

Compiling a Main.as class and running a flash application is pretty easy if all you want to do is draw a square on screen and print “Hello, World!” into a TextField. Applications sometimes need to do a whole bunch of things before the user gets control. Examples:

  • loading fonts
  • loading images
  • setting some default preferences
  • loading some text

BirdBase handles these things during its Bootstrap process, and the class that runs all this is BootManagement in the org.birdbase.framework.controller.boot package. The Bootstrap runs a series of commands, one after the other, and waits for each one to complete successfully before moving onto the next one. This is run by code known as a Finite State Machine, or FSM. The FSM has its roots in the PureMVC framework, and was ported over to RobotLegs by Joel Hooks.

The command steps are found in the org.birdbase.framework.controller.core package, and labelled alphabetically from A to E, in the order that the Bootstrap runs them.

  1. Preferences: initializes the application preferences model
  2. Navigator: creates and sets up the navigator library
  3. Models: prepares application models for use – assets, configuration, navigation, and text
  4. Services: starts the configuration service and loads the configuration from the filesystem
  5. Assets: loads boot-time assets

The BootManagement class configures the FSM, and we will now break down the code to explain how each section works.

public static const FSM:XML = 
    <fsm initial={STARTING}>
        <!-- THE INITIAL STATE -->
        <state name={STARTING}>
            <transition action={STARTED} target={CONFIGURING_PREFERENCES} />
            <transition action={START_FAILED} target={FAILING} />
        </state>
 
        <state name={CONFIGURING_PREFERENCES} changed={CONFIGURE_PREFERENCES}>
            <transition action={CONFIGURING_PREFERENCES_COMPLETE} target={CONFIGURING_NAVIGATOR} />
            <transition action={CONFIGURING_PREFERENCES_FAILED} target={FAILING} />
        </state>

SNIP…

        <state name={LOADING_ASSETS} changed={LOAD_ASSETS}>
            <transition action={LOAD_ASSETS_COMPLETE} target={STARTING_APPLICATION} />
            <transition action={LOAD_ASSETS_FAILED} target={FAILING} />
        </state>
 
        <state name={STARTING_APPLICATION} changed={START_APPLICATION}>
            <transition action={START_APPLICATION_COMPLETE} target={READY} />
            <transition action={START_APPLICATION_FAILED} target={FAILING} />
        </state>
        <!-- READY TO ACCEPT BROWSER OR USER NAVIGATION -->
        <state name={READY} changed={GO} />
        <!-- REPORT FAILURE FROM ANY STATE -->
        <state name={FAILING} changed={FAIL} />
    </fsm>;

SNIP…

    commandMap.mapEvent( BootManagement.LOAD_ASSETS,            E_Assets, StateEvent, true );
 
    commandMap.mapEvent( BootManagement.GO,                     ApplicationReady, StateEvent, true );
    commandMap.mapEvent( BootManagement.FAIL,                   ApplicationFault, StateEvent, true );
 
    eventDispatcher.dispatchEvent( new StateEvent( StateEvent.ACTION, BootManagement.STARTED ) );
}
  • Each state node above describes a command step, and within the step we are most interested in the transition nodes.
  • Each state will map to a command. Your command will at least succeed or fail, and for each of those outcomes, we define a transition.
  • Once the application state is STARTED on line 30, the target is CONFIGURING_PREFERENCES. Move to the CONFIGURING_PREFERENCES state. You can see on line 120 that we are mapping the “changed” attribute CONFIGURE_PREFERENCES to the command A_Preferences in org.birdbase.framework.controller.core.
  • How do we know CONFIGURING_PREFERENCES is complete? Or has failed? The onComplete method in A_Preferences:
private function onComplete():void
{
	eventDispatcher.dispatchEvent( new StateEvent( StateEvent.ACTION, BootManagement.CONFIGURING_PREFERENCES_COMPLETE ) );
}
  • This declares that BootManagement.CONFIGURING_PREFERENCES_COMPLETE. And BootManagement moves onto the next step, which is CONFIGURING_NAVIGATOR and not displayed in the snippet above. But eventually, assuming successful completion of each step, we end up at your context:
commandMap.mapEvent( BootManagement.START_APPLICATION, StartApplication, StateEvent, true );
  • And that fires your StartApplication command. And we call the ApplicationReady command in BirdBase to startup the navigator and hand over control to the user.

Creating an embedded font library

An Embedded Font Library

Build a SWF containing all the fonts you need, load it at boot time with all the other assets, and you’re off.

MXMLC on the command line will quickly compile a font library for you, and here is a script.

package 
{
    import flash.display.MovieClip;
    import flash.text.*;
 
    public class FontLibrary extends MovieClip
    {
        [Embed(source="resources/Chunkfive.otf", fontName='chunk', mimeType='application/x-font', embedAsCFF='false')]
        public var chunkFont:Class;
 
        [Embed(source="resources/Quicksand_Dash.otf", fontName='quick', mimeType='application/x-font', embedAsCFF='false')]
        public var quickFont:Class;
 
        [Embed(source="resources/Vegur-M 0602.otf", fontName='vegur', mimeType='application/x-font', embedAsCFF='false')]
        public var vegurFont:Class;
 
        public function FontLibrary()
        {
            Font.registerFont( chunkFont );
            Font.registerFont( quickFont );
            Font.registerFont( vegurFont );
        }
    }
}
Compile the library
mxmlc -o fontlibrary.swf -static-link-runtime-shared-libraries=true -managers=flash.fonts.AFEFontManager src/FontLibrary.as

Assuming you are in the root of the project, the FontLibrary.as looks for fonts in /src/resources/.

Loading with BirdBase

Simply add the SWF to the configuration.yml

94
95
96
97
98
99
100
101
# Assets to load during bootstrap
assets:
    - item:
        key:    "dynamic_library"
        uri:    "assets.swf"
    - item:
       key:    "fonts"
       uri:    "fontlibrary.swf"
Usage in ActionScript3:
var tf:TextFormat = new TextFormat();
tf.font = "vegur"; // or whichever font name you like.
Fonts used here

Chunkfive: http://www.fontsquirrel.com/fonts/ChunkFive
Vegur: http://www.fontspace.com/arro/vegur
Quicksand: http://www.fontsquirrel.com/fonts/Quicksand

Notes

Ensure the latest font file is being loaded. It’s easy to build the swf and then forget to copy it to bin-debug or wherever you’re testing the app.