fl.browseForFileURL won’t work across hard drives

In JSFL, when you use fl.browseForFileURL it returns a URI pointing to the file or folder you’ve chosen. On OX, however, the reference is wrong when you choose a file on a hard drive other than your primary.

Example: I have a hard drive on my mac named HD2. If I browse to a file on there, the URI returned will be

file:///HD2/myFile.txt

If you then immediately try a

FLfile.exists('file:///HD2/myFile.txt')

it returns false. This is due to OSX’s referencing system. the correct location is

file:///Volumes/HD2/myFile.txt

so all we have to do is add the word “Volumes/” to the string and the reference will be correct.

public static function browseForFileURI( title:String = "", type:String = "open" ):String
{
   var ar:Array = MMExecute( "fl.browseForFileURL('" + type + "','" + title + "');" ).split("/");
   ar[2] = "/Volumes";
   return ar.join("/");
}

Ant compc swc compile Error: ‘Class’ is undefined.

In making an Ant script to produce a swc of my project, I used the compiler.external-library-path to include an external swc. I forgot to include append=”true” and this killed the include of the needed flex swcs.

If you start getting lots of these errors that seem like the Flex/Flash basics aren’t compiling in, look for the swcs you’ve included and make sure you append them, not overwrite.

Here’s the errors I got, there’s a lot of them, but maybe this will help people find this information by searching:

    [compc] Error: 'flash.events:AsyncErrorEvent' is undefined.
    [compc]
    [compc] Error: 'flash.utils:ByteArray' is undefined.
    [compc]
    [compc] Error: 'encodeURI' is undefined.
    [compc]
    [compc] Error: 'flash.utils:escapeMultiByte' is undefined.
    [compc]
    [compc] Error: 'EvalError' is undefined.
    [compc]
    [compc] Error: 'flash.media:SoundTransform' is undefined.
    [compc]
    [compc] Error: 'Array' is undefined.
    [compc]
    [compc] Error: 'Math' is undefined.
    [compc]
    [compc] Error: 'RegExp' is undefined.
    [compc]
    [compc] Error: 'flash.ui:ContextMenuItem' is undefined.
    [compc]
    [compc] Error: 'flash.system:ApplicationDomain' is undefined.
    [compc]
    [compc] Error: 'flash.text:TextSnapshot' is undefined.
    [compc]
    [compc] Error: 'flash.utils:clearInterval' is undefined.
    [compc]
    [compc] Error: 'flash.ui:ContextMenuBuiltInItems' is undefined.
    [compc]
    [compc] Error: 'flash.display:Scene' is undefined.
    [compc]
    [compc] Error: 'flash.system:SecurityDomain' is undefined.
    [compc]
    [compc] Error: 'flash.display:IBitmapDrawable' is undefined.
    [compc]
    [compc] Error: 'Date' is undefined.
    [compc]
    [compc] Error: 'flash.geom:Matrix' is undefined.
    [compc]
    [compc] Error: 'flash.events:StatusEvent' is undefined.
    [compc]
    [compc] Error: 'flash.filters:BlurFilter' is undefined.
    [compc]
    [compc] Error: 'flash.geom:ColorTransform' is undefined.
    [compc]
    [compc] Error: 'isXMLName' is undefined.
    [compc]
    [compc] Error: 'URIError' is undefined.
    [compc]
    [compc] Error: 'flash.display:StageAlign' is undefined.
    [compc]
    [compc] Error: 'ReferenceError' is undefined.
    [compc]
    [compc] Error: 'flash.errors:IllegalOperationError' is undefined.
    [compc]
    [compc] Error: 'flash.text:FontStyle' is undefined.
    [compc]
    [compc] Error: 'flash.net:URLStream' is undefined.
    [compc]
    [compc] Error: 'flash.system:IMEConversionMode' is undefined.
    [compc]
    [compc] Error: 'flash.net:navigateToURL' is undefined.
    [compc]
    [compc] Error: 'XMLList' is undefined.
    [compc]
    [compc] Error: 'flash.events:SecurityErrorEvent' is undefined.
    [compc]
    [compc] Error: 'flash.text:AntiAliasType' is undefined.
    [compc]
    [compc] Error: 'flash.media:Microphone' is undefined.
    [compc]
    [compc] Error: 'flash.net:registerClassAlias' is undefined.
    [compc]
    [compc] Error: 'flash.net:getClassByAlias' is undefined.
    [compc]
    [compc] Error: 'flash.events:ContextMenuEvent' is undefined.
    [compc]
    [compc] Error: 'flash.events:ProgressEvent' is undefined.
    [compc]
    [compc] Error: 'flash.text:TextField' is undefined.
    [compc]
    [compc] Error: 'Class' is undefined.
    [compc]
    [compc] Error: 'flash.ui:Mouse' is undefined.
    [compc]
    [compc] Error: 'flash.display:DisplayObject' is undefined.
    [compc]
    [compc] Error: 'flash.xml:XMLNodeType' is undefined.
    [compc]
    [compc] Error: 'flash.net:NetStream' is undefined.
    [compc]
    [compc] Error: 'isNaN' is undefined.
    [compc]
    [compc] Error: 'flash.events:IMEEvent' is undefined.
    [compc]
    [compc] Error: 'flash.filters:DropShadowFilter' is undefined.
    [compc]
    [compc] Error: 'flash.events:ActivityEvent' is undefined.
    [compc]
    [compc] Error: 'decodeURIComponent' is undefined.
    [compc]
    [compc] Error: 'adobe.utils:MMEndCommand' is undefined.
    [compc]
    [compc] Error: 'flash.system:IME' is undefined.
    [compc]
    [compc] Error: 'flash.utils:setInterval' is undefined.
    [compc]
    [compc] Error: 'flash.ui:Keyboard' is undefined.
    [compc]
    [compc] Error: 'flash.events:Event' is undefined.
    [compc]
    [compc] Error: 'flash.display:BitmapData' is undefined.
    [compc]
    [compc] Error: 'flash.errors:ScriptTimeoutError' is undefined.
    [compc]
    [compc] Error: 'flash.text:TextFieldType' is undefined.
    [compc]
    [compc] Error: 'decodeURI' is undefined.
    [compc]
    [compc] Error: 'escape' is undefined.
    [compc]
    [compc] Error: 'flash.display:GradientType' is undefined.
    [compc]
    [compc] Error: 'flash.accessibility:AccessibilityImplementation' is undefined.
    [compc]
    [compc] Error: 'flash.accessibility:AccessibilityProperties' is undefined.
    [compc]
    [compc] Error: 'flash.media:Camera' is undefined.
    [compc]
    [compc] Error: 'AS3' is undefined.
    [compc]
    [compc] Error: 'flash.net:URLLoader' is undefined.
    [compc]
    [compc] Error: 'Object' is undefined.
    [compc]
    [compc] Error: 'flash.utils:unescapeMultiByte' is undefined.
    [compc]
    [compc] Error: 'flash.net:NetConnection' is undefined.
    [compc]
    [compc] Error: 'flash.display:MovieClip' is undefined.
    [compc]
    [compc] Error: 'flash.events:NetStatusEvent' is undefined.
    [compc]
    [compc] Error: 'SecurityError' is undefined.
    [compc]
    [compc] Error: 'flash.utils:describeType' is undefined.
    [compc]
    [compc] Error: 'UninitializedError' is undefined.
    [compc]
    [compc] Error: 'flash.net:URLRequest' is undefined.
    [compc]
    [compc] Error: 'Function' is undefined.
    [compc]
    [compc] Error: 'DefinitionError' is undefined.
    [compc]
    [compc] Error: 'flash.utils:IDataOutput' is undefined.
    [compc]
    [compc] Error: 'SyntaxError' is undefined.
    [compc]
    [compc] Error: 'flash.events:IOErrorEvent' is undefined.
    [compc]
    [compc] Error: 'flash.utils:IDataInput' is undefined.
    [compc]
    [compc] Error: 'flash.utils:setTimeout' is undefined.
    [compc]
    [compc] Error: 'flash.display:SimpleButton' is undefined.
    [compc]
    [compc] Error: 'Namespace' is undefined.
    [compc]
    [compc] Error: 'flash.utils:Timer' is undefined.
    [compc]
    [compc] Error: 'flash.errors:StackOverflowError' is undefined.
    [compc]
    [compc] Error: 'flash.events:FocusEvent' is undefined.
    [compc]
    [compc] Error: 'XML' is undefined.
    [compc]
    [compc] Error: 'flash.utils:flash_proxy' is undefined.
    [compc]
    [compc] Error: 'VerifyError' is undefined.
    [compc]
    [compc] Error: 'flash.filters:GlowFilter' is undefined.
    [compc]
    [compc] Error: 'flash.net:URLVariables' is undefined.
    [compc]
    [compc] Error: 'flash.display:DisplayObjectContainer' is undefined.
    [compc]
    [compc] Error: 'flash.display:InteractiveObject' is undefined.
    [compc]
    [compc] Error: 'flash.ui:ContextMenu' is undefined.
    [compc]
    [compc] Error: 'flash.display:LoaderInfo' is undefined.
    [compc]
    [compc] Error: 'flash.utils:SetIntervalTimer' is undefined.
    [compc]
    [compc] Error: 'flash.events:FullScreenEvent' is undefined.
    [compc]
    [compc] Error: 'flash.display:Shape' is undefined.
    [compc]
    [compc] Error: 'flash.filters:BitmapFilter' is undefined.
    [compc]
    [compc] Error: 'flash.text:TextFormat' is undefined.
    [compc]
    [compc] Error: 'flash.display:Graphics' is undefined.
    [compc]
    [compc] Error: 'flash.filters:BevelFilter' is undefined.
    [compc]
    [compc] Error: 'flash.events:TimerEvent' is undefined.
    [compc]
    [compc] Error: 'flash.xml:XMLNode' is undefined.
    [compc]
    [compc] Error: 'flash.errors:IOError' is undefined.
    [compc]
    [compc] Error: 'flash.errors:MemoryError' is undefined.
    [compc]
    [compc] Error: 'flash.utils:IExternalizable' is undefined.
    [compc]
    [compc] Error: 'flash.display:Sprite' is undefined.
    [compc]
    [compc] Error: 'flash.events:WeakFunctionClosure' is undefined.
    [compc]
    [compc] Error: 'flash.errors:InvalidSWFError' is undefined.
    [compc]
    [compc] Error: 'flash.text:StyleSheet' is undefined.
    [compc]
    [compc] Error: 'flash.events:IEventDispatcher' is undefined.
    [compc]
    [compc] Error: 'flash.events:WeakMethodClosure' is undefined.
    [compc]
    [compc] Error: 'NaN' is undefined.
    [compc]
    [compc] Error: 'Number' is undefined.
    [compc]
    [compc] Error: 'int' is undefined.
    [compc]
    [compc] Error: 'flash.geom:Rectangle' is undefined.
    [compc]
    [compc] Error: 'flash.display:Loader' is undefined.
    [compc]
    [compc] Error: 'flash.utils:Proxy' is undefined.
    [compc]
    [compc] Error: 'flash.geom:Point' is undefined.
    [compc]
    [compc] Error: 'flash.net:Responder' is undefined.
    [compc]
    [compc] Error: 'TypeError' is undefined.
    [compc]
    [compc] Error: 'isFinite' is undefined.
    [compc]
    [compc] Error: 'flash.events:MouseEvent' is undefined.
    [compc]
    [compc] Error: 'flash.text:Font' is undefined.
    [compc]
    [compc] Error: 'String' is undefined.
    [compc]
    [compc] Error: 'flash.errors:EOFError' is undefined.
    [compc]
    [compc] Error: 'flash.system:Capabilities' is undefined.
    [compc]
    [compc] Error: 'flash.display:Stage' is undefined.
    [compc]
    [compc] Error: 'flash.system:LoaderContext' is undefined.
    [compc]
    [compc] Error: 'parseFloat' is undefined.
    [compc]
    [compc] Error: 'flash.geom:Transform' is undefined.
    [compc]
    [compc] Error: 'parseInt' is undefined.
    [compc]
    [compc] Error: 'ArgumentError' is undefined.
    [compc]
    [compc] Error: 'flash.system:Security' is undefined.
    [compc]
    [compc] Error: 'flash.events:KeyboardEvent' is undefined.
    [compc]
    [compc] Error: 'QName' is undefined.
    [compc]
    [compc] Error: 'encodeURIComponent' is undefined.
    [compc]
    [compc] Error: 'flash.events:TextEvent' is undefined.
    [compc]
    [compc] Error: 'flash.utils:getQualifiedClassName' is undefined.
    [compc]
    [compc] Error: 'flash.events:EventPhase' is undefined.
    [compc]
    [compc] Error: 'undefined' is undefined.
    [compc]
    [compc] Error: 'flash.text:TextFormatAlign' is undefined.
    [compc]
    [compc] Error: 'flash.text:TextLineMetrics' is undefined.
    [compc]
    [compc] Error: 'flash.utils:getDefinitionByName' is undefined.
    [compc]
    [compc] Error: 'flash.utils:getQualifiedSuperclassName' is undefined.
    [compc]
    [compc] Error: 'unescape' is undefined.
    [compc]
    [compc] Error: 'flash.utils:Dictionary' is undefined.
    [compc]
    [compc] Error: 'flash.events:ErrorEvent' is undefined.
    [compc]
    [compc] Error: 'adobe.utils:MMExecute' is undefined.
    [compc]
    [compc] Error: 'flash.display:StageScaleMode' is undefined.
    [compc]
    [compc] Error: 'flash.text:TextFieldAutoSize' is undefined.
    [compc]
    [compc] Error: 'RangeError' is undefined.
    [compc]
    [compc] Error: 'flash.utils:clearTimeout' is undefined.
    [compc]
    [compc] Error: 'trace' is undefined.
    [compc]
    [compc] Error: 'flash.net:sendToURL' is undefined.
    [compc]
    [compc] Error: 'flash.filters:ColorMatrixFilter' is undefined.
    [compc]
    [compc] Error: 'flash.utils:getTimer' is undefined.
    [compc]
    [compc] Error: 'Boolean' is undefined.
    [compc]
    [compc] Error: 'flash.events:HTTPStatusEvent' is undefined.
    [compc]
    [compc] Error: 'Error' is undefined.
    [compc]
    [compc] Error: 'flash.events:EventDispatcher' is undefined.
    [compc]
    [compc] Error: 'flash.external:ExternalInterface' is undefined.
    [compc]
    [compc] Error: 'flash.text:TextRun' is undefined.
    [compc]
    [compc] Error: 'Infinity' is undefined.
    [compc]
    [compc] Error: 'flash.media:Video' is undefined.
    [compc]
    [compc] Error: 'uint' is undefined.
    [compc]

