Monday, July 31, 2006

Mac FlexWeaver: Edit & Compile Flex Apps in Dreamweaver

Last Monday, I wrote about how you can configure Dreamweaver to edit and compile MXML. However, that method only works in Windows, since it uses some Windows-only (and undocumented) methods of the Dreamweaver Extensibility API.

It is a week later, and I have been busy brewing up a solution for us Mac users. One caveat at the outset: I'm on an Intel-based Mac, and so I haven't tested any of this on the Power PC architecture. This procedure requires Dreamweaver 8, and assumes that you have installed the Flex 2 SDK.

For your convenience, I have packaged the necessary files into a handy zip archive. You can download them here: http://labs.tom-lee.com/FlexWeaver/FlexWeaver.zip.

Installation

Opening the package, you'll see several folders. This section will tell you what they are, and where to put them.

  1. Commands - Contains the necessary files for two new Dreamweaver command extensions. Place the contents of this folder in Dreamweaver's "Commands" directory. (Dreamweaver 8:Configuration:Commands)

  2. DocumentTypes - This contains a copy of the file MMDocumentTypes.xml, which has been modified to allow Dreamweaver to treat MXML files like XML files instead of plain text. Place this in Dreamweaver 8:Configuration:DocumentTypes. Note: if you have already modified your MMDocumentTypes file for another purpose, don't overwrite it - instead, manually edit line 150 like so: <documenttype id="XML" writebyteordermark="false" file="Default.xml" macfileextension="xml,xsd,rss,rdf,dtd,vtm,vtml,csn,config,mxi,mxml" winfileextension="xml,xsd,rss,rdf,dtd,vtm,vtml,csn,config,mxi,mxml" internaltype="XML">

  3. Helper - Contains an AppleScript application called FlexCompileHelper.app. This bridges the gap between Dreamweaver and the Flex compiler, as I'll explain later. You can put this file anywhere you like.

  4. mxmlc - Contains a copy of the mxmlc shell script from the Flex 2 SDK which has been modified to allow support for spaces in filenames. Place this in flex_sdk_2:bin. Feel free to name this file something else if you don't wish to overwrite the one in the SDK.


Configuration

After you have copied the files to their proper locations, launch Dreamweaver. In the "Commands" menu, you should now see two new commands: Flex Compile, and Flex Preferences. Flex Preferences allows you to specify the location of the Flex compiler, the FlexCompileHelper app, and the output path for your SWF file, as well as any command line options you wish to use.

As you can (hopefully) see from the screen-shot, I have left the SWF Output Directory field blank. Since it is blank, SWFs will be placed in the same directory as their corresponding MXML files. Also, I have typed "-incremental=true" in the Additional Compiler Options field, to enable incremental compiling. When you click the "Save" button, a file called "FlexCompilerPreferences.txt" is created in your Dreamweaver configuration folder. This file merely stores all the values you enter into the Flex Compiler Preferences dialog.

Before we continue on, it would be a good idea to set MXML files to open in Dreamweaver. To do so, select an mxml file (you can find one in flex_sdk_2:samples) and go to File > Get Info in the Finder. Find where it says "Open With", select "Other" from the drop-down menu, and then browse to your Dreamweaver installation. Once you have Dreamweaver selected, you can click the "Change All" button to make all MXML files open in Dreamweaver.

Now it's time to compile something. Just open an MXML file in Dreamweaver, and select Commands > Flex Compile. This does a number of things:


  1. The Flex Compile command reads the Flex Compiler Preferences and creates a file on your hard drive called "FlexCompileJob.txt" in the same directory as the Flex Compile Helper application. This file contains 4 items: the path to the mxmlc shell script in the Flex 2 SDK, the path to the MXML file being compiled, the output path for the SWF, and any additional command-line options. Then, it launches the Flex Compile Helper application.

  2. The Flex Compile Helper application reads FlexCompileJob.txt, creates a command-line for the job, and passes it to the mxmlc shell script.

  3. When the mxmlc script returns its output, the Flex Compile Helper writes that output to a text file (FlexCompileOutput.txt) and instructs Dreamweaver to open that file.

  4. Flex Compile Helper instructs the Standalone Flash Player (located in the Flex 2 SDK) to open the SWF, and makes that window topmost.

