F9 for actions

Some possibly useful and definitely unuseful ActionScript 3.0 code.

Posts tagged WindowSWF

Aug 31

Moving Library Assets from FLA to FLA with JSFL

One of my latest projects had me scratching my head while I was doing my R&D. The project was to build a Flash panel that could pull assets in from another FLA that acts as a library. My first thought was to see if there was any way to copy items directly out of the library and add or paste them into the current working FLA. In my research this just isn’t possible, but I was still able to get the panel built.

Basically the process that works is as follows:

  1. Open the library FLA file
  2. Put the wanted library item on the stage with library.addItemToDocument()
  3. Use fl.getDocumentDOM().clipCut() to add the item to the clipboard
  4. Close the library
  5. Use fl.getDocumentDOM().clipPaste() to add the asset to the FLA

It seems pretty simple and it is, truly the hardest part was figuring out that that was the process to use. Here’s what my JSFL looks like:

//Loads an asset from the libraryFile into the current working FLA
//libraryFile - the filename of the library (icons.fla)
//AssetName - the asset name as it is in the FLA library
function LoadAsset( libraryFile, AssetName ) {
	
	var originalDoc = fl.getDocumentDOM();
	
	fl.openDocument( librariesPath() + libraryFile );
	var libDoc = fl.getDocumentDOM();
	
	fl.getDocumentDOM().library.addItemToDocument({x:0,y:0}, AssetName);
	
	libDoc.clipCut();
	fl.closeDocument(fl.getDocumentDOM(), false);
	originalDoc.clipPaste();
}

//this is where I'm keeping the library FLA files
function librariesPath() {
	return fl.configURI + 'Resources/AssetLibraries/';
}

And here’s the panel:

The way it all works is the panel loads an XML file that defines all the library files and populates the combo box. Then when a file is selected from the combo box, I have another JSFL function that opens the FLA and grabs all the top-level (not in folders) asset names from the library and returns them back to the panel as a comma delimited string. The string is broken up into an array and populates the asset list. The ‘Add to Stage’ button then uses the name in the list to call back to the JSFL referenced above.

Hope this helps anyone looking to do this, I found no help on this via Google in my own research.


May 17

Listening for stage selections with JSFL

I’ve researched and tested a few ideas, but for the most part the conclusion is that there is no nice way to monitor the stage for some sort of “Selection Event” when building WindowSWF panels or JSFL scripts. JSFL does allow you to listen for some events, however I found none of these to suffice for wanting to know when the user has selected an instance item on the stage.

Adding an ENTER_FRAME event listener to your panel works. Basically calling out to a JSFL script on each frame to see if anything is selected, but the thought of having this execution loop running is like nails on a chalkboard when it comes to being efficient. Also I noticed bugs when trying to drill into objects - double clicks not registering on the stage, etc. So that idea was pitched out the window. A timer would do the same to a lesser degree, but again it’s not as nice a solution as having Flash tell us that something was selected.

I ended up going with what I’ve seen in most 3rd-party panels - a button to manually tell flash “hey, I’m ready for you to analyze my selection I have made on the stage.” Although the manual part about this is annoying at best, it seems to be the “nice” solution for now.


May 10

Converting a JSFL Object to JSON

I couldn’t find any online resource to talk about how people are passing data from JSFL scripts to their Flash Panels. When you use MMExecute you can return a String value back to Flash, or if you’re making a function available via ExternalInterface you can also pass primitive datatypes into the functions. However when you start talking about passing Objects of any significant structure, things get a little hairy.

So it was my conclusion that I needed to serialize my data object in JSFL in order to pass it to Flash. And when you talk serialize in Javascript you should think JSON, so I set in search for an out-of-the-box Javascript Object to JSON serializing function - should be easy to find right? Unfortunately, after two days of struggling with different implementations, I found that some of the String functions like match and replace cause errors (not saying they aren’t implemented, just for whatever reason they didn’t work for me like they do in regular JS).

So without further delay, here is my very less-than perfect, less-than optimized JSFL Object to JSON String functions. (Also note that these will convert any Arrays nested in your Objects to Objects themselves with keys being the string equivalent of their indexes.

— UPDATE —

I wrote this post before testing it completely against sending the JSON string over to Flash via the SWFPanel.call() method. What I found out while trying to do this is that you can not, for whatever reason, send literal single or double quotes embedded within the string variable. So I changed up my function to use tildes (~) instead of quotes, which I then replaced with quotes over on the AS3 side of things.

function serializeObject( o ) {
	var s = '{';
	s += so( o );
	//remove the last comma
	s = s.slice( 0, s.length-1 );
	s += '}';

	return s;
}

function so( o ) {
	var s = '';

	for( var key in o ) {
		if( o[key].toString() == '[object Parameter]' ) {
			s +=  '~' + key + '~:{';
			s += so( o[key] );

			//remove the last comma
			s = s.slice( 0, s.length-1 );
			s += '},';
		} else if(o[key].constructor === Array ) {

			for( var key2 in o[key] ) {
				if(key2 != "" && o[key][key2].value != '""') {
					s += '~' + key2 + '~:~' + o[key][key2].value + '~,';
				}
			}

		}else {
			if(key != "" && o[key] != '""') {
				s += '~' + key + '~:~' + o[key].toString()  + '~,';
			}
		}
	}

	return s;
}

And here is what I do on the AS3 side to convert it into an Object from JSON (note I’m using the as3corelib to JSON decode the string).

//function exposed via ExternalInterface and called from JSFL
public function setParameters( s:String ):void {

	var p:RegExp = /~/g;
	var t:String = s.replace(p, '"');		

	var o:Object = JSON.decode(t);

}

Like I said it’s not a perfect implementation, but it works pretty well for nested Objects. To put this in perspective, I’m using this so I can pass all the attributes of multiple selected components on the stage (via the fl.getDocumentDOM().selection Array) to my WindowSWF Panels which will allow me to change and configure the components’ properties.