Embed a text/txt file in a Flex/AS3 application

This is actually pretty easy, but it’s not something widely known. Here’s the code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
            layout="absolute"
            creationComplete="trace(text);">
   <mx:Script>
      <![CDATA[
         [Embed( source="myTextFile.txt", mimeType="application/octet-stream" )]
         public var MyText:Class
         public var text:String=new MyText().toString();
      ]]>
   </mx:Script>
</mx:Application>

So what is this doing?
The embed tag works to keep the file in your swf. It then binds it to the Class defined on the next line. Since it’s an unrecognized file format (Flex supports swf, mp3, jpg, gif, png), Flex wouldn’t know what to do with it, so we specify a mimeType — a description of how to handle this file.
Then, we create a new variable and set its contents to a new instance of the Class, then convert it to a string.
Finally, I’ve set the Application parameter creationComplete to perform a trace of the text variable’s contents. If all is correct, you should see a trace with the txt file’s contents.
EmbedTXTTest

Helpful JSFL Scripts for Indexing the Flash IDE Stage

Get all of the layers in a timeline

By using JSFL, you can use this code to get a list of all of the layers in a timeline. This is returned as an array of named objects whose data is accessible like this:

var layers = getLayers(fl.getDocumentDOM().getTimeline());
layers[0].name