This gives us the basic functionality to edit and preview a Flex 2 application from within Dreamweaver.

Error Checking

If the Flex Compile Preferences have not been set correctly, or an MXML file is not the active file in Dreamweaver, the Flex Compile command will not be available. Here is a list of the conditions under which Flex Compile will be grayed out:

  1. FlexCompilerPreferences.txt does not exist or is empty

  2. No compiler is specified, or the specified compiler does not exist

  3. No Flex Compile Helper app is specified, or the specified one does not exist

  4. No document is open

  5. The active document is not an MXML document


Further Explanation

This may seem like a lot of moving parts to achieve what should be a simple task. It was easier on Windows, thanks to the MM.createProcess command, which allowed me to call mxmlc directly from Dreamweaver and also catch its output. Unfortunately, this command does not work on the Mac. So, I had to create the AppleScript application which I could call with the more standard dreamweaver.openWithApp command. Since that command does not facilitate passing data to the application it's launching, I had to first write the necessary parameters into a text file which the application could then read.

I also spent a fair amount of time fighting with the mxmlc shell script, which choked on spaces in filenames. By default, it treats a space as an argument separator. If you open mxmlc in a text editor, and look at the last line, you will see this:
java $VMARGS -jar $FLEX_HOME/lib/mxmlc.jar $*
To fix it, I changed it to this:
java $VMARGS -jar $FLEX_HOME/lib/mxmlc.jar "$@"
For the exact reasons why, check out this page on bash scripting. I don't want to get into it right now, it kind of gives me a headache. With that line of code in there, you can escape any spaces in your filename by surrounding the filename in single quotes. FlexCompileHelper takes care of that for you, but if you put any file paths in the Additional Compiler Options field, you'll need to take that into account.

By the way, if you want to see what's in FlexCompileHelper.app, feel free to open it up. I have not protected the contents from being decompiled, so you should be able to see it in Script Editor.

Conclusion

Well, that's it for now. Can this be improved upon? You betcha. This meets my needs for now though, so I probably won't spend too much more time on it. If you have a suggestion on how to streamline this puppy, I'm all ears. I'm kind of intrigued by the fact that even Dreamweaver's code hinting is extensible. I may take on the challenge of adding code hinting to FlexWeaver, but if I do, it won't be for a while. Enjoy, and let me know if you have questions or comments.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

JD on Blog Transparency

I was midway through a comment on John Dowdell's post regarding Ryans Stewart's post regarding Steve Rubel's post regarding the "Underground Blogosphere".... when I realized I was going a bit long, and should probably just blog it myself.

After reading Ryan's article on Friday, I gave the topic a "background process" in my brain, and I must confess it hasn't returned much. What I've got is this: who cares if bloggers email each other to pitch their stories, and why? I care, for the reason that I wish the most popular, easy to find blog posts were the ones with the most valuable content - as opposed to the ones with the best promotion. But what's to be done? The reality is, blogs get popular for lots of reasons - the author holds a position of prominence or is well-connected, the posts are inflammatory or invite controversy, the author advertises their blog like crazy, the content is of a high value to its audience, etc. Not to mention that if you are blogging, you probably want people to read it, and so you will no doubt take steps to increase your readership. It stands to reason that those who have popular blogs have made an effort to achieve that popularity (sorta like how the more powerful a politician is, the more power-hungry they likely had to be to achieve their position).

Now, if you rely on blogs to be accurate, then you probably care a lot more deeply about this issue than I do, and you really need to understand what a blogger's motivations might be. I personally don't rely on anything to be accurate: not the mainstream press, not the alternative press, and CERTAINLY not the blogosphere.

I guess I'm ultimately just stating the obvious: no matter where your information comes from, how it was promoted, or who authored it, you must make your own judgement as to its validity. Does the fact that an article was promoted via social connections (or even begging for a link) make it less valid for you? If it's something you really care deeply about, believe only your own senses.

