Feeds:
Posts
Comments

XML support in ActionScript is actually quite nice (though it’s a bit creepy to see raw XML inserted straight into the code). The whole E4X thing takes some getting used to, but in general everything just works surprisingly well. Except for deleting. That just doesn’t work at all like you’d expect. Consider the following ActionScript code:

var xml:XML = <foo>
<bar id=”1″/>
</bar>
<bar id=”2″/>
</foo>;

That’s right, you can just assign XML straight to a variable. Wiggy, right? Anway, so the operations are a little weird, but not too bad. trace( xml ) spits out the entire <foo> tree in well-formatted XML to the log file, as you’d expect. trace( xml.bar ) outputs the all the <bar> elements as an array, so that’s sorta reasonable. trace( xml.bar.(@id==1) ) starts to get trippy, as the dot before the parenthesis isn’t a typo but rather an E4X selector of all children of bar with an “id” equal to 1. Anyway, all this is spelled out in way more detail in the docs.

So hard-coding XML is incredibly easy, and accessing it is weird but pretty easy too. It also turns out that adding more nodes to the tree is really easy: just assign some node to a variable, and then call appendChild(). Duh, what could be easier?

var child:XML = xml.bar[0]; // xml.bar is an array, we want the first one
var grandChild:XML = <blah>; // That’s right, this is valid
child.appendChild( grandChild );

Ok, so we’ve hard coded some XML, we’ve added some nodes, now all we need to do is remove it. Everything else has been easy, this should be too, right? Wrong. At least for me, deleting nodes from an XML tree was really non-intuitive. Here’s what I assumed I could do:

child.removeChild( grandChild );

I mean, we could add it that way, why not remove it? Nope! Doesn’t work that way. That function doesn’t exist. Ok, that’s fine you think — we still have a reference to grandChild; let’s just delete that:

delete grandChild;

Nope, that doesn’t work either — you get this message “Error: Attempt to delete the fixed property grandChild. Only dynamically defined properties can be deleted.” I’m not entirely sure what that means, but it sounds bad. Maybe it’s because grandChild is just defined with a constant XML object that screws it up? Ok, let’s get a reference to grandchild and then try to delete that. How to get the reference? Well, you might notice that appendChild() returns an XML object. And you might think that means it returns a reference to the new XML object it just allocated. That would mean you could do this:

var appended:XML = child.appendChild( grandChild );
delete appended;

Alas, that doesn’t work. “appended” in this example is just set equal to “child”, for no reason I can surmise. In other words, there’s no easy way to get a reference to the thing you just created. You’ve got to turn to the black arts of E4X to dig it out:

var grandChild:XML = <blah>;
child.appendChild( grandChild );
var appended:XML = child.blah[ child.blah.length()-1 ]; // The last one is the one we appended
delete appended;

So, append grandChild to child, then get a reference to appended, and then just delete appended, right? Wrong! You get that same mysterious “Attempt to delete the fixed property” compile error as before. Hrm. Ok, so how the hell do we delete something? Turns out, the only way (that I can find) is to use more E4X magic, this time in conjunction with a special “delete” operator:

delete child.blah[ child.blah.length()-1 ];

So, you can use references to XML elements to query them and add children, but you need E4X in order to delete them. Now, in the above example you might be thinking “why do the whole “length-1″ bit — why not just use “blah[0]“? The answer is “because generally you don’t know how many children are already there and thus need to find the last one”. Which brings up a really, really excellent question: how do you delete an item from the *middle* of a child list. So glad you asked!

Well, if you know its index, then you can just delete it with the array operator (eg, “delete child.blah[2];”). But if you don’t know its index, then you need to give it an attribute (child.blah[2].@id=1337;) and then delete using that attribute (delete child.blah.(@id==1337);). All in all, it sorta makes sense now that I know it, but it sure wasn’t an intuitive leap to get from there to here. Anyway, that’s my learning process, I hope it helped you through yours. Here’s some test code, as well as the output it generates:

var xml:XML = <foo>
<bar id=”1″/>
<bar id=”2″/>
</foo>;
trace( “—- xml —-” );
trace( xml );
trace( “—- xml.bar —-” );
trace( xml.bar );
trace( “—- xml.bar.(@id==1) —-” );
trace( xml.bar.(@id==1).toXMLString() );
trace( “—- before append —” );
var child:XML = xml.bar[0];
trace( child.toXMLString() );
trace( “—- after append —-” );
var grandChild:XML = <blah/>
child.appendChild( grandChild );
trace( child.toXMLString() );
trace( “—- after delete —-” );
delete child.blah[ child.blah.length()-1 ];
trace( child.toXMLString() );

—- xml —-
<foo>
<bar id=”1″/>
<bar id=”2″/>
</foo>
—- xml.bar —-
<bar id=”1″/>
<bar id=”2″/>
—- xml.bar.(@id==1) —-
<bar id=”1″/>
—- before append —
<bar id=”1″/>
—- after append —-
<bar id=”1″>
<blah/>
</bar>
—- after delete —-
<bar id=”1″/>

