Combining multiple scripts into stand-alone Modules

Categories:Extensibility

Contents

Overview

As described on the Extending xJSFL page, a Module is a collection of folders and files that are packaged together to provide related functionality.

XJSFL comes with several modules as standard:

  • The Snippets module, which allows you to launch script files from an easy-to-use panel
  • The Sample Module module, which is designed to be easy to pick apart to see how modules work
  • The Code Examples module, which is simply a repository for scripts and asset files, outside of the user folder

This page will expand on that to give you a clear idea of the various components that go to make up a module, physically and conceptually, and where necessary, illustrating points with the the Sample Module module that comes with xJSFL.

For a short tutorial on creating a module from scratch, see Writing an xJSFL Module.

Anatomy of a module

The folder structure of a module mirrors the core or user folders, as it is a self-contained entity with its own relationships and inter-dependencies:

However, rather than going over the layout and structure again, take a look at Folder stucture for more info.

Regarding modules, they have a few extra key files:

  1. An XML manifest, which defines common module attributes
  2. The JSFL bootstrap, which runs initialization code as soon as the module is loaded
  3. The JSFL module, which contains the core module functionality
  4. An optional SWF panel, which provides a rich interactive interface in order to interact with the user

In the case of the Sample Module, that looks like this:

/xJSFL
    /modules
        /Sample Module
            /assets
            /config
            /jsfl
                /bootstrap.jsfl
                /sample.jsfl
            /flash
                /WindowSWF
                    /Sample Module.swf
            /ui
            /manfest.xml

These components will be discussed next.

Module components

XML manifest

It is a requirement of each module to have a manifest file in its root folder, as they are searched for and registered by the system at startup. This file (borrowed from Java methodology) defined the module's root folder, and provides is a single location where common module information can be accessed from all module-related environments:

  • The JSFL authoring environment (via xjsfl.file.load())
  • The AS3 authoring environment (via URLRequest())
  • The SWF panel (via URLRequest())

The file itself is simply XML, and stores information in the following format:

<manifest>
	<module>
		<meta>
			<name>Sample Module</name>
			<description>A sample module, with all source, demonstrating AS3/JSFL functionality</description>
			<version>0.1</version>
			<url>xjsfl.vercel.app/category/support/tutorials/modules</url>
			<author>
				<name>Dave Stewart</name>
				<company>xJSFL</company>
				<email>dave@xjsfl.vercel.app</email>
			</author>
		</meta>
		<data>
			<namespace>Sample</namespace>
			<panel>xJSFL Sample Module</panel>
			<preload>false</preload>
			<uri token="sample" />
		</data>
	</module>
</manifest>

Note that the data.namespace and data.panel properties should match exactly the spelling and case of both the value supplied to the xjsfl.module.create() function and the actual panel's published name, otherwise the framework will not be able to match them up.

JSFL bootstrap

Once the module's manifest has been registered, the next file to be loaded (usually triggered by the module's panel being opened) will be the module's bootstrap.

Like the user bootstrap, it's completely up to the developer what to put in here, but usually, you would load any necessary libraries and functions, then load the module's core Module file:

xjsfl.init(this);                  // initialize the framework in the current scope
load('libraries/sample lib.jsfl'); // load the custom module libraries
load('sample.jsfl');               // load the main module file

Note that the "this" in the init() call will be the window object of the panel's container, which is a separate sandboxed scope from the main window object that holds Flash's documents Array.

Note that the bootstrap file must reside in the root of your module's /jsfl folder.

JSFL module

The core of every module is its main JSFL class, and serves as the access point to your module's functionality. This file can be saved anywhere in your module's /jsfl folder, but the convention is to place it in the jsfl root.

xJSFL modules must extend the xJSFL Module class, which provides the following base functionality:

  • core properties like the module's URI
  • methods to set up and load data from the framework
  • methods needed to communicate with the SWF panel
  • logging functionality

