Flex MXML ArrayCollection cannot ObjectUtil.compare

The ObjectUtil Class has lots of fun things in it that can make your life easier. When I needed to check to see if an ArrayCollection had changed, I thought to myself, why not use ObjectUtil.compare? Turns out that no matter what you do, every ArrayCollection is unique because they produce a UID parameter in every ArrayCollection instance that differentiates it. What’s the purpose of this? I have no idea, but someone thought it was a good idea.

Sadly, I did not find a solution to this problem, so I ended up using an Array instead of an ArrayCollection.

Determine Goal Width and Height in Image Resizing

I find myself doing image manipulation on a regular basis. One of the common things I have to do is to fit an image into a max width or height. I’ve distilled this as best I can, and I think this is as simple as it gets. It’s in PHP, but the logic should be applicable to any language.

$max_size=200;
$ratio = $image_width/$image_height;
if($ratio>1)
{
	$goal_width = $max_size;
	$goal_height = $max_size/$ratio;
}
else
{
	$goal_width = $max_size*$ratio;
	$goal_height = $max_size;
}

Making a ComboBox only show ToolTips for Long Items

I had a Flex Combobox that had contents too big to fit, but when I made it shorter to fit, the items would be cut off. There’s a brilliant solution on the FlexExamples site that handles it so:

<mx:ComboBox id="projectComboBox"
             dataProvider="{projectList}"
             maxWidth="400"
             itemRenderer="mx.controls.Label"/>

All this does is specify the use of a label control as the TextField in the ComboBox. Since Labels are made to truncate then produce tooltips automatically, this is amazingly simple.

Coding for Understandability

Often I have a number of options in how to code a particular piece of functionality. I’m constantly balancing between brevity, simplicity, speed, size, and readability. I often find that if I put a little more focus on simplicity and readability, I save myself time and headaches, in addition to making my code more readable, more object oriented, and more accessible to other coders.

I’m going to provide some examples in ECMAScript, but I know that similar problems exist in other languages, as well.

I recently ran across some code that was coded for brevity:

var userdefined:Object = (_model.partner || {}).userdefined || {},
bsb:BannerShownBeacon = new BannerShownBeacon(
	userdefined.dims 
		? userdefined.dims
		: userdefined.width && userdefined.height
			? userdefined.width + 'x' + userdefined.height
			: 'fixed_bottom'
)
;

Now, this is fully valid, well-written code, and it’s also tabbed and line-broken for readability, but what exactly is it doing? What is the purpose of this code?

The difficulty I find is that when someone is trying to determine whether their particular implementation is going to be executed — lets say we have dims, width, and height in our userdefined param, and we’re looking at this the first time. Since coding standards aren’t set for how to structure ? : style if statements, it’s difficult to go through this by instinct and take a guess at what it’s doing. Every language has if/else statements and most coders are intimately familiar with them.

First, we look to see if _model.partner exists and if it doesn’t, we create it, then we check to see if _model.partner.userdefined exists and if not, we create it and assign that to a variable.
Then, we create a second variable called bsb that expects a BannerShownBeacon;
If userdefined has a dims param, we use it, otherwise, we check if it has width and height params, and if it does, we combine them with an x in between, otherwise, we just use the term “fixed_bottom” and make a BannerShownBeacon out of that.

The final option is to include large amounts of comments (which is excellent for non-compiled languages like JS), but in compiled languages, this often doesn’t save any time or lines of code.

I’ve rewritten this here using if/else statements

var bsbText:String = "fixed_bottom";
if(_model.hasOwnProperty("partner"))
{
	if(_model.partner.hasOwnProperty("userdefined"))
	{
		var userdefined:Object = _model.partner.userdefined;
		if(userdefined.hasOwnProperty("dims"))
		{
			bsbText = userdefined.dims;
		}
		else if(userdefined.hasOwnProperty("width") && userdefined.hasOwnProperty("height"))
		{
			bsbText = userdefined.width + "x" + userdefined.height;
		}
	}
}
var bsb:BannerShownBeacon = new BannerShownBeacon(bsbText);

Cannot Trace using Debugger on OSX

Oh good lord, all I wanted to do was trace the output of my flash debug player, yet there was nothing in the usual location. Typically I just run

tail -f ~/Library/Preferences/Macromedia/Flash\ Player/Logs/flashlog.txt

in the Terminal and it spits out everything Flash does. The file didn’t exist on my system, so I couldn’t tail it. The solution turned out to be a missing mm.cfg file.
in ~/Library/Application\ Support/, produce a mm.cfg file with the following content:

TraceOutputFileEnable=1
ErrorReportingEnable=1

This, along with a correct debugger, should produce traces.

Using Flash’s Date Class in AMF PHP to MySQL

So you’re trying to rectify your dates, eh? Here’s a little funbit. If you want to take a Flash Date, transfer it to AMF, convert it to a PHP date, then insert that into a MySQL database as a DATETIME, you’re in for one hell of a headache. How does flash store it’s date class anyway? How can PHP read it? What about that whole milliseconds to seconds thing? No worries, my friends, I have a solutions for you.

Actionscript:

var d:Date = new Date()

This creates a new date. This can then be passed to AMF using whatever means you feel work best. I’m using a codeigniter port with AMF as the model that was built by my pal, Steve.

PHP to make a DATE in MySQL:
I have passed in an FP object that contains my Date object.

$date = $fp['d']/1000;
$date = date("Y-m-d","$date");

This will output your date as something like 2010-10-18. You can modify the output to be anything you like, such as:
How does it work? Flash automatically encodes Dates as the number of milliseconds since the Unix Epoch. This means that to convert it to the typical date structure in PHP, you have to convert it to seconds, which involves division by 1000. From there we can turn it into a date, but it has to be turned into a string, hence the quotes.

$date = $fp['d']/1000;
$date = date("Y-m-d H:i:s","$date");

This would give you something like 2010-10-18 15:45:30
This number can be used to insert into or compare against MySQL DATETIME entries.

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("/");
}

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.