xjsfl (library)

Categories:Core

Overview

Summary

The core xJSFL class holds core framework settings, manages file loading, and provides error-trapping and debugging functionality.

Contents

Concept & usage

The majority of the interaction with the xjsfl library happens in the bootstrap process, such as setting up the environment and subsequently loading classes and files.

However, the xjsfl class is the glue that holds the rest of the framework together, so it's a good idea to at least familiarise yourself with its properties and functions as it will give you insight into the basic core of the framework.

API

Initialisation

Functions to initialize and reload the framework

init(scope, scopeName, classes)

Initialize the environment by extracting variables / objects / functions to global scope, optionally reloading classes

Parameters:

  • scope Object The scope into which the framework should be extracted
  • scopeName String An optional id, which when supplied, traces a short message to the Output panel
  • classes Array An optional Array of class names / URIs to load

In order to use the framework's functionality, you will first need to initialize it. This is done via xjsfl.init(), which copies the loaded framework classes, functions and variables from the extension to the supplied scope. Once initialized, you are free to use any xJSFL functionality.

Note that for external calls (for example, publishing from Komodo, or simply running the JSFL fle manually) xjsfl.init() will need to have been called before any xJSFL code is called, as external script calls are sandboxed between executions.

The Commands menu and Flash panels however, each have their own persistent scope, and init() only needs to be called once.

The following example initializes the calling scope, then runs the xJSFL inspection function:

xjsfl.init(this);
inspect({a:1, b:2, c:3});
Inspect: Object (depth:4, objects:0, values:3, time:0.0 seconds)
--------------------------------------------------------------------------------
object => Object
	 a: 1
	 b: 2
	 c: 3

Note that when developing classes, you sometimes need to reload classes if you've made changes. In order not to reload the entire framework, you can simply supply the name of the changed classes, and they will be reloaded:

xjsfl.init(this, ['SomeClass']);
> xjsfl: loading library: 'SomeClass'

Note that if you plan to use other classes that also use the re-loaded class, you will need to reload them as well, as they will still reference the original class. If you don't reload, it will appear that Flash (or xJSFL) has magically gobbled your changes, when in fact it's just that the composing class or object is referencing the old composed object.

In this example, the Collection class was updated, but the current ElementSelector function and ElementCollection class need to be updated as they will still be referencing the old Collection class by way of closures:

// add the doSomethingCool() method to the Collection class

// reinitialise framework and reload Collection, plus dependancies
xjsfl.init(this, ['Collection', 'ElementCollection', 'ElementSelector']);

// use the new Collection method, via ElementSelector and ElementCollection
var collection = $('*').doSomethingCool();	

reload()

Reload the framework from disk

Sometimes, especially when developing your own libraries, you may need to reload the whole framework to reset dependancies. The following code reloads the entire framework from scratch:

xjsfl.reload();	

Properties

xjsfl.uri

The xJSFL installation uri

  • Type: String
  • Access: Read

The xJSFL uri is the installation folder of your copy of xJSFL, and will be different, per machine, depending on where you installed it.

The following example traces the path to a file in the user/temp folder:

trace(xjsfl.uri + 'user/temp/test.txt');
file:///E|/Projects/xJSFL/user/temp/test.txt
xJSFL has much more advanced file handling than vanilla JSFL; see the section on File handling for more information.

Settings

Core settings and cached variables

The xjsfl.settings object holds most of the variables and parameters needed to have the framework function. Usually, you won't need to touch these in your everyday xJSFL development, but they're included here for consistency.

xjsfl.settings.app

Application data Information about the Flash version the user is currently running

  • Type: Object
  • Access: Read/write

The xjsfl.settings.app object holds the parsed properties of the fl.version string, as well as some platform (os) constants you can test against:

inspect(xjsfl.settings.app);
Inspect: Object (depth:4, objects:1, values:6, time:0.0 seconds)
--------------------------------------------------------------------------------
object => Object
	 platform: "win"
	[os] => Object
		 mac: false
		 win: true
	 name: "CS4"
	 version: 10
	 csVersion: 4

xjsfl.settings.folders

