Spark Equivalent of mx:Module and mx:ModuleLoader. mx:Module and mx:ModuleLoader extend the mx:Container infrastructure which is undesirable.
Herman is building a Spark app. He defines a set of views in a TabNavigator. He is sad that he still has to use mx:TabNavigator as there is no Spark equivalent, but he wants to use Spark for everything else. So he uses NavigatorContent as the children of the mx:TabNavigator and Spark components within. His TabNavigator might look something like:
<mx:TabNavigator width="500" height="300"> <s:NavigatorContent label="Tab One"> <s:layout> <s:VerticalLayout /> </s:layout> <s:Label text="label one" /> <s:TextInput /> <s:Label text="label two" /> <s:TextArea /> </s:NavigatorContent> <s:NavigatorContent label="Tab Two"> <s:layout> <s:HorizontalLayout /> </s:layout> <s:Label text="label three" /> <s:Button label="button three" /> <s:Label text="label four" /> <s:Button label="button four" /> </s:NavigatorContent> </mx:TabNavigator>
He realizes that he's going to have lots of tabs, and that will make for a very big SWF, plus different team members are going to be responsible for different tabs so he decides to use modules. He simply copies the guts of each NavigatorContent into a separate MXML as follows:
<!-- SparkModule1.mxml --> <?xml version="1.0" encoding="utf-8"?> <s:Module xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" > <fx:Declarations> </fx:Declarations> <fx:Style> </fx:Style> <fx:Script> <![CDATA[ ]]> </fx:Script> <s:layout> <s:VerticalLayout /> </s:layout> <s:Label text="label one" /> <s:TextInput /> <s:Label text="label two" /> <s:TextArea /> </s:Module> <!-- SparkModule2.mxml --> <?xml version="1.0" encoding="utf-8"?> <s:Module xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" > <fx:Declarations> </fx:Declarations> <fx:Style> </fx:Style> <fx:Script> <![CDATA[ ]]> </fx:Script> <s:layout> <s:HorizontalLayout /> </s:layout> <s:Label text="label three" /> <s:Button label="button three" /> <s:Label text="label four" /> <s:Button label="button four" /> </s:Module>
and modifies the main app to look like this:
<mx:TabNavigator width="500" height="300"> <s:ModuleLoader label="Tab One" url="SparkModule1.swf" > </s:ModuleLoader> <s:ModuleLoader label="Tab Two" url="SparkModule2.swf"> </s:ModuleLoader> </mx:TabNavigator>
This makes him very happy because in Flex 4.1, he would have had to use mx:Module as the main class in the module files and placed a SkinnableContainer inside the mx:Module which would have added another layer to the display object tree.
Work with your Flash Builder contacts to complete a workflow document that describes how this feature will be exposed to users in Flash Builder. Include a link to this document here.
Work with your Catalyst contacts to complete a workflow specification that describes how this feature will be exposed to users in Catalyst. Include a link to this document here.
Carving up a set of navigator views into modules is the most common use of mx:Module and mx:ModuleLoader today. The second most common scenario for UI modules is to bring in popups as modules. This is currently hard to do even with mx:Module as mx:Module ends up wrapping an mx:TitleWindow or mx:Panel which defeats its ability to be dragged or have its own focus manager. The popup-as-modules scenario will remain difficult with Spark as well. s:Module will also wrap the s:TitleWindow or s:Panel and prevent dragging and focus. There is a solution on my blog that folks will continue to use for Spark that does not involve Module or ModuleLoader. We will focus entirely on the most common case of carving up a set of navigator views. Therefore:
Spark Module will extend SkinnableContainer. This is because NavigatorContent also extends SkinnableContainer and we want to allow all attributes and tags of the NavigatorContent including the skinClass to be simply copied and pasted into a module file (except for the label and icon properties which should remain on the child of the navigator).
Spark ModuleLoader will implement INavigatorContent so it can be used directly in mx-based Navigators. Spark ModuleLoader will extend Group as it doesn't need a skin. All of its visuals are dictated by the Spark Module that it loads.
Spark Module has no new APIs. It mainly gives us a new tag and a place to hang the Frame metadata. Here is the entire class:
//////////////////////////////////////////////////////////////////////////////// // // ADOBE SYSTEMS INCORPORATED // Copyright 2008 Adobe Systems Incorporated // All Rights Reserved. // // NOTICE: Adobe permits you to use, modify, and distribute this file // in accordance with the terms of the license agreement accompanying it. // //////////////////////////////////////////////////////////////////////////////// package spark.modules { import mx.modules.IModule; import spark.components.SkinnableContainer; <a href="Frame%28factoryClass%3D%26quot%3Bmx.core.FlexModuleFactory%26quot%3B%29">Frame(factoryClass="mx.core.FlexModuleFactory")</a> /** * The Spark equivalent of mx:Module * * @langversion 3.0 * @playerversion Flash 10.2 * @playerversion AIR 2.5 * @productversion Flex 4.5 */ public class Module extends SkinnableContainer implements IModule { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @langversion 3.0 * @playerversion Flash 10.2 * @playerversion AIR 2.5 * @productversion Flex 4.5 */ public function Module() { super(); } } }
The Spark ModuleLoader looks as follows. The events are exactly the same as mx:ModuleLoader. The APIs are a combination of INavigatorContent and mx:ModuleLoader.
package spark.modules { //-------------------------------------- // Events //-------------------------------------- /** * Dispatched when the ModuleLoader starts to load a URL. * * @eventType mx.events.FlexEvent.LOADING * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ <a href="Event%28name%3D%26quot%3Bloading%26quot%3B%2C%20type%3D%26quot%3Bflash.events.Event%26quot%3B%29">Event(name="loading", type="flash.events.Event")</a> /** * Dispatched when the ModuleLoader is given a new URL. * * @eventType mx.events.FlexEvent.URL_CHANGED * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ <a href="Event%28name%3D%26quot%3BurlChanged%26quot%3B%2C%20type%3D%26quot%3Bflash.events.Event%26quot%3B%29">Event(name="urlChanged", type="flash.events.Event")</a> /** * Dispatched when information about the module is * available (with the <code>info()</code> method), * but the module is not yet ready. * * @eventType mx.events.ModuleEvent.SETUP * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ <a href="Event%28name%3D%26quot%3Bsetup%26quot%3B%2C%20type%3D%26quot%3Bmx.events.ModuleEvent%26quot%3B%29">Event(name="setup", type="mx.events.ModuleEvent")</a> /** * Dispatched when the module is finished loading. * * @eventType mx.events.ModuleEvent.READY * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ <a href="Event%28name%3D%26quot%3Bready%26quot%3B%2C%20type%3D%26quot%3Bmx.events.ModuleEvent%26quot%3B%29">Event(name="ready", type="mx.events.ModuleEvent")</a> /** * Dispatched when the module throws an error. * * @eventType mx.events.ModuleEvent.ERROR * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ <a href="Event%28name%3D%26quot%3Berror%26quot%3B%2C%20type%3D%26quot%3Bmx.events.ModuleEvent%26quot%3B%29">Event(name="error", type="mx.events.ModuleEvent")</a> /** * Dispatched at regular intervals as the module loads. * * @eventType mx.events.ModuleEvent.PROGRESS * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ <a href="Event%28name%3D%26quot%3Bprogress%26quot%3B%2C%20type%3D%26quot%3Bmx.events.ModuleEvent%26quot%3B%29">Event(name="progress", type="mx.events.ModuleEvent")</a> /** * Dispatched when the module data is unloaded. * * @eventType mx.events.ModuleEvent.UNLOAD * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ <a href="Event%28name%3D%26quot%3Bunload%26quot%3B%2C%20type%3D%26quot%3Bmx.events.ModuleEvent%26quot%3B%29">Event(name="unload", type="mx.events.ModuleEvent")</a> /** * ModuleLoader is a component that behaves much like a SWFLoader except * that it follows a contract with the loaded content. This contract dictates that the child * SWF file implements IFlexModuleFactory and that the factory * implemented can be used to create multiple instances of the child class * as needed. * * <p>The ModuleLoader is connected to deferred instantiation and ensures that * only a single copy of the module SWF file is transferred over the network by using the * ModuleManager singleton.</p> * * @see mx.controls.SWFLoader * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public class ModuleLoader extends Group implements INavigatorContent { //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- //---------------------------------- // applicationDomain //---------------------------------- /** * The application domain to load your module into. * Application domains are used to partition classes that are in the same * security domain. They allow multiple definitions of the same class to * exist and allow children to reuse parent definitions. * * @see flash.system.ApplicationDomain * @see flash.system.SecurityDomain * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public var applicationDomain:ApplicationDomain; //---------------------------------- // child //---------------------------------- /** * The IVisualElement created from the module factory. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public var child:IVisualElement; //---------------------------------- // url //---------------------------------- /** * The location of the module, expressed as a URL. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get url():String { .... } /** * @private */ public function set url(value:String):void { .... } //-------------------------------------------------------------------------- // // Properties: INavigatorContent // //-------------------------------------------------------------------------- //---------------------------------- // creationPolicy //---------------------------------- // Internal flag used when creationPolicy="none". // When set, the value of the backing store _creationPolicy // style is "auto" so descendants inherit the correct value. private var creationPolicyNone:Boolean = false; <a href="Inspectable%28enumeration%3D%26quot%3Bauto%2Call%2Cnone%26quot%3B%2C%20defaultValue%3D%26quot%3Bauto%26quot%3B%29">Inspectable(enumeration="auto,all,none", defaultValue="auto")</a> /** * @inheritDoc * * @default auto * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get creationPolicy():String { ... } /** * @private */ public function set creationPolicy(value:String):void { ... } //---------------------------------- // icon //---------------------------------- <a href="Bindable%28%26quot%3BiconChanged%26quot%3B%29">Bindable("iconChanged")</a> <a href="Inspectable%28category%3D%26quot%3BGeneral%26quot%3B%2C%20defaultValue%3D%26quot%3B%26quot%3B%2C%20format%3D%26quot%3BEmbeddedFile%26quot%3B%29">Inspectable(category="General", defaultValue="", format="EmbeddedFile")</a> /** * The Class of the icon displayed by some navigator * containers to represent this Container. * * <p>For example, if this Container is a child of a TabNavigator, * this icon appears in the corresponding tab. * If this Container is a child of an Accordion, * this icon appears in the corresponding header.</p> * * <p>To embed the icon in the SWF file, use the @Embed() * MXML compiler directive:</p> * * <pre> * icon="@Embed('filepath')" * </pre> * * <p>The image can be a JPEG, GIF, PNG, SVG, or SWF file.</p> * * @default null * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get icon():Class { ... } /** * @private */ public function set icon(value:Class):void { ... } //---------------------------------- // label //---------------------------------- <a href="Bindable%28%26quot%3BlabelChanged%26quot%3B%29">Bindable("labelChanged")</a> <a href="Inspectable%28category%3D%26quot%3BGeneral%26quot%3B%2C%20defaultValue%3D%26quot%3B%26quot%3B%29">Inspectable(category="General", defaultValue="")</a> /** * The text displayed by some navigator containers to represent * this Container. * * <p>For example, if this Container is a child of a TabNavigator, * this string appears in the corresponding tab. * If this Container is a child of an Accordion, * this string appears in the corresponding header.</p> * * @default "" * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get label():String { ... } /** * @private */ public function set label(value:String):void { ... } //-------------------------------------------------------------------------- // // Methods: INavigatorContent // //-------------------------------------------------------------------------- /** * @private */ public function get deferredContentCreated():Boolean { ... } /** * @private */ public function createDeferredContent():void { ... } //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * Loads the module. When the module is finished loading, the ModuleLoader adds * it as a child with the <code>addElement()</code> method. This is normally * triggered with deferred instantiation. * * <p>If the module has already been loaded, this method does nothing. It does * not load the module a second time.</p> * * @param url The location of the module, expressed as a URL. This is an * optional parameter. If this parameter is null the value of the * <code>url</code> property will be used. If the url parameter is provided * the <code>url</code> property will be updated to the value of the url. * * @param bytes A ByteArray object. The ByteArray is expected to contain * the bytes of a SWF file that represents a compiled Module. The ByteArray * object can be obtained by using the URLLoader class. If this parameter * is specified the module will be loaded from the ByteArray and the url * parameter will be used to identify the module in the * <code>ModuleManager.getModule()</code> method and must be non-null. If * this parameter is null the module will be load from the url, either * the url parameter if it is non-null, or the url property as a fallback. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function loadModule(url:String = null, bytes:ByteArray = null):void { ... } /** * Unloads the module and sets it to <code>null</code>. * If an instance of the module was previously added as a child, * this method calls the <code>removeChild()</code> method on the child. * <p>If the module does not exist or has already been unloaded, this method does * nothing.</p> * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function unloadModule():void { ... } } }
None
See Usage Scenario
None
None
None
None
None
None
None
None
None
Using existing resources
None
\