This will return the first layer’s name.

var getLayers = function(timeline){
   var layers = [];
   for(var l in timeline.layers){
      layers.push({
         name:timeline.layers[l].name,
         layer:timeline.layers[l],
         index:l
      });
   }
   return layers;
};

Get all of the keyframes in a layer

By using JSFL, you can use this code to get a list of all of the Keyframes on a layer. This is returned as an array of named objects whose data is accessible like this:

var keyframes = getKeyframes(fl.getDocumentDOM().getTimeline().layers[0]);
keyframes[0].index;

This will return the first keyframe’s index, allowing you to reference it later using layer.frames[index].

var getKeyframes = function(layer){
   var keyframes = [];
   for(var f in layer.frames){
      if (f==layer.frames[f].startFrame){
         keyframes.push({
            frame:layer.frames[f],
            index:f
         });
      }
   }
   return keyframes;
};

Get all of the instances in a keyframe

By using JSFL, you can use this code to get a list of all of the instances on a keyframe. This is returned as an array of named objects whose data is accessible like this:

var instances = getInstances(fl.getDocumentDOM().getTimeline().layers[0].frames[0]);
instances[0].index;

This will return the first instance’s index, allowing you to reference it later using frame.instances[index].

var getInstances = function(keyframe){
   var instances = [];
   for(var e in keyframe.elements){
      if(keyframe.elements[e].elementType == 'instance'){
         if(keyframe.elements[e].libraryItem.itemType != 'compiled clip'){
            instances.push({
               instance:keyframe.elements[e], 
               index:e
            });
         }
      }
   }
   return instances;
};

