Determining local timezone in ActionScript (AIR, Flex, AS3)

I made a little utility class that determines the local timezone (PST, EST, MST, CST, etc.). The guts of the utility are three methods, one for determining if the local machine is currently observing daylight savings time, another determines the GMT time from the the local machines current Date, and one for looking up the timezone abbreviation by GMT time. This is sort of a conglomerate of code that I could find on different posts and leveraged them to achieve my own goals.

Determining if the daylight savings time is currently being observed.

**
* Determines if local computer is observing daylight savings time for US and London.
* */
public static function isObservingDTS():Boolean
{
     var winter:Date = new Date(2011, 01, 01); // after daylight savings time ends
     var summer:Date = new Date(2011, 07, 01); // during daylight savings time
     var now:Date = new Date();

     var winterOffset:Number = winter.getTimezoneOffset();
     var summerOffset:Number = summer.getTimezoneOffset();
     var nowOffset:Number = now.getTimezoneOffset();

     if((nowOffset == summerOffset) && (nowOffset != winterOffset)) {
          return true;
     } else {
          return false;
     }
}

Creating the GMT from a Date object and adjusting for daylight savings time.

/**
* Method to build GMT from date and timezone offset and accounting for daylight savings.
*
* Originally code befor modifications:
* http://flexoop.com/2008/12/flex-date-utils-date-and-time-format-part-i/
* */
private static function buildTimeZoneDesignation( date:Date, dts:Boolean ):String
{
     if ( !date ) {
          return "";
     }

     var timeZoneAsString:String = "GMT";
     var timeZoneOffset:Number;

     // timezoneoffset is the number that needs to be added to the local time to get to GMT, so
     // a positive number would actually be GMT -X hours
     if ( date.getTimezoneOffset() / 60 > 0 && date.getTimezoneOffset() / 60 < 10 ) {
          timeZoneOffset = (dts)? ( date.getTimezoneOffset() / 60 ):( date.getTimezoneOffset() / 60 - 1 );
          timeZoneAsString += "-0" + timeZoneOffset.toString();
     } else if ( date.getTimezoneOffset() < 0 && date.timezoneOffset / 60 > -10 ) {
          timeZoneOffset = (dts)? ( date.getTimezoneOffset() / 60 ):( date.getTimezoneOffset() / 60 + 1 );
          timeZoneAsString += "+0" + ( -1 * timeZoneOffset ).toString();
     } else {
          timeZoneAsString += "+00";
     }

     // add zeros to match standard format
     timeZoneAsString += "00";
     return timeZoneAsString;
}

Finally, parsing the abbreviation from a simple lookup Array object.

/**
* List of timezone abbreviations and matching GMT times.
* Modified form original code at:
* http://blog.flexexamples.com/2009/07/27/parsing-dates-with-timezones-in-flex/
* */
private static var timeZoneAbbreviations:Array = [
     /* Hawaii-Aleutian Standard/Daylight Time */
     {abbr:"HAST", zone:"GMT-1000"},
     {abbr:"HADT", zone:"GMT-0900"},
     /* Alaska Standard/Daylight Time */
     {abbr:"AKST", zone:"GMT-0900"},
     {abbr:"ASDT", zone:"GMT-0800"},
     /* Pacific Standard/Daylight Time */
     {abbr:"PST", zone:"GMT-0800"},
     {abbr:"PDT", zone:"GMT-0700"},
     /* Mountain Standard/Daylight Time */
     {abbr:"MST", zone:"GMT-0700"},
     {abbr:"MDT", zone:"GMT-0600"},
     /* Central Standard/Daylight Time */
     {abbr:"CST", zone:"GMT-0600"},
     {abbr:"CDT", zone:"GMT-0500"},
     /* Eastern Standard/Daylight Time */
     {abbr:"EST", zone:"GMT-0500"},
     {abbr:"EDT", zone:"GMT-0400"},
     /* Atlantic Standard/Daylight Time */
     {abbr:"AST", zone:"GMT-0400"},
     {abbr:"ADT", zone:"GMT-0300"},
     /* Newfoundland Standard/Daylight Time */
     {abbr:"NST", zone:"GMT-0330"},
     {abbr:"NDT", zone:"GMT-0230"},
     /* London Standard/Daylight Time */
     {abbr:"BST", zone:"GMT+0100"},
     {abbr:"GMT", zone:"GMT+0000"}
];