As for the RIA bit - I suspect that if RIA-related blog posts aren't getting picked up outside of MXNA and the Goog, it's because the blogosphere at large just isn't as interested in RIAs as the MXNA crowd. I'm always a little surprised when I brag to one of my web developer cohorts about something I'm working on and I get that blank stare... I'm lucky enough to have some very honest friends who have on occasion come out and said "Ok, that's cool and all, but why would you ever want to do that?". I do think there will come a time when rich UI is expected and even demanded, and then those people will get it. But for now, people who are into Flex and so forth may be a but ahead of the curve.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

Monday, July 24, 2006

Edit and Compile Flex Apps in Dreamweaver

In what I think is a brilliant move by Adobe, the Flex 2 SDK and Flex 2 Framework are available for FREE. This is nothing new, but it's worth restating (it seems that a lot of people don't know it yet). I intend to make take full advantage of that fact until such time as I can afford Flex Builder. That's not to say that Flex Builder is unaffordable: quite the contrary. However, I also have to have licenses for Flash, Dreamweaver, Photoshop, and Illustrator. So for me, an extra $500 is substantial.

I actually see not having access to Flex Builder as an opportunity to learn. Like many, I learned HTML by hand-coding in Notepad, and it made me REALLY learn HTML. I think that not using Flex Builder will force me to learn the behind-the-scenes stuff, and therefore will end up being a positive thing. When I do buy the Builder license, I'll have a strong understanding of what's going on under the hood, as well as the conveniences of the Design view and robust code hinting.

Configuring Dreamweaver

Since I already have Dreamweaver, I'll use that as my XML editor. It's really easy to associate MXML files with Dreamweaver, and with a little configuration, you can take advantage of Dreamweaver's XML syntax highlighting. Here's how to do it in Windows:




1) Download the Flex 2 SDK from http://www.adobe.com/products/flex (the link is at the bottom of the page). Install the SDK by unzipping it to the directory of your choice. I put mine in the root of my C drive.

2) Associate MXML files with Dreamweaver. To do so, right-click a file with a .mxml extension, and click Properties. In the Properties dialog, find where it says "Opens with:" and click the "Change" button. Select "Dreamweaver" from the resulting menu. If you don't have any .mxml files yet, you can find one in C:\flex_2_sdk\Samples.

3) Enable XML syntax highlighting for .mxml files. For this, you need to edit one of Dreamweaver's configuration files. The specific file is called MMDocumentTypes.xml, and is located at C:\Program Files\Macromedia\Dreamweaver 8\Configuration\DocumentTypes. You can edit this with Dreamweaver. Find the tag and add "mxml" to the list of extensions in the "winfileextension" parameter. Save the file, and restart Dreamweaver.


At this point, you should be able to double-click an MXML file and have it open in Dreamweaver, complete with syntax highlighting. Now that's all well and good, but how do we compile it? The command-line compiler that comes with the SDK is fine, but typing commands over and over again when I want to build is not my idea of a good time. Wouldn't it be swell if you could compile from Dreamweaver?

Creating a Command to Compile MXML

Yup! Thanks to Dreamweaver's robust extensibility API, it's pretty easy to write a command that will compile the active MXML document and launch the resulting SWF in the stand-alone player. Here's how it's done:

1) Create a new JS file and put the following code in it:

// Compile mxml file from Dreamweaver

function flexCompile(){

var currentDocURL = dreamweaver.getDocumentPath("document");
var i = currentDocURL.lastIndexOf("/");

var parentDirectoryURL = currentDocURL.substring(0,i+1);
var fileNameURL = currentDocURL.substring(0,currentDocURL.lastIndexOf("."));

var parentDirectory = MMNotes.localURLToFilePath(parentDirectoryURL);
var fileName = MMNotes.localURLToFilePath(fileNameURL);

var currentDocFile = MMNotes.localURLToFilePath(currentDocURL);
if(!currentDocFile){
alert("You must have an mxml document open to compile.");
}else{
MM.createProcess('', 'C:\\flex_sdk_2\\bin\\mxmlc.exe "'+currentDocFile+'" -output "'+fileName+'.swf"', -1, true, parentDirectory ,parentDirectory+'flex-compiler-output.txt');
dreamweaver.openWithApp(fileNameURL+'.swf','file:///C:/flex_sdk_2/player/debug/SAFlashPlayer.exe');
}
}

