19 June 2006
A basic understanding of JSFL syntax, the Flash authoring environment, and familiarity with JavaScript.
Intermediate
If you've ever had to do any tedious, repetitive tasks in the Flash authoring environment, chances are that you could have automated it using JavaScript Flash (JSFL), the extensibility layer that first appeared in Macromedia Flash MX 2004.
Flash 8 includes a number of useful new JSFL objects and methods that enable advanced customization and extensibility of the authoring environment and will ultimately make your life easier. Read on to discover more about these new JSFL features and how to put them to good use in your projects.
Although an in-depth discussion of JavaScript Flash syntax is not possible due to the limited scope of this article, I'll run through the very basics, for those of you new to extending the Flash authoring environment.
If you've ever written JavaScript code for the browser, you probably know about the Document Object Model (DOM). The DOM is essentially a tree structure that describes all elements on a web page. In the case of JSFL, the DOM describes all elements in the Flash authoring environment.
The following line of JavaScript code in the browser would get the value of an input text field named message in the first form element of the current page:
document.forms[0].message.value;
In this case document is the top-level object of the DOM, forms is an array containing references to all forms in the document, and message is the name of the text field element where you're retrieving the value. As you can see, you're essentially walking down the DOM to get to the element you need.
Similar to the previous example, the Flash authoring environment also has a DOM for use with JSFL that you can use to target pretty much any function of the interface. For example, the following line of JSFL code would target the background color value of the currently opened document:
flash.getDocumentDOM().backgroundColor
Here flash (or fl for short) is the top-level object of the DOM. This object contains a method called getDocumentDOM() which returns a DOM representing the file currently open. You then target the backgroundColor property which, when used in an actual script, would return you to the current value of the background color property.
The most important difference between JavaScript in the browser and JSFL in the Flash authoring environment is that, unlike a script on a web page, JSFL will run onlyduring authoring—not when your Flash application is deployed. This is because the goal of JSFL is simply to extend functionality of the authoring environment.
Now that you've got some idea of the concept of JSFL, let's move on to look at what new features were introduced in JSFL for Flash 8.
When you first look at the list of new features in JSFL for Flash 8, it might not look incredibly impressive, but looks can deceive. Three additional objects were added: Filter, Project, and ProjectItem. These objects pretty much do what you expect: Filter enables you to specify a filter that you can then add to an item on the Stage, and Project and ProjectItem enable you to work with Flash Project (FLP) files using JSFL code—something that was not possible in Flash MX 2004.
In addition to these objects, there is an impressive list of very useful new methods and properties. Listing them all is not feasible but these items are just some of the more interesting additions: document.zoomFactor for getting or setting the zoom factor of the Stage, document.setMetaData() and document.getMetaData() for assigning metadata to your SWF, and fl.getAppMemoryInfo() for retrieving information about current memory usage by the Flash authoring environment.
There are also a wide range of methods and properties that enable you to work with advanced stroke settings, custom easing, strokes, and fills but one of my favorite additions is without a doubt confirm(). This method allows you to present the user with a simple confirmation dialog box. This truly indispensable feature enables the user to confirm the action when doing anything potentially dangerous such as deleting a file or clearing items from the Stage.
The example below shows a simple JSFL script that asks the user to confirm before deleting the currently selected layer in the Timeline (see Figure 1).
var answer = confirm("Are you sure you want to delete this layer?");
if(answer) {
fl.getDocumentDOM().getTimeline().deleteLayer();
}
The confirm method returns true when the user clicks OK and false when Cancel (see Figure 1). In this example you store the result of the confirm method in the answer variable and use an if statement to check that its value is true before deleting the layer.
Note: Flash will delete a layer only if there is more than one available in the Timeline.
This example illustrates how methods like confirm can help you deal with situations where you'd like some user confirmation before proceeding. No doubt you can think of numerous other situations where this would come in handy.
As you probably expect, the new Filter object is related to the Filters feature in Flash 8. Using the document.getFilters and document.setFilters methods, you can get or modify filters on the selected symbol instance on the Stage.
The following JSFL script looks at what filters are applied to the currently selected symbol instance on the Stage and writes the name of each filter to the Output panel:
var currentFilters = fl.getDocumentDOM().getFilters();
for(var i=0; i<currentFilters.length; i++) {
fl.trace(filters[i].name);
}
Note that the document.getFilters method works only when a symbol selected has at least one filter applied; otherwise the script fails and stops executing. This small issue will no doubt be addressed for the next release.
When looping through the array provided by the document.getFilters method, each item is an instance of the Filter object and has properties that hold the settings for the particular filter that was applied. We then output the name property of each of these Filter instances. The value of these name properties can be any combination of the filter name values listed below:
dropShadowFilterblurFilterglowFilterbevelFiltergradientGlowFiltergradientBevelFilteradjustColorFilterTo retrieve the available properties for the applied filters, you can iterate through the Filter object instance using the following script:
var currentFilters = fl.getDocumentDOM().getFilters();
for(var i=0; i<currentFilters.length; i++) {
for(var j in currentFilters[i]) {
fl.trace(j+": "+currentFilters[i][j]);
}
}
Running the script with a symbol instance selected that has the Dropshadow filter applied with the default settings would output the following:
name: dropShadowFilter
angle: 44.999998781459
blurX: 5
blurY: 5
distance: 5
color: '#000000'
quality: low
strength: 100
inner: false
knockout: false
hideObject: false
As you can see, the Dropshadow filter has name, angle, blurX, blurY, distance, color, quality, strength, inner, knockout and hideObject properties. You can use these properties to make changes to the filters and apply them using the document.setFilters method. The JSFL script (below) loops through the applied filters and changes the Dropshadow filter distance value to 10:
var currentFilters = fl.getDocumentDOM().getFilters();
for(var i=0; i<currentFilters.length; i++) {
if(currentFilters[i].name == "dropShadowFilter") {
currentFilters[i].distance = 10;
}
}
fl.getDocumentDOM().setFilters(currentFilters);
That is all well and good, but you can also add and remove filters for a selected symbol using the document.addFilter and document.removeFilter methods. The following JSFL script adds the Blur filter to a selected symbol (or symbols) on the Stage:
fl.getDocumentDOM().addFilter("blurFilter");
That's pretty easy, no? Once you've applied a filter, the document.removeFilter method allows you to remove any filter from a symbol instance based on its index. The first applied filter has index value 0, the second has index value 1, and so on. The following line of code removes the first filter applied to a symbol:
fl.getDocumentDOM().removeFilter(0);
There is another method available for removing all filters applied on a symbol in one go, document.removeAllFilters:
fl.getDocumentDOM().removeAllFilters();
You can temporarily disable a specific filter based on its index using the document.disableFilter method or re-enable it using the document.enableFilter method. In this case we disable the first filter applied to a symbol instance:
fl.getDocumentDOM().disableFilter(0);
Just as with document.removeAllFilters there is a method available to disable all filters in one go, document.disableAllFilters:
fl.getDocumentDOM().disableAllFilters();
One final feature available for disabling filters is the document.disableOtherFilters method. After you provide the index of a filter, this feature disables all filters other than the one at the index you provide.
Let's say you've got a symbol instance that has, respectively, the Dropshadow, Blur, and Glow filters applied. The following line of JSFL code will disable the Dropshadow and Glow filters:
fl.getDocumentDOM().disableOtherFilters(1);
The Blur filter has an index of 1, making it the only filter of the selected symbols remaining enabled.
Last but not least, there is a document.changeFilterOrder method that swaps two filters based on their index:
fl.getDocumentDOM().changeFilterOrder(0,1);
You can see how the JSFL Filter object gives you a great deal of freedom in managing filters applied to symbols. Some possible use cases include changing a specific filter setting, such as the Dropshadow filter distance property, throughout an entire FLA in one go. If you are in a situation where you would otherwise have to change dozens of symbols manually, you'll be happy to have this helpful tool at your disposal.
The Project and ProjectItem objects are more exciting additions to JSFL for Flash 8. These objects enable you to work with Flash Project (FLP) files, setting or retrieving the name of your project, the default document for the project, the project location on your hard drive, and much more.
Before exploring these features, let's create a new Flash Project file using JSFL syntax. The following line of code creates an FLP file named top-secret.flp in the root of your C drive (admittedly not the most convenient location to put it, but I'm sure it's the last place they'll look for top-secret material):
fl.createProject("file:///C|/top-secret.flp","Top Secret Project");
When this line of code is executed, it creates the file in the location you provide in the first argument and gives the Flash Project the name provided in the second argument—in this case, "Top Secret Project".
Note: On Mac OS, use this file path: file:///[Macintosh HD]/top-secret.flp.
Using the document.openProject method, you can then open this project, providing it with the URI as the first argument:
fl.openProject("file:///C|/top-secret.flp");
Once a Flash Project is available, you can put the Project and ProjectItem objects to good use. First of all, change the name of the project. "Top Secret Project" is too obvious, so let's call it "Project X".
To make this change, you need to get a reference to the currently opened project using document.getProject where you can then set the new value for its name property:
fl.getProject().name = "Project X";
Next, start adding files to the project using the Project.addFile method, passing the URI to the file(s) you want to add. A second optional argument then determines whether the project should automatically create a folder.
The automatic creation of a folder works as follows:
If you don't provide the second, optional argument, the Project.addFile method defaults to false, meaning it doesn't create a subfolder:
fl.getProject().addFile("file:///C|/Projects/myFile.fla",true);
This JSFL script adds the myFile.fla file in the Project subfolder to the open Flash Project. Because the second argument is true, a folder called "Projects" is created in the FLP.
When a Flash Project contains a number of items and you would like to retrieve information about a specific item, you can use the Project.items array. Each of the items in this array is an instance of the ProjectItem class. The example below loops through the Project.items array and writes the name of each item to the Output panel:
var currentProject = fl.getProject();
for(var i=0; i<currentProject.items.length; i++) {
fl.trace(currentProject.items[i].displayName);
}
Running the above JSFL script for your current Flash Project outputs "myFile.fla" because it's the only file added to the project. You could also use the Project.findProjectItem method if you know the item's location on the hard drive to have it return a ProjectItem instance:
fl.getProject().findProjectItem("file:///C|/Projects/myFile.fla");
Apart from the displayName property, each ProjectItem instance also has an itemURI property that holds the location of the item on your hard drive, and a publishProfile property which holds the name of the publish profile chosen for that item.
Another useful feature in the ProjectItem object is the isMissing property. This gets set to true if the item in the project is no longer available on the hard drive. So if you delete or move a file that is contained within your Flash Project, this property will flag the problem.
Besides the properties just discussed, there are a few more methods available for both the Project and ProjectItem object that determine whether a Flash Project or a particular file in the project can be tested or published. These methods are Project.canTestProject and Project.canPublishProject for the Project object, and ProjectItem.canTest and ProjectItem.canPublish for the ProjectItem object.
This is not difficult to use, you just trigger these methods on a Project or ProjectItem object instance and it returns a true or false boolean value that tells you whether it is able to test or publish. The line of JSFL code (below) checks to see if the current project is able to be published and writes the result out to the output panel:
fl.trace(fl.getProject().canPublishProject());
Of course once you know that a Flash Project or ProjectItem can be tested or published, you might want to trigger that using JSFL syntax. This is where the Project.testProject, Project.publishProject, ProjectItem.test, and ProjectItem.publish methods come into use. The example (below) uses JSFL syntax to trigger the currently opened Flash Project to publish:
fl.getProject().publishProject();
Using all the Project and ProjectItem objects introduced in JSFL for Flash 8, you now have full control over Flash Project files. You can use this functionality to dynamically create new FLP files, add commonly used ActionScript classes to a project, and have your script set up files according to your usual convention. A huge timesaver!
I hope this article has given you some insight into what's new with JSFL for Flash 8. Using the Filter object to create, modify, and remove filters, you now have the ability to automate the use of filters in your Flash projects. With the new Project and ProjectItem objects at your disposal, you can now work with Flash Project files using JSFL syntax.
Of course, this is just a small glimpse at what is available for you to use. As I mentioned early on in the article, there are many new methods for working with strokes, fills, and custom easing that you can look at, and no doubt use, when working on your next JSFL script.
For more information on the available methods and properties, check out the documentation in Flash Help (Help > Flash Help > Extending Flash > Introduction > What's new in the JavaScript API) or the Flash LiveDocs.
This is the first of several articles I'm writing about JSFL. Feel free to contact me at feedback@peterelst.com to let me know what you would like to learn more about regarding JSFL features.
| 04/23/2012 | Auto-Save and Auto-Recovery |
|---|---|
| 04/23/2012 | Open hyperlinks in new window/tab/pop-up ? |
| 04/21/2012 | PNG transparencies glitched |
| 04/01/2010 | Workaround for JSFL shape selection bug? |
| 02/13/2012 | Randomize an array |
|---|---|
| 02/11/2012 | How to create a Facebook fan page with Flash |
| 02/08/2012 | Digital Clock |
| 01/18/2012 | Recording webcam video & audio in a flv file on local drive |