/**
* Goes through the timze zone abbreviations looking for matching GMT time.
* */
private static function parseTimeZoneFromGMT(gmt:String):String
{
     for each (var obj:Object in timeZoneAbbreviations) {
          if(obj.zone == gmt){
               return obj.abbr;
          }
     }
     return gmt;
}

This utility is obviously not robust enough to do world timezones, but its enough of a framework to work with if you want to expand past just US timezones (and London). I am sure there are a lot of different ways this could be improved, so please share resources or ideas if you have them. You can get the code for the complete utility from GitHub:

TimzeZoneUtil.as

Thanks!

-Mister

AS3 P2P Helper Class

This is just a simple class I created to allow to clients (AIR Desktop, AIR Mobile) to send and receive commands from each other using Flash Player 10 P2P (Peer to Peer). This class is used to drive a AIR application running on a large wall mounted flat screen monitor from an Android mobile device. These are two different applications but are talking to each other through this common library while connected on the same network.

There is a great little starter video by Paul Trani with CS5. Peter Elst is also working on a P2P library called Cocoon that allows more robust communication. Also check out Renaun Erickson’s post for setting up your Mac as a hub for local P2P connections without WiFi.

Full code: https://gist.github.com/673f0a77f701d4ae98a7

-Mister

AIR for Android: Phoenix Traffic Released in Android Market


Phoenix Traffic for Android

I finally released my first application into the Android Market. This application takes data for Phoenix traffic cameras and displays live camera images. That part was simple enough, but deciding to go with either Flex or Flash for development was the hard part. Originally, I built the application using Flex 4 (this was pre-Hero and Burrito) and talked about it in a previous post. However, I found the Flex application to be memory intensive, lethargic, and the scrolling list functionality simply unusable.

For the final release of the application, I decided to use Flash CS5. This allowed me to build a somewhat smaller version of the application that could be easily be deployed using Adobe’s AIR technology for Android directly from Flash. As part of this project I built (or rather modified code from others) an AS3 scrolling list that responds to touch events and behaves similar to native Android scrolling lists.

In my opinion, the list still performs better than some of the current controls in being built for Flex Burrito. This might change in the near future, but for now, AS3 only applications on Android seem to be lighter and perform better than Flex. If you are interested, you can see the code and example files for the scrolling list here in this post.

To download the Phoenix Traffic application, you can visit the Phoenix Traffic application page from this site or just search for “Phoenix Traffic” in the Android Market. Please feel free to leave me any comments or feedback about the application. I will continue to tinker with the application and improve it over time.

Update

This application has since been migrated from AIR to a native Android application.

- Mister

AS3 Scrolling List for Android and iOS devices

I created a very simple AS3 list that works with the both Android and iOS devices. The project files include a Flash Professional project created with Flash Builder 4. You will need Adobe AIR for Android or the packager for iPhone to create naive create native iOS (iPhone, iPad) or Android.

If you only want to build for Android, then I recommend you check out Adobe Flash Builder Burrito and the Flex Hero SDK (or SDK 4.5). There is already a list control in the Flex Hero SDK (or SDK 4.5) for Android devices. However for iOS devices, you will need a scrolling list that works with AS3 and CS5 for packaging.

The list I created is an AS3 list that works for multiple devices, touch scrolls, and uses custom item renderers that detect user interaction. Here is an example AS3 project with the list in action. Just use your mouse like you would your finger on a mobile device to scroll the list and select items.



AS Scrolling List (click to view)

The list is suited best for smaller sets of data because the list does not recycle list items. But for most mobile applications you don’t normally have that many items to scroll. Adobe also recommends that you not use the drawing API in Flash because of its memory consumption on mobile devices. It would be better to create a MovieClip or Sprite in Flash and use that as the background of your item renderer. However, int this project I used the drawing API to change the selection color of the list item throwing all caution to the wind.