function canAcceptCommand(){
return dreamweaver.getDocumentPath("document").indexOf(".mxml") != -1;
}



2) Create a new HTML file, and put the following code in it:

<!DOCTYPE HTML SYSTEM "-//Macromedia//DWExtension layout-engine 5.0//
dialog">
<HTML>
<HEAD>
<Title>Flex Compile</Title>
<SCRIPT SRC="Flex Compile.js"></SCRIPT>

</HEAD>
<body onLoad="flexCompile()">
</body>
</HTML>

3) Save these to Dreamweaver's "Commands" folder (C:\Program Files\Macromedia\Dreamweaver 8\Configuration\Commands) as Flex Compile.js and Flex Compile.htm, respectively.


4) Restart Dreamweaver. You should now have a new item in the "Commands" menu called "Flex Compile" which will compile the active MXML document with the Flex 2 compiler, launch it in the standalone player, and save a text file of the compiler output.

How It Works

When you click the Flex Compile menu option, Flex Compile.htm is loaded, and its body.onload function is called, which is our flexCompile function. First, a few useful variables are set. We get the file path of the active document using dreamweaver.getDocumentPath("document"), which returns the location of the active document as a URL. Then we can get the URL of the parent directory by taking a substring of the currentDocURL - everything before and including the last "/" character. Now for these to be useful to us, we must convert them to file paths. To do this, we call MMNotes.localURLToFilePath(), which is part of the Design Notes API. This function changes the syntax of the file path from URL syntax ('file:///C:/directory/filename.xxx') to file path syntax ('C:\directory\filename.xxx') .

Next comes the real magic, an undocumented command called MM.createProcess(), which I found at http://www.communitymx.com/blog/index.cfm?newsid=179&blogger=35. This allows us to send a command to the compiler without opening it in a command-line window, and it can also be configured to make Dreamweaver wait while the compiling takes place. Note that in my command, I have hard-coded the path to the compiler. If you want to keep the Flex 2 SDK anywhere other than C:\flex_2_sdk, you will have to update the JS file. Also note that in MM.createProcess, the backslashes have to be escaped.

I have configured this command to put the SWF output in the same directory as the mxml file. MM.createProcess also optionally sends the output of the process to a text file, which I have opted for in this command. It will create a text file called 'flex-compiler-output.txt' in the same directory as your mxml file.

Next, I call dreamweaver.openWithApp to launch the SWF in the standalone player. Again, I have hard-coded the path to the Flex 2 SDK.

The function canAcceptCommand() simply ensures that the command is grayed out unless an MXML document is the active document in Dreamweaver.

Conclusion

I believe this setup has a great deal of potential as a basic Flex 2 workflow. One could easily imagine a more configurable version of the Flex Compile command where you could specify the path for the SWF output, or the path to the Flex 2 SDK. What I was going for with this command was to mimic the functionality of Preview in the Flash IDE, so that as I make edits to the MXML I can easily see the results of my changes. Ultimately, this makes up for the lack of a design view, which is one of the great benefits of Flex Builder.

Since I would prefer to work on my Mac, I am creating a Mac version of this command. It will probably have to rely on a shell script or AppleScript to achieve similar functionality since MM.createProcess (and its friends) do not work on the Mac. There is some promise with the undocumented dw.runAppleScript() command, but it does not appear to work on my MacTel.

On the XML-editing side of things, I will probably explore creating an MXML file template for Dreamweaver, as well as rudimentary code-completion. Thanks to Dreamweaver's robust extensibility, I will be able to efficiently create Flex applications without buying Builder, and learning a lot in the process.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

Sunday, July 23, 2006

Flex 2 Compiler (mxmlc) on OS X - No Spaces in Filenames