JSFL and compiled clips

I’ve run into a number of issues trying to reconcile JSFL and compiled clips. Some of the features of a library object are unavailable when inspecting a compiled clip, leading to the wonderful JavaScript Errors we’ve come to love.

The particular oddity I’ve been wrestling with is that CompiledClipInstance objects don’t have a timeline, so if I try and walk the display list, digging into items as I find them, when I hit one of these, the reference to instance.timeline throws an error. The only solution is to exclude these kinds of items from your search.

Using Flex SWFs as Component UI or in J2EE Tapestry

Flex and Flash swfs have some small differences in how they work. While Flex produces a 2-frame swf, it doesn’t work quite right in certain situations. If you’ve got a project where Flash or an AS3 project in Flex/FlashBuilder produces SWFs that work just fine and Flex/Flashbuilder MXML-based swfs don’t (if you can right click your partially loaded MXML-based swf and say play and it works), this will probably solve your problem.

Anyone building Custom UI components in Flash might be thinking about using Flex, which, until today would prove difficult. I’ve got some other tutorials out there on how to use Flex UIs in Flash, but they were missing a big part–embedding capability.

Now that we can bypass the preloader in flex, we can use this same process to kick-start our Flex files when using them in Flash or in Tapestry (I assume Tapestry works, please let me know if it doesn’t).