TouchList

The TouchList class creates the list, adds items and handles touch events dispatched by the item renderers. You might notice that I didn’t use any actual TouchEvent listeners in the list. This is because a TouchEvent is essentially a MouseEvent and I couldn’t see any difference in using one over the other. The TouchList class has a built in delay to differentiate between a scrolling and touch action. Like the Android phone, you can’t select an item while scrolling and pressed items are deselected if you scroll while pressed.

TouchListItemRenderer

TouchListItemRenderer implements ITouchListItemRenderer and renders the display of the items in the list data. This renderer can be customized to show whatever type of data you want in the list. List items can also be variable height.

ITouchListItemRenderer

If you want to create an item renderer for the list, then it must implement the ITouchListItemRenderer interface. This interface gives the renderer basic functionality to interact with user selection and touch events used by the list.

ListItemEvent

The list item event is a custom custom ListItemEvent dispached when a list item renderer is pressed. The event contains the event payload and a instance of the item renderer selected.

Installation

Included in the GitHub repository is the working project files for that I created in Flash Builder 4 that handles adding the list to the stage, screen orientation on the device, stage resize, and other functions for an Android AIR application. To install, just checkout the project file and import it into Flash Builder. I have also included Android .apk file if you want to deploy it directly to your Android phone.

The AS3ScrollinList project is located on GitHub.

If you do use the list in a project, be sure to drop me a note or mention me in your will. This list is actually a combination of my efforts and those of others in the Flash community. So please share what you build as well. If you have improvements, just post them back to this post or feel free to fork the GitHub code.

Work Cited

-Mister

Simple AS3 Mouse Scrolling List

Here is a simple ActionScript 3 list that scrolls with selectable items done two ways. The list itself acts like a component added to the stage, it can be sized and placed anywhere on the stage. The first way scrolling is achieved is based on the movement of the mouse over a defined masked area.

The smooth movement of the list is accomplished with TweenLite:

ListScroll.swf

The second way to scroll the list was on an enter frame event. This method is not as smooth because TweenLite could not be produced to create the movement of the list:

ListScroll2.swf

That’s pretty much the extent of it. Below is the code for the list application and scrolling list.

List.as

package
{
    import flash.display.MovieClip;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.text.TextField;

    [SWF( width = '320', height = '440', backgroundColor = '#000000', frameRate = '30')]
    public class ListScroll extends Sprite
    {
        private var list:MouseScrollList;

        public function ListScroll()
        {
            addEventListener(Event.ADDED_TO_STAGE, init);
        }

        private function init(e:Event):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            list = new MouseScrollList(300, 400, false);
            list.y = 20;
            list.x = 5;
            this.addChild(list);
        }
    }
}

MouseScrollList.as