Common folders which may be used as placeholders in URI references, i.e. '{core}path/to/file.txt'

  • Type: Object
  • Access: Read/write

The xjsfl.settings.folders object stores the location of key folders in an easily-accessible hash. These values are added during the framework bootstrap, and when new modules are created.

The following code lists the currently registered folders:

inspect(xjsfl.settings.folders);
Inspect: Object (depth:4, objects:0, values:9, time:0.0 seconds)
--------------------------------------------------------------------------------
object => Object
	 xjsfl: "file:///E|/Projects/xJSFL/"
	 core: "file:///E|/Projects/xJSFL/core/"
	 modules: "file:///E|/Projects/xJSFL/modules/"
	 user: "file:///E|/Projects/xJSFL/user/"
	 flash: "file:///F|/Users/Dave%20Stewart/AppData/Local/Adobe/Flash%20CS4/en/Configuration/"
	 swf: "file:///F|/Users/Dave%20Stewart/AppData/Local/Adobe/Flash%20CS4/en/Configuration/WindowSWF/"
	 Sample: "file:///E|/Projects/xJSFL/modules/Sample%20Module/"
	 Snippets: "file:///E|/Projects/xJSFL/modules/Snippets/"
	 PGTools: "file:///H|/Perforce/Bolt%20Creative/dev_Mesh_Desktop/iPhone/BoltLib/xJSFL/modules/Pocket%20God%20Tools/"

Each of the property names in the folders hash can be used as a placeholder variable in URIs, and will be swapped out by the system:

load('{user}jsfl/some script.jsfl'); 
// equivilent to: xjsfl.uri + 'user/jsfl/some script.jsfl'

These folders are set up automaticaly when the system starts, with modules setting their own shortcuts, but you can also manually add your own with xjsfl.settings.folders.set():

// create a new custom folder reference
	xjsfl.settings.folders.set('temp', 'c:/temp/');
	trace(xjsfl.settings.folders.temp);

// create a new URI using the custom placeholder
	var uri = new URI('{temp}path/to/folder/');
	trace(uri);			
file:///c|/temp/
file:///c|/temp/path/to/folder/

xjsfl.settings.uris

URIs An ordered list of base URIs which xJSFL uses when searching for files module uris are updated automatically when new modules are added

  • Type: Object
  • Access: Read/write

xJSFL has a specialised file loading system, that allows:

  1. files to be loaded by name, without knowing their absolute URI
  2. the end user to override settings in core or module folders with settings from their user folder

In order to do this, xJSFL holds a list of core URIs where files can be seached for, which are in turn further broken down into core, module and user Arrays. Normally, user files are searched first, followed by module files, followed by core files. This allows you, the user, to override settings on module or core files, just by including the same-named file in your user folder.

Again, in everyday use, you won't need to worry about this, but it's included here for consistency. See the section on Cascading file structure for more info.

The following example dumps the stored URI, for demonstration purposess:

inspect(xjsfl.settings.uris);
Inspect: Object (depth:4, objects:3, values:6, time:0.0 seconds)
--------------------------------------------------------------------------------
object => Object
	[core] => Array
		 0: "file:///F|/Users/Dave%20Stewart/AppData/Local/Adobe/Flash%20CS4/en/Configuration/xJSFL/"
		 1: "file:///E|/Projects/xJSFL/core/"
	[module] => Array
		 0: "file:///E|/Projects/xJSFL/modules/Sample%20Module/"
		 1: "file:///E|/Projects/xJSFL/modules/Snippets/"
		 2: "file:///H|/Perforce/Bolt%20Creative/dev_Mesh_Desktop/iPhone/BoltLib/xJSFL/modules/Pocket%20God%20Tools/"
	[user] => Array
		 0: "file:///E|/Projects/xJSFL/user/"

xjsfl.settings.uris.add(pathOrURI, type)

Adds URIs to the URIs list

Parameters:

  • pathOrURI String A valid path or URI
  • type String The type of URI to add. Valid types are 'user', 'module', or 'core'. Defaults to 'user'

There may be times when you want to add a new path to the URIs list.

The following example adds an 'extra libs' folder, which then allows you to load the 'CustomLib.jsfl' file by name only:

xjsfl.settings.uris.add('f:/development/jsfl/extra libs/');
xjsfl.classes.load('CustomLib');
// Loading 'Custom lib'

xjsfl.settings.newline

Newline character depending on PC or Mac

  • Type: String
  • Access: Read/write
The xjsfl.settings.newline constant can be used to provide correct newlines per system.

xjsfl.file

Methods to load framework assets, or handle common filesystem functionality

find(type, name, returnType)

Finds all files of a particular type within the cascading file system

Parameters:

  • type String The folder in which to look in to find the files, @see switch statement
  • name String A file name (pass no extension to use default), or partial file path
  • returnType Number An optional 0, 1 or -1; 0: all files (default), -1: the last file (user), 1:the first file (core)

Returns:

  •   String A single file path if found and return type is 1 or -1, or null if not
  •   Array An Array of file uris if found, and return type is 0, or null if not

Often, you can just load a file in xJSFL using a URI, or any of the methods outlined in the File handling section of the site.

However, due to the way the cascading file structure in XJSFL works (for example, you may have core, module and user config files), you may sometimes want to find the files you need, rather than accessing them directly, as you don't know in advance in which folder the right file will be.

You can search for files using the following arguments (note that the correct extension will be added for a file if you don't include it):

Folder Function argument default .ext Returns
/jsfl script, scripts, jsfl jsfl The last file
/config config, settings xml The last file
/assets/templates template txt The last file
/jsfl/libraries lib ,libs, library, libraries jsfl All files
any other folder other   All files

The following example finds the main settings file xjsfl.xml, which has been overridden in the user folder, from the core folder:

var file = xjsfl.file.find('settings', 'xjsfl');
trace(file);
'file:///E|/Projects/xJSFL/user/config/xjsfl.xml'

load(pathOrName, type)

Attempts to find and run or return files from the cascading file structure

Parameters:

  • pathOrName String The relative or absolute path, or uri to the file
  • pathOrName String The name or path fragment to a file, with or without the file extension
  • type String The folder type in which to look (i.e. settings) for the file(s)

Returns:

  •   Boolean A Boolean indicating Whether the file was successfully found and loaded
  •   XML An XML object of the content of the file, if XML
  •   String The string content of the file otherwise

The load() method will directly load a file, or will attempt to first find, then load an existing file from within the cascading file structure, depending on the method arguments:

xjsfl.file.load('path/to/file.ext'); // load a file directly
xjsfl.file.load(file, folder); // find and load a file within the framework folder structure

For more information on finding files, see the sections on folder structure and automatic file-finding.

Also, depending on the file type, the file will be executed or returned as follows:

  • jsfl files will be executed
  • xml files will have an XML object returned
  • All other files will return plain text

The following examples load and return a file called user.xml ( returning an XML object) directly:

var xml = xjsfl.file.load(xjsfl.uri + 'user/settings/data/some file.xml');
var xml = xjsfl.file.load('user/settings/data/some file.xml'); // defaults to xjsfl folder

The following example finds, then loads and returns the same user XML file using the find file functionality:

var xml = xjsfl.file.load('some file', 'data');

The following example finds and returns the contents of a text file:

var text = xjsfl.file.load('some file.txt', 'temp');		

save(pathOrURI, contents, force)

Saves data to file

Parameters:

  • pathOrURI String The path or URI to save data to
  • contents String The data to save
  • force Boolean An optional Boolean to force overwriting of readonly files

Returns:

  •   Boolean true or false depending on the result

The save method is a shortcut to File's save method. The following example saves some text to the same folder the script is currently running in:

xjsfl.file.save('test.txt', 'Hello there!');
trace(new File('test.txt').contents);
Hello there!

xjsfl.classes

Core methods to load and register framework libraries and classes

When creating a library, class or function that you want restored on framework initialization, the class needs to be loaded, registered and restored when needed. See the guide on Creating your own functions, libraries and classes for more details.

register(name, obj, uri)

Registers a class/function for later retrieval

Parameters:

  • name String The name of the class / function / object to register
  • obj Object The actual class / function / object
  • uri String An optional URI to the object's file, defaults to the calling file's URI

Returns:

  •   xjsfl The main xJSFL object

When creating a library, class or function that you want restored on framework initialization, you need to first register it with the xJSFL core then the library file is automatically restored each time the framework is initialized.

The following example registers a Test class with the xJSFL core so it is loaded on future xjsfl.init()s:

function Test(value)
{
    this.value = value;
}

xjsfl.classes.register('Test', Test);

load(fileRef, reload)

Load a class or array of classes from disk

Parameters:

  • fileRef String A class name
  • fileRef String A class filename or path, relative to any jsfl/libraries folder
  • fileRef String A wildcard string pointing to a folder, i.e. '//user/jsfl/libraries/*.jsfl'
  • fileRef Array An Array of class filepaths
  • reload Boolean An optional Boolean to force a reload of loaded URIs

Returns:

  •   xjsfl The main xJSFL object

This method should only need to ever be called from the bootsrap files, but for the record, the syntax is documented here.

The following example loads the jsfl file Test.jsfl from the jsfl/libraries folder:

xjsfl.classes.load('Test');

By default, xJSFL doesn't reload classes which have already been loaded, as so many classes rely on each other. To force a reload, pass true as the second parameter:

xjsfl.classes.load('Test', true);

Alternatively, you can use the $classes parameter of the xjsfl init() method to reload classes as you initialize the framework (this is useful when developing classes, and needing to update just the class, or its dependencies, without reloading the whole framework).

in xJSFL, by convention, the there is one class (usually) per file, and the file name is named after the class (this makes it easier to track down classes when loading using the cascading file system and file.find)

Note that if you get errors when loading external classes, you can check the xJSFL logs for more details, from Commands > xJSFL > View Log.

cache

Cache of class definitions

  • Type: Object
  • Access: Read/write

The class.cache property holds a cache of all the loaded classes, and can be used to access loaded classes directly, even when they haven't yet been loaded into the current scope:

// no need to call xjsfl.init(this) first...
xjsfl.classes.cache.Output.inspect({a:1, b:2});
Inspect: Object (depth:4, objects:0, values:2, time:0.0 seconds)
--------------------------------------------------------------------------------
object => Object
a: 1
b: 2

xjsfl.modules

Core methods to handle the initialization and loading of modules

create(namespace, properties, window)

Factory method to create an xJSFL module instance

Parameters:

  • namespace String The namespace of the module (should match the AS3 and manifest values)
  • properties Object The properties of the module
  • window Window A reference to the window the function was called from

Returns:

  •   Module An xJSFL Module instance

Due to the way Flash and JSFL sandboxes data, xJSFL Modules need to be created, then internally stored in the xJSFL extension for future retrieval. This is done through the framework-centric xjsfl.modules.create() method.

The following example :

Test =
{
	init:function()
	{
		trace("I'm a new Test Module!");
	},

	doSomething:function()
	{
		trace("Test module is doing something!");
	}
}
Test = xjsfl.modules.create('Test', Test, this);			

The next time flash loads, and assuming you have the correct manifest.xml file in the module's folder, you should see this:

> xjsfl: REGISTERING MODULE "TEST"
> xjsfl: added 1 search paths for "E:/Projects/xJSFL/modules/Test/"

 

find(uri, init)

Finds and returns the base URIs of all modules in a given folder and sub folders

Parameters:

  • uri String An optional folder URI to search in, defaults to xJSFL/modules/
  • init Boolean An optional Boolean to initialize any found modules

Returns:

  •   Array An Array of module URIs

The find method is responsible for finding and initializing modules, and is called core bootstrap to ensure all modules have their search paths added, and are ready to run when their panels load.

However, you can also call find() manually (usually in the user bootstrap) to add modules from folders external to xJSFL. You might want to do this if you have a centralised repository of code that multiple developers are contributing to.

The following example attemps to find and initialize modules on an external development drive:

xjsfl.find('f:/development/jsfl/xjsfl modules/', true);	
> xjsfl: REGISTERING MODULE "ANIMATION TOOLS"
> xjsfl: added 1 search paths for "f:/development/jsfl/xjsfl modules/Animation Tools/" > xjsfl: REGISTERING MODULE "EXPORT TOOLS"
> xjsfl: added 1 search paths for "f:/development/jsfl/xjsfl modules/Export Tools/"

load(namespace)

Loads the module's bootstrap to load code locally (usually into the host panel)

Parameters:

  • namespace String The namespace of the module to initialize

Usually, this method is only ever called (automatically) by the AS3 Module framework, and is used to load the module's bootstrap file, and thus the code therin, into a panel, however you can run it manually if you wish.

The following example runs the bootstrap file of the named module Test from from the modules folder:

xjsfl.modules.load('Test');
Test bootstrap run!

xjsfl.debug

Debugging methods for file, function and errors

The xjsfl.debug object has been designed to help you debug your code by packaging boilerplate code into some handy methods, that are easy to call and provide clear Output Panel feedback on the results.

func(fn, params, scope)

Tests a callback and outputs the error stack if the call fails

Parameters:

  • fn Function The function to test
  • params Array An optional Array of arguments or Arguments object to pass to the function
  • scope Object An optional scope to run the function in

Returns:

  •   Value The result of the function if successful

The following example tests an erroneous function, where b is not defined:

function test(a)
{
	trace(b);
}

xjsfl.debug.func(test, [1])
ReferenceError: b is not defined
--------------------------------------------------------------------------------

	0 > test([object Array])

		line: 9
		file: temp.jsfl
		path: xJSFL/core/jsfl/temp/

	1 >

		line: 12
		file: temp.jsfl
		path: xJSFL/core/jsfl/temp/

If testing functions on objects, it is important to pass the scope through through as well, or else the function's this will point to the window object, and not the object on which the function resides:

var obj =
{
settings:{a:1, b:2, c:3},
test:function()
{
trace(this.settings.a);
}
};
xjsfl.debug.func(obj.test); // TypeError: this.settings has no properties
xjsfl.debug.func(obj.test, [], obj); // 1

Also see the MDN docs on error types for throwing your own errors.

file(uriOrPath)

Attemps to run and trap errors in external script files

Parameters:

  • param String uriOrPath The URI or path of the file to load

One of the most annoying things in JSFL development is running files which seem to fail silently. The cause of this is always errors within the loaded file which fl.runScript() won't alert you to.

xjsfl.debug.file() attempts to work round this limitation by wrapping Flash's native fl.runScript(), and instead, reading and eval()ing the contents of both the target file and any subsequent JSFL files loaded (thorugh fl.runScript(), or any of xJSFL's file loading functions), trapping any errors and printed the message to the output panel.