Bypassing the Flex Preloader

Ahh, one of those holy grail type posts. After days of searching to answer a problem, I’ve managed to solve it by completely bypassing the preloader in Flex. It can be done, and here’s how:

Flex uses a 2-frame configuration to display its content. The Preloader is put on the first frame, and is downloaded immediately. It then waits for the rest of the content to load and fires its complete event. Then the SystemManager jumps to frame 2 and everything’s ready to go. To turn this off, we need to do two things:

1: Create a preloader shim file named PreloaderShim.as:

package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
 
	import mx.managers.SystemManager;
	import mx.preloaders.DownloadProgressBar;
 
	public class PreloaderShim extends DownloadProgressBar
	{
		private var delay:Timer = new Timer(1);
 
		override public function set preloader(value:Sprite):void
		{
			SystemManager(value.parent).gotoAndStop(2);
			delay.addEventListener(TimerEvent.TIMER, go);
			delay.start();
		}
 
		public function go(e:TimerEvent):void{
			delay.stop();
			delay.removeEventListener(TimerEvent.TIMER, go);
			delay = null;
			dispatchEvent(new Event(Event.COMPLETE));
		}
 
	}
}

2: Use this in our Flex file:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
				preloader="PreloaderShim">

We override the set preloader function of the DownloadProgressBar class. This is automatically set to the preloader instance in Flex. This instance’s parent is the SystemManager. The SystemManager has a gotoAndStop method that allows us to skip to the next frame. Almost immediately, we can fire the complete event. I think that Flex needs a single millisecond to begin its download process, so we wait that long before firing the complete. After that, Flex loads, no preloader perceived.