package
{
    import com.greensock.TweenLite;
    import com.greensock.easing.Quad;

    import flash.display.MovieClip;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.text.TextField;

    public class MouseScrollList extends Sprite
    {
        private var background:Sprite;
        private var menuMask:Shape;
        private var listHitArea:Shape;
        private var list:Sprite;

        private var prevY:Number = 0;
        private var listHeight:Number;
        private var hitAreaHeight:Number;
        private var listY:Number;
        private var listX:Number;
        private var listInitY:Number;

        private var verticalPadding:Number = 5;
        private var itemHeight:Number = 35;
        private var children:Number = 50;

        private var componentWidth:Number;
        private var componentHeight:Number;

        private var scrollOnMouseMove:Boolean = false;  // uses mouse move instead of enter frame, but doesn't work as good as I thought
        private var scroll:Boolean = true; // on mouse down set to false to hold scroll position in list when item is clicked

        public function MouseScrollList(w:Number, h:Number, scrollOnMouseMove:Boolean = false)
        {
            this.componentWidth = w;
            this.componentHeight = h;
            this.scrollOnMouseMove = scrollOnMouseMove;

            addEventListener(Event.ADDED_TO_STAGE, init);
            addEventListener(Event.REMOVED, destroy);
        }

        private function init(e:Event):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);

            if(scrollOnMouseMove){
                addEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
            } else {
                addEventListener(Event.ENTER_FRAME, handleEnterFrame);
            }

            listHitArea = new Shape

            menuMask = new Shape();
            menuMask.graphics.clear();
            menuMask.graphics.beginFill(0xFFFFFF,.4);
            menuMask.graphics.drawRect(0, 0, componentWidth, componentHeight)
            menuMask.graphics.endFill();

            this.addChild(menuMask);

            list = new Sprite();
            list.mask = menuMask;

            this.addChild(list);

            for(var i:int = 0; i < children; i++) {
                var textField:TextField = new TextField();
                textField.text = String(i);
                textField.mouseEnabled = false;

                var item:Sprite = new Sprite();
                    item.graphics.clear();
                    item.graphics.beginFill(0xFF0000, 1);
                    item.graphics.drawRect(0, 0, componentWidth - verticalPadding*2, itemHeight)
                    item.graphics.endFill()
                    item.y = i*(verticalPadding + itemHeight);
                    item.x = verticalPadding;

                    item.addEventListener(MouseEvent.ROLL_OVER, handleRollOver);
                    item.addEventListener(MouseEvent.ROLL_OUT, handleRollOut);
                    item.addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
                    item.addEventListener(MouseEvent.MOUSE_UP, handleMouseUp);

                    item.addChild(textField)
                list.addChild(item);
            }

            listHitArea = new Shape();
            listHitArea.graphics.clear();
            listHitArea.graphics.beginFill(0xFFFFFF,0);
            listHitArea.graphics.drawRect(0, 0, componentWidth, componentHeight)
            listHitArea.graphics.endFill();

            this.addChild(listHitArea);

            var point:Point = new Point(listHitArea.x, listHitArea.y);
                point = this.globalToLocal(point);

            listX = point.x;
            listY = point.y;
            listInitY = list.y;
            hitAreaHeight = listHitArea.height;
            listHeight = children*(verticalPadding + itemHeight) - hitAreaHeight;
        }

        private function scrollMouseMove(y:Number):void
        {
            var percent:Number = y/hitAreaHeight;
            var newY:Number = -(Math.round(listHeight*percent));

            if(newY + itemHeight*3 > hitAreaHeight) {
                newY = hitAreaHeight;
            } else if (newY + itemHeight*3 > listInitY) {
                newY = listInitY;
            }

            TweenLite.to(list, 2, {y:newY, ease:Quad.easeOut});
        }

        private function scrollEnterFrame(y:Number):void
        {
            var distance:Number = Math.cos( ( -(y + listY)/hitAreaHeight)*Math.PI )*15;
            var currentY:Number = list.y;
            var newY:Number;

            if( (currentY + distance - verticalPadding) > listInitY + verticalPadding) return;

            newY = list.y + distance;

            var delta:Number = Math.abs(prevY - newY);

            if(delta < 1) {
                list.y = prevY;
                return;
            }

            if(newY >= listInitY) {
                newY = listInitY;
            } else if (Math.abs(newY) > listHeight){
                newY = -listHeight;
            }

            prevY = list.y;
            list.y = newY;
        }

        private function handleMouseMove(event:MouseEvent):void
        {
            var x:Number = this.mouseX + Math.abs(listX);
            var y:Number = this.mouseY + Math.abs(listY);

            if( menuMask.hitTestPoint( x, y )  && scroll) {
                scrollMouseMove(y - Math.abs(listY));
            }
        }

        private function handleEnterFrame(event:Event):void
        {
            var x:Number = this.mouseX + Math.abs(listX);
            var y:Number = this.mouseY + Math.abs(listY);

            if( listHitArea.hitTestPoint( x, y ) && scroll  ) {
                scrollEnterFrame(y);
            }
        }

        public function handleRollOver(e:MouseEvent):void
        {
            e.target.alpha = .5;
        }

        private function handleRollOut(e:MouseEvent):void
        {
            e.target.alpha = 1;
        }

        private function handleMouseDown(e:MouseEvent):void
        {
            e.target.alpha = .2;
            scroll = false;
        }

        private function handleMouseUp(e:MouseEvent):void
        {
            e.target.alpha = 1;
            scroll = true;
        }

        private function destroy(e:Event):void
        {
            removeEventListener(Event.REMOVED, destroy);

            var list:MovieClip = list as MovieClip;

            if(list.numChildren != 0) {
                var i:int = list.numChildren;
                while( i-- ){
                    var item:Sprite = list.getChildAt(i) as Sprite;
                    item.removeEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
                    item.removeEventListener(MouseEvent.MOUSE_UP, handleMouseDown);
                    item.removeEventListener(MouseEvent.ROLL_OVER, handleRollOver);
                    item.removeEventListener(MouseEvent.ROLL_OUT, handleRollOut);
                    list.removeChildAt( i );
                }
            }

            removeEventListener(Event.ADDED_TO_STAGE, init);
            removeEventListener(Event.REMOVED, destroy);
            removeEventListener(Event.ENTER_FRAME, handleEnterFrame);
            removeEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
        }
    }
}