On top of this, the developer should add additional functionality by way of public methods that can be called directly within the JSFL environment, or from a Flash panel.

Module methods can be accessed:

  • internally to the module via this.method
  • externally, within the window scope via the module's variable, i.e. Test.method
  • externally, via a different window scope via xjsfl.modules.getModule('Test').method;
  • from ActionScript (in the Flash panel) via AbstractModule.call('method');

The JSFL for a basic module can be as simple as this:

// module properties
var Sample =
{
    init:function()
    {
        trace('Module "xjsfl.modules.' +this.name+ '" initialized...');
    },

    test:function(value)
    {
        this.log('Test function called with: "' +value+ '"');
    }
}

// create and register module
Sample = xjsfl.modules.create('Sample', Sample, this);

// test module
Sample.test('Hello!');

Note the init() method, which serves as the module's constructor function.

Also, the code to create and register the module, which is a static all to the main xJSFL class where the modules definitions are also stored:

Test = xjsfl.modules.create('Sample', Sample, this);

Upon executing the file in Komodo (CTRL+Enter), or reloading the framework, you would see the following:

Module "xjsfl.modules.Sample" initialized...
> Sample: Test function called with "Hello!"

SWF panel

The final piece in the module puzzle is the SWF panel.

Panels are optional, but they provide a much richer environment than XUL to interact with your tools, and have the advantage of being non-modal, so the user can interact with the panel and the Flash IDE at the same time.

The FLA file for the panel can be stored anywhere (although usually assets/source/) but the SWF file should be published to the flash/WindowSWF/ folder, so that it can be automatically copied to the main Flash folder each time the framework starts.

xJSFL comes with its own AS3 module framework which provides as standard:

  • structured loading of assets and data
  • separation of AS3 and JSFL logic
  • 2-way communication from AS3 to JSFL
  • JSFL-specific classes to bring additional functionality

Creation of an AS3 panel is as simple as:

  • Extending the AbstractModule class
  • Setting a few authoring-time values
  • Adding some calls to the JSFL Module via AbstractModule.call()
  • Wiring the calls to some button event handlers (or the like)
  • Publishing, then opening the actual panel in Flash

The simplest code needed to set up a module would be this:

// SampleModule class

package
{
	import com.xjsfl.jsfl.modules.AbstractModule;

	/**
	 * ...
	 * @author Dave Stewart
	 */
	public class SampleModule extends AbstractModule
	{
		// Create a static instance property as the class is accessed for the first time
		public static const instance:SampleModule = new SampleModule();

		// constructor
		public function SampleModule()
		{
			// setup name + authoring time module URI and xJSFL URI
			// Note that the paths here needs to point to YOUR local xJSFL and module folders!
			setup('Sample', 'file:///E|/Projects/xJSFL/modules/Sample Module/', 'file:///E|/Projects/xJSFL/');
		}

		// makes the AS3 > JSFL call to Sample.test()
		public function test(value:String):String
		{
			return call('test', value);
		}

	}

}

In your main AS3 Document class, where you would have your button, you would then have the following code:

// Document class

protected function onTestClick(event:MouseEvent):void
{
	SampleModule.test('Goodbye'); // access SampleModule statically
}

Note that the public API in the AS3 class contains no JSFL. Typically, developers tend to use long, concatenated strings of JSFL inside their ActionScript, which is then passed to the JSFL environment via MMExecute(), but this makes for fragile and hard-to-maintain code.

xJSFL promotes clear separation of JSFL and AS3 code, in the same way that you wouldn't send PHP code to a server from a client, you shouldn't send JSFL code from AS3 to the Flash authoring environment; instead you call a defined public API (your JSFL module instance) and have values returned, just like the web.

If you have too many methods for your main JSFL module instance, then simply break down the calls into smaller objects:

// SampleModule class

// makes the AS3 > JSFL call to Sample.subobject.test()
public function test():String
{
	return call('subobject.test', 'Some value');
}

Next Steps

Comments are closed.