xjsfl.debug.file('user/jsfl/bad-file.jsfl');

Upon encountering an error, the output panel will display something like the following:

> xjsfl: Debugging "E:\projects\xJSFL\user\jsfl\bad-file.jsfl" ...
The following JavaScript error occurred:

At line 7 of file "error.jsfl":
ReferenceError: a is not defined

The following JavaScript error(s) occurred:

At line 1603 of file "xjsfl.jsfl":

> xjsfl: Script debugging halted

Note that because debug.file() eval()s files rather than running them, the "loaded" files are not physically run from their location on disk so any URI-specific functions like scriptDir and fl.scriptURI will fail.

To turn on or off file debugging permanently, including for fl.runScript(), see the xjsfl.debug.state flag.

error(error, testing)

Generates, logs and traces a human-readable error stack

Parameters:

  • error Error A JavaScript Error object
  • log Boolean An optional Boolean to log the error
  • testing Boolean Internal use only. Removes test() stack items

Traces a human-readable error stack to the Output Panel

Parameters:

  • error Error A javaScript Error object

The example below is the longhand version of the example above, but uses a manual try/catch case to send the error to the debug function.

try
{
	test(1);
}
catch(err)
{
	xjsfl.debug.err(err);
}

Again, the output will be the error stack:

ReferenceError: b is not defined
--------------------------------------------------------------------------------

	0 > test([object Array])

		line: 9
		file: temp.jsfl
		path: xJSFL/core/jsfl/temp/

	1 >

		line: 12
		file: temp.jsfl
		path: xJSFL/core/jsfl/temp/

Comments are closed.