You can download a Flash working example here.

- Mister

AS3 Button with Text and Basic Styling

It’s been a while since I had the opportunity to work on a pure AS3 project. I recently had a need for a simple AS3 button that displays text and decided to customize the SimpleButton control. As I quickly discovered, the SimpleButton control isn’t really setup to support text or a lot of other features, and hacking these features into it doesn’t make much sense. So I built a quick little class that emulates the behavior of SimpleButton but could display text and offer a few other features for styling the button dynamically.

SimpleButtonProject.swf

SimpleButtonProject.as

package
{
	import com.components.CustomButton;
	import flash.display.Sprite;
	import flash.events.MouseEvent;

	[SWF( width = '200', height = '200', backgroundColor = '#FFFFFF', frameRate = '20')]
	public class SimpleButtonProject extends Sprite
	{
		private var button:CustomButton;

		public function SimpleButtonProject()
		{
			button = new CustomButton("Welcome");
			button.x = 0;
			button.addEventListener(MouseEvent.CLICK, handleMouseClick);
			addChild(button);
		}

		private function handleMouseClick(event:MouseEvent):void
		{
			button.label = "Clicked"

			/*
			     // remove the button and mark it for garbage collection
			     button.removeEventListener(MouseEvent.CLICK, handleMouseClick);
			     this.removeChild(button);
			     button = null;
			*/
		}
	}
}

CustomButton.as

