Invisible Button Command - Part II
Welcome to the second part of my series on extending Flash with JSFL commands. Part one of the series can be found here which you need to have read to follow along. In this part of the series we will be creating a dialog box using XML and associate it with our invisible button command.
This dialog box will be a list of options the developer can customize when using our new command. Here’s the options we’ll implement:
- Enter a URL for the button
- Choose whether the URL entered is a variable name or a string
- Enter in the target window for the URL
Step 1
In your “My Commands” folder, or whatever the name is of the folder you created the “Invisible Button.jsfl” file in, create an empty text document named “Invisible Button.xml.” We’ll keep the name the same as our command except for the extension for this tutorial but this doesn’t need to be the case. You can name this file anything you want. You may even have multiple XML files per command if you wanted to make a complex interface. The XML is parsed with an XML to UI engine that uses a subset of the XML User Interface Language (XUL) plus some additional Flash only tags. You can see the full documentation in Macromedia’s Live Docs.
Open this empty XML document in the text editor of your choice so we can add the following content to it:
<?xml version="1.0"?> <dialog title="Invisible Button" buttons="accept,cancel"> </dialog>
Here we are defining the dialog as having the title “Invisible Button” and adding “accept” and “cancel” buttons to the form. Since we want to tweak our form and see how it looks as we build it, let’s open it from within our command.
var flash_doc = fl.getDocumentDOM(); var flash_lib = flash_doc.library; var flash_tl = flash_doc.getTimeline(); var flash_w = flash_doc.width; var flash_h = flash_doc.height; // Be sure to set this path to match your setup var result = flash_doc.xmlPanel("file:///C:/Documents and Settings/Username/Desktop/My Commands/Invisible Button.xml"); // rest of the code follows
By using the xmlPanel( fileURI ) method of the document object we open the XML file we just created. The URI format for this method uses a string expressed as a file:/// URI. It must be a full path to the file. In part three we’ll learn how to reference the folder we install the finished command to. Save your files and click on your command to see the dialog box open. It should look just like this:

Clicking on either of the two buttons returns to your JSFL script a result object which we store in a variable cleverly named “result”. This object’s dismiss property is the only predefined property and will have a value of either “accept” or “cancel”. The other properties will be defined by you in your XML file.
... var result = flash_doc.xmlPanel("file:///C:/Documents and Settings/Username/Desktop/My Commands/Invisible Button.xml"); if (result.dismiss == "accept") { var symbolname = "invisible"; … flash_doc.selectNone(); }
If you go ahead and run your command you will notice that clicking the “accept” button will add the invisible button to the movie and clicking the “cancel” button will do nothing, as it should.
Step 2
Let’s take a look at the XML file. Open “Invisible Button.xml” in your text editor and we’ll start to add controls to the form. Each of the controls we add will in turn become properties of the xmlPanel’s result object. We want the form to look like this:

Let’s start with the layout controls. We’ll use the <grid> container so that we can lay out our controls in a columns and rows format. As you can see we need the form to be two columns wide; one for the field names and the other for the fields. Since there are three form elements and we have one per line we’ll need three rows.
The format is very different than the <table> container you might expect from HTML. The <grid> container always contains exactly two children - <columns> and <rows>.
The <columns> container has two empty <column/> tags to let the engine know that each row will contain two columns. When the engine parses a <row> tag it will put the first element in the first column and the second element in the second column. For example, our first element in each row will be a <label> control to display the name of our input control. The second element in each row will be the input control. Finally, after the grid we have a <separator/> tag which will draw a line between the form an its buttons.
This is how the complete “Invisible Button.xml” file should look:
<?xml version="1.0"?> <dialog title="Invisible Button" buttons="accept,cancel"> <grid> <columns> <column/> <column/> </columns> <rows> <row> <label value="URL:" /> <textbox id="url" tabindex="1" value="_root.clickTag" multiline="false" maxlength="100" /> </row> <row> <label value="URL Type:" /> <radiogroup id="type" tabindex="2"> <radio label="Variable" selected="true" /> <radio label="String" /> </radiogroup> </row> <row> <label value="Target:" /> <textbox id="target" tabindex="3" value="_blank" multiline="false" maxlength="20" /> </row> </rows> </grid> <separator/> </dialog>
Each input control has an “id” attribute which becomes a property with the same name in the result object returned from xmlPanel(). This is how we will access the user defined values in our JSFL file.
Save your updated XML file and run the command. You should now see the form, though none of the options actually has an affect on the button we are creating. We’ll do that in the next step.
Step 3
Now that we have the form laid out correctly it’s pretty simple to access its properties. All you need to do is access the property you need from the result object. To see the form work and the properties it’s returning let’s add this bit of code to our JSFL file.
Add the following lines to your JSFL:
... var result = flash_doc.xmlPanel("file:///C:/Documents and Settings/Username/Desktop/My Commands/Invisible Button.xml"); // Add these three lines here to see all of the available // properties of the result object for (var prop in result) { fl.trace("property " + prop + " = " + result[prop]); } if (result.dismiss == "accept") { …
You output window should display something similar to the following:
property url = _root.clickTag property type = Variable property target = _blank property dismiss = accept
Using these newly created properties we can make the JSFL respond to the options selected in the dialog box.
Here’s the Part II version of the “Invisible Button.jsfl” in its entirety:
/** * Invisible Button.jsfl (Part 2 of 3 part series) * JSFL Command that adds an invisible button to the library of an open * FLA and places that button on to the current timeline at the height * and width of the stage. * * Author: James O’Reilly - JOR * www.jamesor.com * * This work is licensed under the Creative Commons attribution 2.5 * This comment block must remain intact. */ var flash_doc = fl.getDocumentDOM(); var flash_lib = flash_doc.library; var flash_tl = flash_doc.getTimeline(); var flash_w = flash_doc.width; var flash_h = flash_doc.height; // Be sure to set this path to match your setup var result = flash_doc.xmlPanel("file:///C:/Documents and Settings/Username/Desktop/My Commands/Invisible Button.xml"); if (result.dismiss == "accept") { // Make sure the result values are valid // and use defaults if they are not var mUrl = result.url; if (mUrl == "") mUrl = "_root.clickTag"; else { // If we are setting the URL to a string instead of // using a variable name then we need to quote the url. if (result.type == "String") mUrl = "\"" + mUrl + "\""; } var mTarget = result.target; // Additional Local Variables var symbolname = "invisible"; // Check the library to see if the symbol already exists // if it does, create a new one with the next highest // number while (flash_lib.itemExists(symbolname)) { flash_lib.deleteItem(symbolname); } // Add the new symbol to the library and enter edit mode flash_lib.addNewItem("button", symbolname); flash_lib.editItem(symbolname); // Draw the button button_tl = flash_doc.getTimeline(); button_tl.insertKeyframe(3); button_tl.currentFrame = 3; flash_doc.addNewRectangle({left:0, top:0, right:flash_w, bottom:flash_h}, 0); flash_doc.selectAll(); flash_doc.breakApart(); flash_doc.setFillColor("#000000"); flash_doc.setStroke("#00000000", 1, "solid"); flash_doc.selectNone(); // Exit edit mode and add the symbol to the stage flash_doc.exitEditMode(); // Create a new layer for this symbol and rename it to button var layerNum = flash_tl.addNewLayer(); flash_tl.setSelectedLayers(layerNum, true); flash_tl.setLayerProperty("name", "button"); // Place the button on the stage and add the actionscript flash_lib.addItemToDocument({x:flash_w/2, y:flash_h/2}, symbolname); flash_doc.selection[0].actionScript = "on (release) {\n\tgetURL("+mUrl+", \""+mTarget+"\");\n}"; flash_doc.selectNone(); }
In part three of this series we’ll see how to package this command up into an installer for distribution.
August 24th, 2006 at 1:23 pm
Invisible Button Command - Part III
Welcome to the third and final installment of this three part series on writing and packaging JSFL commands. In this last post I will go over how to update our Invisible Button command so that we can use a relative installation path to locate our XML …
August 18th, 2008 at 8:05 am
Thanks James this is a really good example of how to use XMLUI , i found a problem though, perhaps its something indroduced with CS3 but i get:
At line 56 of file “C:\Documents and Settings\MY NAME\Local Settings\Application Data\Adobe\Flash CS3\en\Configuration\Commands\Invisible Button.jsfl”:
The function breakApart() is currently unavailable.