The Mac version of mxmlc that ships with the Flex 2 SDK does not support spaces in filenames, or so it seems. This is inconvenient to say the least, since the default name of your hard drive on OS X systems is "Macintosh HD". If you have a space in your filename, mxmlc can't find the file - it thinks that the full path to the file is the part after the last space. I'm presently seeking a workaround, but no amount of escape sequences or quotes seems to help.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

Monday, July 17, 2006

IE CSS Rollover Cache Bug

Basically, the bug is that if you use CSS for image rollovers (by giving a hyperlink a background-image and changing it with the :hover selector), Internet Explorer will (in most circumstances) check the server for a newer version of the image every time a user mouses over your hyperlink. This can merely look bad (it causes the image to flicker) or it can present real usability problems. The seldom-mentioned side effect is that when a user clicks the hyperlink, the IE 'loading' animation (or 'spinner' as some like to call it - that wavy window animation in the upper right corner) will stop as soon as the user mouses off of the hyperlink, making it seem as though the page load has completed. If you are using the hyperlink to submit a form, the user may click the button multiple times.

Seems like every time I run into this bug, I've forgotten where to find the relevant discussion, so....

Here's a solution on Css-Discuss that involves manipulating Vary headers server-side. Also, a discussion on Mezzoblue that seems to be a good general doorway into the topic. If you use Pixy's No-Preload rollovers, check out the bottom of this page for a client-side solution which may involve extra markup. This article at www.fivesevensix.com seems to be the most comprehensive write-up on the subject. Got any others?

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

Sunday, July 16, 2006

Using Subversion w/ Eclipse

Another 'saving this link for later' post. IBM has a great article on using Subversion with Eclipse, complete with pictures:
http://www-128.ibm.com/developerworks/opensource/library/os-ecl-subversion/?ca=dgr-jw22EclipseSubversion

Getting up to speed on Subversion is on my to-do list. This will no doubt come in handy when the tiime comes.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

Saturday, July 15, 2006

Things Never Taught In Design School

Michael McDonough’s Top Ten Things They Never Taught Me in Design School - Design Observer article by way of John Dowdell. I really like this one and don't want to lose it, so am posting it here.

My particular favorite: show me the output! It's not enough to have an idea, you must also make it manifest (working on that as a bit of self-development, actually). Many people have ideas, few actually make something of them.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

All FOUCed Up

I recently ran across a problem with CSS where IE would momentarily display unstyled content until the external stylesheets loaded. This bug is called "Flash of Unstyled Content" or "FOUC", and is documented here:

http://www.bluerobot.com/web/css/fouc.asp

This can happen if you reference your external stylesheets using @import. The fix is to use at least one link element or one script element in the head of your document. An interesting wrinkle: the link element or script element can be completely empty.

The reason I'd never encountered it before is that I never had created a page which did not use either a link element or a script element in the head element. You see, I developed a habit over the years where I specify a print media stylesheet using a link element and then include other stylesheets with the @import statement, which prevents them from being loaded by IE 3 and NS 3.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

Friday, July 14, 2006

JamJar, Flex 2 - A Little Worried

So Flash Player 9 and Flex 2 are both available now, and I finally have the chance to show off what they can do. I've been bragging up Flex 2 to all of my colleagues, many of whom simply don't get the Flash Platform at all. I'm hearing great things about the JamJar demo, and it sound like a perfect app to show off the power of Flex. Except that when I run it, I get this:

ReferenceError: Error #1069: Property hasDefinition not found on
flash.system.ApplicationDomain and there is no default value. at
mx.managers::SystemManager/getDefinitionByName() at
mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::addingChild() at
mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::rawChildren_addChildAt() at
mx.managers::SystemChildrenList/addChild() at
mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::initialize() at
mx.managers::SystemManager/::initHandler()


I have a "Dismiss All" button and a "Continue" button, both of which yield the same result: a lovely blue-green screen with a nice gradient (you know, the standard Flex background). That's it.

I updated my Flash Player, but that's all I can think of to do... I've been a Flash developer for years, and I am at a total loss. Imagine when the average user comes up against one of these error boxes!

I knew AS3 would not fail silently, and I've always had a feeling that was a bad idea. But, I guess I just figured I'd get my code 100% right. But if the Flex team can't get it right, what chance do I have?