package com.components
{
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFormatAlign;

	public class CustomButton extends Sprite
	{
		// ---- Properties -----

		protected var __button:CustomSimpleButton;
		protected var __txtFormat:TextFormat;
		protected var __txtField:TextField;
		protected var __background:Shape;
		protected var __hitarea:Sprite;

		protected var _label:String = "";
		protected var _font:String = "Arial";
		protected var _fontSize:int = 12;
		protected var _fontColor:uint = 0x000000;
		protected var _upColor:uint = 0xFFCC00;
		protected var _overColor:uint = 0xCCFF00;
		protected var _downColor:uint = 0x00CCFF;
		protected var _buttonWidth:int;
		protected var _buttonHeight:int;
		protected var _buttonStrokeColor:int = 0x000000;

		public function get label():String
		{
			return _label;
		}
		public function set label(value:String):void
		{
			_label = value;
			updateDisplayList();
		}

		public function get buttonStrokeColor():uint
		{
			return _buttonStrokeColor;
		}
		public function set buttonStrokeColor(value:uint):void
		{
			_buttonStrokeColor = value;
			updateDisplayList();
		}

		public function get font():String
		{
			return _font;
		}
		public function set font(value:String):void
		{
			_font = value;
			updateDisplayList();
		}

		public function get fontSize():int
		{
			return _fontSize;
		}
		public function set fontSize(value:int):void
		{
			_fontSize= value;
			updateDisplayList();
		}

		public function get fontColor():uint
		{
			return _fontColor;
		}
		public function set fontColor(value:uint):void
		{
			_fontColor= value;
			updateDisplayList();
		}

		public function get upColor():uint
		{
			return _upColor;
		}
		public function set upColor(value:uint):void
		{
			_upColor = value;
			updateDisplayList();
		}

		public function get overColor():uint
		{
			return _overColor;
		}
		public function set overColor(value:uint):void
		{
			_overColor = value;
		}

		public function get downColor():uint
		{
			return _downColor;
		}
		public function set downColor(value:uint):void
		{
			_downColor = value;
		}

		// ---- Constructor -----

		public function CustomButton(label:String = "", w:int = 80, h:int = 22)
		{
			super();

			if(label != "") this.label = label;

			this.addEventListener(Event.REMOVED_FROM_STAGE, destroy);

			_buttonWidth = w;
			_buttonHeight = h;

			createChildren();
			updateDisplayList();
		}

		// ---- Public Methods -----

		public function destroy(event:Event = null):void
		{
			this.removeEventListener(Event.REMOVED_FROM_STAGE, destroy);

			if(__background) {
				__background.graphics.clear();
				__background = null;
			}

			if(__hitarea){
				__hitarea.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
				__hitarea.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
				__hitarea.removeEventListener(MouseEvent.MOUSE_UP, onMouseOver);
				__hitarea.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
				__hitarea.graphics.clear();
				__hitarea = null;
			}

			if(__txtField) {
				__txtField.text = "";
				__txtField = null;
				__txtFormat = null;
			}
		}

		// ---- Protected Methods -----

		protected function createChildren():void
		{
			if(!__background) {
				__background = new Shape();
				addChild(__background);
			}

			if(!__txtField) {
				__txtField = new TextField();
				__txtField.selectable = false
				addChild(__txtField);
			}

			if(!__hitarea) {
				__hitarea = new Sprite();
				__hitarea.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
				__hitarea.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
				__hitarea.addEventListener(MouseEvent.MOUSE_UP, onMouseOver);
				__hitarea.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
				addChild(__hitarea);
			}
		}

		protected function drawButtonBackground(color:uint):void
		{
			if(__background){
				__background.graphics.beginFill(color);
				__background.graphics.lineStyle(1, buttonStrokeColor);
				__background.graphics.drawRect(0, 0, _buttonWidth, _buttonHeight);
				__background.graphics.endFill();
			}
		}

		protected function updateDisplayList():void
		{
			if(__txtField){
				__txtFormat = new TextFormat(font, fontSize, fontColor, false, null, null, null, null, TextFormatAlign.CENTER);
				__txtField.width = _buttonWidth;
				__txtField.defaultTextFormat = __txtFormat;
				__txtField.text = _label;
				__txtField.y = (_buttonHeight - __txtField.textHeight)/2;
			}

			if(__background) {
				drawButtonBackground(upColor);
			}

			if(__hitarea){
				__hitarea.graphics.beginFill(0x000000, 0);
				__hitarea.graphics.drawRect(0, 0, _buttonWidth, _buttonHeight);
				__hitarea.graphics.endFill();
			}
		}

		protected function onMouseOver(e:Event):void
		{
			e.stopPropagation();
			drawButtonBackground(overColor);
		}

		protected function onMouseDown(e:Event):void
		{
			e.stopPropagation();
			drawButtonBackground(downColor);
		}

		protected function onMouseUp(e:Event):void
		{
			e.stopPropagation();
			drawButtonBackground(overColor);
		}

		protected function onMouseOut(e:Event):void
		{
			e.stopPropagation();
			drawButtonBackground(upColor);
		}
	}
}