PS: The “toXMLString()” is needed because if you don’t use it, then trace() outputs nothing for XML nodes that have no children (even if they have attributes). Strange, but true.

So I am capturing global keypress events, and I want to suppress my action if some component has focus.  A quick read of the docs and the FocusManager class looks like the ticket!  More specifically, FocusManager::getFocus() looks like exactly the function I need.  So I go ahead and call it, only to find it’s not static — I can only call it on a FocusManager object.  Which brings to mind: how do I find one?  After a bit of searching, I see some sample code that just refers to a variable “focusManager”.  I don’t see it defined in the same, so I assume it’s some magic global — I drop that into my code, and it works!

So if you want a global FocusManager, just try “focusManager” and see if that works for you.

Why does that work?  Well, after a bit more thought, I consider: Perhaps focusManager is an attribute on the Application class?   And maybe the keypress handler function I’m writing in the <mx:script> section of my MXML file is actually a method extending the Application class, meaning all the Application protected attributes are accessible in my function?  A quick look at the Application docs, and sure enough, that’s the case.  Cool!

That’s right, it needs to be capitalized.  How lame is that?

Enabling Trace

If you’re like me, you love logfiles. So you see the “trace” command and think “Sweet! I can log!” But then, if you’re like me, your hopes are dashed as nothing actually happens. Well, it’s probably due to one of two reasons:

  1. You don’t have the debug version of the Flash player installed
  2. You haven’t activated logging

Here’s how you achieve this state of logging nirvana:

  1. Go to the Flash debug player install page and install the relevant debug player for your platform. If you’re lucky enough to be a Linux user, you can enjoy the following additional steps: download the Linux Flash Player, find the file and run “tar xvfz flash_player_9_linux_dev.tar.gz”, then run “tar xvf install_flash_player_9_linux.tar.gz”, and then run “./flashplayer-installer”, and then delete “.mozilla/firefox/z270avvr.default/xpti.dat”. Easy!
  2. Go to the Debug Flash Player Configuration Page and create your mm.cfg file (in ~/mm.cfg for Linux) containing:
    ErrorReportingEnable=1
    MaxWarnings=0
    TraceOutputFileEnable=1
  3. Restart Firefox and it should start spitting out logs into the logfile location stated on the page (~/.macromedia/Flash_Player/Logs/flashlog.txt for Linux)

So… not *quite* as easy as a checkbox somewhere, but not horrendous. But there is a slight problem with this: it, basically, doesn’t work. Or, it only sorta works — I have to keep deleting the flashlog.txt file or nothing happens… I’m still sorting it out. Fun!

[Update] Aha, that’s the story: it’s working fine, but it deletes and remakes the logfile every time.  Sorta annoying, but you can get around this with “tail –follow=name flashlog.txt”.  This will tail the file like “tail -f”, but will reload it if it gets deleted.

After much consternation, I’ve discovered that the Java runtime that comes with Ubuntu 7.10 just doesn’t quite cut it for MXML compilation.  Specifically, MXMLC pegs the CPU to 100% and eats up all available RAM — both physical and virtual — until your system grinds to a halt.  The solution, thankfully, is easy enough: just install the “real” JRE that comes with the Java 6 JDK, and welcome back to the sweet land of sunshine.

Aha, Bindable

So that’s what it’s for: if you specify that an attribute of an object is “bindable”, then the UI automatically updates when it changes. (Or, more specifically, it generates a “propertyChanged” event, which is picked up by the MX framework to update.) Very handy!

Whoever invented the Flash security model is an idiot that should be shunned from society. I’m too tired and frustrated to make the complete argument, but here are some tips:

  1. If the web service you want to access is on HTTPS, you need to host the SWF on HTTPS too.
  2. The most permissive crossdomain.xml I can figure out how to write is:
    <?xml version=”1.0″ encoding=”UTF-8″?>
    <cross-domain-policy xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:noNamespaceSchemaLocation=”http://www.adobe.com/xml/schemas/PolicyFile.xsd”>
    <allow-access-from domain=”*”/>
    <site-control permitted-cross-domain-policies=”all”/>
    </cross-domain-policy>
  3. When hosting crossdomain.xml, set “Content-Type” to “text/x-cross-domain-policy”
  4. Just to be safe, also set “X-Permitted-Cross-Domain-Policies” to “all”
  5. And set “X-Just-Fucking-Work-Please-Goddamn-You” to “true”. That’s crucial.

After that, it probably still won’t work for you. You can read this extremely long and boring document here:

http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security.html

But don’t bother, because it manages to say utterly fucking nothing in the longest way possible. For more futility, enable Flash logging with the convenient 1842-step process documented here:

http://livedocs.adobe.com/flex/201/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=logging_125_04.html

If that isn’t inscrutable enough for you, dial up the pain by enable policy file logging (that’s right, let’s give it its own logfile, brilliant!) here:

http://www.adobe.com/devnet/flashplayer/articles/fplayer9_security_05.html

Then you too can experience the joy of total confusion and anger at the most retarded security model ever invented.

Follow

Get every new post delivered to your Inbox.