I've got a feeling there's more going on than buggy code. Maybe my Flash player didn't update itself correctly - that would be a bad thing too. I really want the Flex platform to succeed (I want to make a living at it!), but if this kind of user experience becomes common, it will only give ammunition to the anti-Flash crowd and make it a tougher sell.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

Tuesday, July 11, 2006

ExternalInterface Out Of Memory Error

With the release of Flash Player 9, one of the web sites for which I am responsible began throwing "out of memory" errors in Internet Explorer. This happened when a user would navigate away from the page. Stepping into the debugger revealed the following problematic code:


function __flash_unloadHandler() {
mySwf.style.display = 'none';
for (var prop in mySwf) {
if (typeof(mySwf[prop]) == "function") {
mySwf[prop]=null;
}
}
if (__flash_savedUnloadHandler != null) {
__flash_savedUnloadHandler();
}
}


function __flash_setupUnloadHandler() {
if (window.onunload != __flash_unloadHandler) {
__flash_savedUnloadHandler = window.onunload;
window.onunload = __flash_unloadHandler;
}
}


__flash_setupUnloadHandler();


My first reaction was "Whaa? I didn't write any of that code", but then I remembered this neat little article by Brad Neuberg showing how the Flash Player uses JavaScript methods for serializing incoming ExternalInterface calls. So, my problem was related to ExternalInterface.

A quick search for "ExternalInterface out of memory error" yielded the following Flashcoders discussion: http://chattyfig.figleaf.com/pipermail/flashcoders/2006-July/168998.html. So I was not alone, and it seems the issue is related to having multiple swfs using ExternalInterface on one page.

(The same search also turned up this page, where Geoff Stearns talks about fixing problems with audio streams and SWFObject. The code which fixes Geoff's issue looks mighty familiar when I look at my debugger.)

The part where IE gets stuck is in executing __flash_savedUnloadHandler(); At first glance it looks to me like __flash_savedUnloadHandler() would be executed for every swf you have embedded in your page. In the Flashcoders thread I referred to earlier, Alexis Glass suggests the problem may be related to the fact that the unload handler is saved in a global variable:
...it saves the previous unload handler in a global variable so that if
ExternalInterface is initialized twice on one page it recursively calls the
__flash_savedUnloadHandler until IE complains about no memory.

It may be possible to override the faulty JavaScript, but I don't want to go down that road for fear it will break with a future release. So, I will have to revert back to good ol' FSCommand and getURL for the time being. Yuk. Anybody got something better for me?

As an aside, in my research I also came across John Dowdell's response to Brad Neuberg's original article. I know it's a bit dated now, but the ensuing comments are interesting, because John seems to be focused on the context of Brad's usage of ExternalInterface, whereas Brad seems to be offering the exact points of failure. It seems that John is saying "You're out of scope, the point is moot" while Brad is saying "My personal scope of use is not important, here are in-scope examples of how ExternalInterface is broken". I encountered the same "perspective gap" when dealing with Macromedia's customer support folks a few years ago. They seem to be trained to focus on the context in which you are using the functionality, so they can offer alternate means to your particular end. But that can be frustrating when you are trying to present a unit test which is failing for no particular reason, and they are preoccupied with the question of why you want to do it in the first place.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

Monday, July 10, 2006

Flash Player 7 String Parsing Performance

I just came across the following in my notes from last year, thought it was worth saving:

When performing String parse operations, the presence of characters above the ASCII 128 character range can slow the parsing significantly. In my case, I was applying String.toLowerCase on a 45000 character string, and it was taking 2.5 seconds. Removing the characters above character code 128 reduced the execution time to just 2 milliseconds.

I have no idea if this applies to Flash Player 8 or 9, but I have a feeling I'll be checking into it soon.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.

Saturday, July 01, 2006

IE 5 currentStyle.display bug

In IE 5, Element.currentStyle.display will return "inline" for block elements that do not have a display property explicitly set. This was corrected in IE5.5. There is no known workaround.

Test page here.

Was this post helpful to you? If so, please consider making a small donation to keep this blog going.