So there you have it, a very simple button that displays text and has a few other features. I realize its not so simple ( # lines of code), but I added a lot of public properties to change the style and label dynamically, as well as logic for garbage collection. If you don’t need those extra features, you can easily be customize it to fit any your needs.

-Mister

Flash Builder 4: Building ASDocs and SWC with Ant

This post has been updated to work with Flash Builder 4

I wanted to write a quick post because I am just exploring the ability to build ASDocs using ANT from within FB 4. Adobe Labs has a post about using Flex Ant Tasks to manage builds from Flex. With this tool you can compile Flex applications, modules, libraries, and HTML wrapper code, as well as build your documentation with ASDocs. I created a sample Flex Library project that uses the compc feature of the Flex Ant tasks to compile my library into a SWC. I also use exec command in the same build file to create the ASDocs for the project. The path names in the build file have been abstracted into properties file. This properties file can be changed to build the project on both Mac and PC.

The only problems I ran into for this project was pointing to the path of the asdocs on my Mac when compared to the paths on a PC. The asdoc (asdoc.exe on PC and just asdoc on Mac) doesn’t like spaces in the path names to the output and source directories. So if you place these values directly in the build XML file you have to use single quotes for the values, something like this:

<target name="asDocs">

		<exec executable="${FLEX_HOME}/bin/asdoc" failonerror="true">

		<arg line="-doc-sources '/Users/xmritchie/Documents/Flex Builder 3/as3xdrivelib/com'">

		<arg line="-window-title 'Xdrive AS3 Library'">

		<arg line="-output='/Users/xmritchie/Documents/Flex Builder 3/as3xdrivelib/docs'">

		<arg line="-external-library-path='/Users/xmritchie/Documents/Flex Builder 3/as3xdrivelib/libs'">

		</arg>

		<echo>docs created</echo>

	</arg>

However, if you abstract these value into a properties file you won’t have any issues with paths. The build.xml file and the properties file go into the root level of your library project. Be sure you have the flexTasks.jar file in the properly location, you can get more information here: Flex_Ant_Tasks Adobe.

Here is the code for the build.xml:

<!-- Flex Library Project ASDocs -->

<project name="ASDocsTest" default="compile" basedir=".">

	<!-- import our build properties file -->
	<property file="${basedir}/build.properties" />

	<!-- Flex Ant Tasks used to perform compc and mxml compiling more info at http://labs.adobe.com/wiki/index.php/Flex_Ant_Tasks -->
	<taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/ant/lib/flexTasks.jar" />

	<target name="setup" description="perform an setup operations">

	<!-- Execute the ASDoc Compile wich runs 3 seperate tasks in a series -->
	<target name="compile" description="series of tasks to create docs and swc">

		<antcall target="cleanDir" description="clean the docs directory">

		<antcall target="asDocs" description="full build of asdocs">

		<antcall target="buildSWC" description="build the SWC file">

	</antcall>

	<target name="deploy" description="perform an deployment operations">

	<target name="install" description="perform an installation operations">

	<!--

	DELETE the existing output folder and files and then re-generate the output folder

	-->

	<target name="cleanDir" description="DELETE the existing output folder and files and then re-generate the output folder">

		<delete dir="${basedir}/${docsoutputfolder}" failonerror="true" includeemptydirs="true">

		<mkdir dir="${basedir}/${docsoutputfolder}">

		<!-- echo dumps output to the console window -->
		<echo>doc directory cleaned</echo>

	</mkdir>


	<!--

	Run the ASDoc executable and generate the ASDocs to the new output folder

	-->

	<target name="asDocs" description="Run the ASDoc executable and generate the ASDocs to the new output folder">

		<exec executable="${asdoc.exe}" failonerror="true">

			<arg line="-doc-sources ${domainextensions}">

			<arg value="-window-title">
			<arg value="'${title}'">

			<arg value="-output">
			<arg value="${basedir}/${docsoutputfolder}">

			<arg value="-external-library-path">
			<arg value="${basedir}/${libpath}">

		</arg>

		<echo>docs created</echo>

	</arg>

	<!--

	Compile the  SWC file library including libs folder and the path to our classes, we use compc for library, but we
	would use mxml for MXML files, check the docs for Flex Ant Tasks, http://labs.adobe.com/wiki/index.php/Flex_Ant_Tasks.

	-->

	<target name="buildSWC" description="Compile the SWC file for the Librayr Project">

		<compc output="${basedir}/${liboutputfolder}/${liboutputfile}">

			<!--
				Include the path to any external SWC files used in our document, you may have to place name of SWC (corelib.swc) at end of path
				I didn't include it because I didn't want to redistribute the corelib.swc. So file path would be file="${basedir}/${libpath}/corelib.swc"
			 -->
			<include-libraries file="${basedir}/${libpath}/">

			<source-path path-element="${basedir}/src">

			<!-- include our Class packages into the build (com folder) -->
			<include-sources dir="${basedir}/${domainextensions}" includes="*">

		</include-sources>

		<echo>SWC created</echo>

	</source-path>

</include-libraries>

Here is the code for the build.properties:

# Window and document title for the documentation
title = ActionScript 3 Library
maintitle = ActionScript 3 Library

# Class-folders you want to search for classes to be included in the docs, seperated by spaces (for example   ../src/ ../net/  )
# to include every .as and .mxml file within your project, just state   ../
domainextensions = ./src/

# The Location of deployment library on your Computer (PC/Mac) for compiled SWC file
liboutputfolder = bin
liboutputfile = as3library.swc
libpath = libs

# The Location of the output folder for your generated documents
docsoutputfolder = asdocs

# Home directory for flex sdk 3, change this to build for Mac or PC using # as comment
# FLEX_HOME = C:/Program Files/Adobe/Adobe Flash Builder 4/sdks/4.1.0
FLEX_HOME = /Applications/Adobe Flash Builder 4/sdks/4.1.0
	
# The location of your asdoc.exe, change this to build for Mac or PC using # as comment
#asdoc.exe = C:/Program Files/Adobe/Adobe Flash Builder 4/sdks/4.1.0/bin/asdoc.exe
asdoc.exe = /Applications/Adobe Flash Builder 4/sdks/4.1.0/bin/asdoc

Once you have the Ant plugin installed for Flash Builder and restart, go to Widows –> Other Views and select Ant. Drag the build.xml file to the Ant dialog window, then double-click on compile to run the script. This is how you build the docs and the SWC file. You can also use those same build and properties files in the SDK.

Here is the example file, just download the file directly from link, unzip the file, and import into your Flex builder (this has not been updated to Flash Builder 4!).

ASDocsTest.zip

Additional Resources

http://www.unitedmindset.com/jonbcampos/2010/06/22/building-an-air-application-with-ant/

http://elromdesign.com/blog/2010/07/08/flashbuilder-4-tip-install-ant-prospective-in-eclipse-version-351/

- Mister

JSON (Lite)

For a current Flex project we use JSON to transfer data between the application and the backend. Adobe Labs has a JSON serialization library called corelib that includes MD5 hashing, JSON, and other parsing tools.  What if you need just JSON for your Flex or Flash AS3 application development?

There is already a JSON ActionScript file for AS2 available at JSON.org. This file would be great for your older Flash projects and maybe some mobile application development.   Initially, I tried to convert this file to AS3, but then I figured someone probably already did this.   After some extensive searching and help from Lar (as always), we were able to locate a version of JSON that had been converted to AS3 for a project called VEGAS.      

There was no stand alone version of JSON for AS3, we had to extract the JSON pieces from the project files.  I did a little touch up for the error messaging, but it is essentially the same JSON for AS2, just updated to work with AS3.  In fact, it is by the same author, ekameleon.    

I am including all the links to the original source information as well as a stand alone version of the JSON AS3 ActionScript file and Flex Library file with the compiled SWC (called JSONLite).   The total size of the JSON AS3 file is 5KB!   

JSON AS3 (Flash/Flex)

JSON SWC (Flex)

To use the file just add the SWC to your Flex Library path.    In the MXML file, import the file and call to serialize/deserialize the same way you do with the corelib JSON SWC:

import com.serialization.json.JSON;

var dataString:String = JSON.serialize(object);

var obj:Object = JSON.deserialize(string);

I don’t support these files, I am just passing the information along and doing some experimentation with other JSON libraries. Also note that using the JSONLite SWC or class file file instead of the corelib file won’t significantly lighten your Flex applications. Flex only compiles the packages and class files you reference in your application from the library. So the post title is a bit misleading because you only shave off that 1KB. However, I have heard from others that this class file is faster than most other JSON parsers which does give it a slight advantage if speed is a concern.

-Mister