The Flex part is easy–just point your Flex project to have this new class as a preloader. Just drop your PreloaderShim.as file in with your mxml files and you’re off and running!

Note, I’ve only tried this on local files, and have NO idea how it would work in a real, downloading production file. It works fine for me, but please test it before you go breaking things.

Flash IDE CS4 crashes on any AS3 file close after profiling in Eclipse FlexBuilder 3

Recently I felt the need to work with the Flex Builder 3 Profiler. I found, as many OSX people do that the profiler didn’t work out of the box. I modified my mm.cfg file with the following line

PreloadSwf=/Users/mengel/Documents/workspace/.metadata/.plugins/
	com.adobe.flash.profiler/ProfilerAgent.swf?host=127.0.0.1&port=9999

This allowed the profiler to talk to pretty much every swf I load and was working great. What I didn’t know is that when you get your profiler working, it starts modifying your Flash Player preferences in a way that the Flash IDE may not like. It specifically added a folder:

/Users/mengel/Library/Preferences/Macromedia/Flash Player/#Security

This folder, coupled with my project settings, produced a configuration file that, every time I closed anything remotely AS3 related, crashed Flash, never to return. Since this is a bug in Flash player, uninstalling/reinstalling CS4 does nothing.
Even opening the projects panel and closing it breaks Flash as the IDE uses the player to display it. The solution is to remove the #security folder, drop your mm.cfg, and work without the profiler until you absolutely need it.

A friend of mine also tells me that the beta of FlashBuilder 4 may solve this problem as well. Your mileage may vary.

Adding a classpath to the Flash IDE using JSFL

MXP files can place classes most anywhere on the user’s computer, but in order to make Flash able to use them, you need to add the classpath to either the FLA or to the IDE. The IDE is preferable, in my opinion, since you only have to add it once and it works for all files. This is how you do that using JSFL.

MMExecute(
	"var found = false;" +
	"var paths = fl.as3PackagePaths.split(';');" +
	"for(var i = 0; i<paths.length; i++){" +
	"	if(paths[i] == '$(LocalData)/myClasses'){" +
	"		found=true;" +
	"	}" +
	"}" +
	"if(!found){" +
	"	paths.push('$(LocalData)/myClasses');" +
	"	fl.as3PackagePaths = paths.join(';');" +
	"}" );

What are we doing?

  • First, we set a variable to determine if we already have this classpath in our list (multiple classpaths of the same location can make Flash crash instantly)
  • Next, we take the semicolon-delimited string from fl.as3PackagePaths and assign it to an array variable.
  • Then we loop through this array looking for a match for our classpath. In my case, I’ve chosen to use a classpath variable, $(LocalData) that resolves to your Flash Configuration folder (Mac is /Users/UserName/Library/Application Support/Adobe/Flash CS4/en/Configuration)
  • If we find it, we set our found variable to true to indicate we shouldn’t add the path again.
  • Otherwise, we add the path to the array, convert it back to a string, and set the Flash IDE’s paths equal to it.

Getting Named Parameters for a Component in Flash using JSFL

When working with components, using JSFL, you can get access to the selected Component using

fl.getDocumentDOM().selection[0]

If your component has parameters, you should be able to access each parameter’s name attribute, but for some reason, there’s a bug in Flash. You can still get the parameters, but it takes a little doing.
The following script will return an array of parameters for the selected component.

var attribs:Array = MMExecute("var a = [];" +
	"for(var i  in fl.getDocumentDOM().selection[0].parameters){" +
	"	a.push(i);" +
	"}" +
	"a.splice(a.length/2).join(',')").split(",");

How does it work?
When you use the for…in feature on the parameters array, it returns double the results that it should, given the length attribute. For example, if you were to say

for(var i = 0; i< fl.getDocumentDOM().selection[0].parameters.length; i++)

you might get 11 results, whereas with this:

for(var i  in fl.getDocumentDOM().selection[0].parameters)

you'd get 22, the same results, followed by a list of names. It's as though there's another named value array tacked on to the results of the for...in. I've used this to produce a double length array, which I then chop off half and return a joined String.
We then parse this string back into an array and can move through it.

←Older