Filter messages using the logcat command

When working on mobile with AIR you cab use the logcat tool available in the Andorid SDK to grab information from the device and dumping them via USB on a log screen.
If you are interested to get only the trace statements and the ActionScript error messages you can restict the logcat output via command line with the snippet you find below.
The reason why you can do this filtering is because during the packaging process each AIR application has the word air added to the application ID, therefore using the filter I.air guarantees to dump all messages for the currently running AIR application.
The letter I stays for the Information priority level.
androidSDK/platform-tools/adb logcat|grep "I.air"

Detect Internet Explorer and its version

Unfortunately sometime is pretty useful to understand if the JavaScript is executed into Internet Explorer and the version of the browser, you can recover all this information with the usage of regular expressions.
if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)){ 

var version = new Number(RegExp.$1);
// Do whatever you want with the version information

}

JQuery tools overlay handling

There are several JavaScript libraries that can help you to create an overlay effect, a good one should be JQuery tools.
A common issue with this library is that the auto load feature allow you to load only once the overlay, second time you try to load it nothing happens and no errors appear.
To solve this issue you can disable the auto load feature in the configuration and manually handle the closure of the overaly binding and unbinding the click event to the document object using jQuery.
var currentOverlay;

function openOverlay(){

var config = {};

config['mask'] = {

// you might also consider a "transparent" color for the mask
color: '#000000',

// load mask a little faster
loadSpeed: 300,

// very transparent
opacity: .6

};
config['closeOnClick'] = false;
config['load'] = false;
config['top'] = '40%';
config['onLoad'] = activateCloseHandler;
config['onClose'] = removeCloseHandler;

$("#theDivYouWantToOpenInOverlay").overlay(config);
currentOverlay = $("#theDivYouWantToOpenInOverlay").data("overlay").load();

}

function activateCloseHandler(event){

$(document).click(function(e) {

e.stopPropagation();
currentOverlay.close();

});

}

function removeCloseHandler(event){

$(document).unbind('click');

}

Language Management and multilang web app

A common issue in a web application is handling the automatic language detection and the selection of a specific language made by an user.
A possible approach is to keep the language handling client side and handle it through JavaScript. In order to do this you can manipulate the URL and append and recover values using the jsuri library hosted on google code and encapsulate the language detection in a script included in each page.
The steps the script has to perform are:

  • Declare a varbiable to store the current language

  • Recover the browser language

  • Check if the URL already contains a language query string param

  • Change the href value of your page or populate the variable that contains the current language


var currentLanguage;

if (navigator.appName == 'Netscape'){

var language = navigator.language;

}else{

var language = navigator.browserLanguage;

}

if (language.indexOf('en') > -1) currentLanguage = "en";
else if (language.indexOf('it') > -1) currentLanguage = "it";
else currentLanguage = "en";

var uri = new jsUri(location.href);

if(!uri.getQueryParamValue('lang')){

uri.setQuery('?lang=' + currentLanguage);
location.href = uri;

}else{

currentLanguage = getQueryParamValue('lang');

}

Dynamically add JavaScript

In order to add dynamically a script to your page you can use the DOM and access the header, in this way you can be sure that the page will contain this file before other script will be executed.
var currentFile = 'test';

var headID = document.getElementsByTagName("head")[0];
var script = document.createElement( 'script' );
script.type = 'text/javascript';
script.src = 'js/' + currentFile + '.js';
headID.appendChild( script );

CSS and orientation mode on iOS devices

You can use media query in your CSS in order to load the appropriate file accordingly to the device orientation.
In order to do this you can create a main.css file for your mobile web page and the use inside it media query combined with the import directive.
This sinppet is particulary tailored of iOS devices
@import url("portrait.css") all and (orientation:portrait);
@import url("landscape.css") all and (orientation:landscape);

ALT GR + foreign keyboards workaround

With Firefox and Chrome the handling of the ALT GR keyboards combination fails silently.
We found a workaround based on the usage of an instance of the class LocalConnection in an SWF file based on ActionScript 1.0 (available here) but we strongly avoid to use AS1 also for workaraounds like this.
The solution we outlined is available here, is based on JavaScript and ActionScript 3.0 and can be summarized as following
  • Instead of using a input text filed use a dynamic text field
  • Through a Cursor class (the one available in the following snippet) the standard cursor behavior is simulated
  • The focus is immediately removed from the text field and moved to the body of the HTML page
  • The HTML page handle the keyboard pressure and communicate with the SWF file through JavaScript


The source code is not fully implemented so consider it as a proof of concept (POC), in the demo you can take a look to the behavior of a dynamic text field and of a input text field. In order to download the code you have to create an account.
package  {
import flash.display.Sprite;
import flash.text.TextField;
import flash.events.Event;
import flash.events.TextEvent;
import flash.events.FocusEvent;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.display.Graphics;

public class Cursor extends Sprite {

private var target:TextField;
private var timer:Timer;

private const CURSOR_DELAY:int = 400;
private const PADDING_BOTTOM:int = 4;
private const PADDING_TOP:int = 4;
private const PADDING_LEFT:int = 2;

private var _cursorDelay:int;
private var drawable:Boolean;

private var _paddingTop:int;
private var _paddingLeft:int;
private var _paddingBottom:int;

public static const ACTIVATE_INTERACTION:String = "onActivateInteraction";
public static const DEACTIVATE_INTERACTION:String = "onDeActivateInteraction";

public function Cursor(tg:TextField) {

target = tg;

addEventListener(Event.ADDED_TO_STAGE, init);
addEventListener(Event.REMOVED_FROM_STAGE, dispose);

}

private function createCursor():void{

if(!timer){

timer = new Timer(cursorDelay);

timer.addEventListener(TimerEvent.TIMER, onBlink);
timer.start();

}

}

public function destroyCursor():void{

if(timer){

timer.stop();
timer.removeEventListener(TimerEvent.TIMER, onBlink);

timer = null;

graphics.clear();

}

}

protected function onBlink(e:TimerEvent):void{

drawable = !drawable;
var g:Graphics = graphics;

if(drawable){

g.lineStyle(1, 0x000000, 1);
g.moveTo(cursorX, target.y + paddingTop);
g.lineTo(cursorX, target.y + target.height - paddingBottom);

}else{

g.clear();

}

}

protected function handleInput(e:TextEvent):void{



}

protected function onFocusIn(e:FocusEvent):void{

dispatchEvent(new Event(ACTIVATE_INTERACTION));

createCursor();

stage.focus = parent;

}

protected function onFocusOut(e:FocusEvent):void{

dispatchEvent(new Event(DEACTIVATE_INTERACTION));



}

private function init(e:Event):void{

target.addEventListener(TextEvent.TEXT_INPUT, handleInput);

target.addEventListener(FocusEvent.FOCUS_IN, onFocusIn);
target.addEventListener(FocusEvent.FOCUS_OUT, onFocusOut);

}

private function dispose(e:Event):void{

target.removeEventListener(TextEvent.TEXT_INPUT, handleInput);

target.removeEventListener(FocusEvent.FOCUS_IN, onFocusIn);
target.removeEventListener(FocusEvent.FOCUS_OUT, onFocusOut);

}

public function set cursorDelay(value:int):void{

_cursorDelay = value;

}

public function get cursorDelay():int{

return _cursorDelay ? _cursorDelay : CURSOR_DELAY;

}

public function set paddingTop(value:int):void{

_paddingTop = value;

}

public function get paddingTop():int{

return _paddingTop ? _paddingTop : PADDING_TOP;

}

public function set paddingBottom(value:int):void{

_paddingBottom = value;

}

public function get paddingBottom():int{

return _paddingBottom ? _paddingBottom : PADDING_BOTTOM;

}

public function set paddingLeft(value:int):void{

_paddingLeft = value;

}

public function get paddingLeft():int{

return _paddingLeft ? _paddingLeft : PADDING_LEFT;

}

public function get currentTarget():TextField{

return target;

}

private function get cursorX():int{

return target.x + paddingLeft + target.textWidth;

}

}

}

Duplicate SWF or raster content of an Image component

Using the BitmapData class is quite easy and fast copy or manipulate an external image loaded into a Flex application, it's quite interesting the difference between the data type of the content property of an Image component because it changes if a bitmap or a SWF has been loaded:
  • the first one is a Bitmap
  • the second on is a MovieClipLoaderAsset


In order to let you copy the content also with a SWF file loaded into the Image component you can use a Loader and the loadBytes() method.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical"
verticalAlign="middle"
backgroundColor="white">

<mx:Script>
<![CDATA[
import mx.core.MovieClipLoaderAsset;
import mx.core.BitmapAsset;
import mx.collections.ArrayCollection;

[Embed(source="placeholder.swf")]
private const ARTWORK_PLACE_HOLDER_SWF:Class;

[Embed(source="placeholder.png")]
private const ARTWORK_PLACE_HOLDER_PNG:Class;

[Bindable]
private var collection:ArrayCollection = new ArrayCollection();

private function handleImage(e:Event):void{

if(e.currentTarget.selectedValue == "PNG"){

img.source = ARTWORK_PLACE_HOLDER_PNG;

}else{

img.source = ARTWORK_PLACE_HOLDER_SWF;

}

}

private function dumpImage(source:Image):void {

var asset:* = source.content;
var data:BitmapData;
var bitmap:Bitmap;

try{

data = Bitmap(source.content).bitmapData;
bitmap = new Bitmap(data);

collection.addItem({image:bitmap, label:"item #" + (collection.length + 1)});

}catch(error:Error){

var loader:Loader = new Loader();

loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onBitmapData);

var swf:MovieClipLoaderAsset = asset as MovieClipLoaderAsset;
loader.loadBytes(swf.movieClipData);

}

}

private function onBitmapData(e:Event):void{

e.target.removeEventListener(e.type, arguments.callee);

var content: MovieClip = MovieClip((e.currentTarget as LoaderInfo).content)
var data:BitmapData = new BitmapData(content.width, content.height);
data.draw(content, null, null, null, null, true)
var bitmap:Bitmap = new Bitmap(data)

collection.addItem({image:bitmap, label:"item #" + (collection.length + 1)});

}

]]>
</mx:Script>

<mx:HBox>
<mx:Panel title="Source image">
<mx:HBox verticalAlign="middle" horizontalAlign="center" width="100%" height="100%">
<mx:Image id="img" source="{ARTWORK_PLACE_HOLDER_SWF}" />
</mx:HBox>

<mx:RadioButtonGroup id="imageSelector" change="handleImage(event)" />
<mx:RadioButton label="SWF" selected="true" group="{imageSelector}" />
<mx:RadioButton label="PNG" group="{imageSelector}" />

<mx:ControlBar>
<mx:Button label="Copy image" click="dumpImage(img)" />
</mx:ControlBar>
</mx:Panel>

<mx:TileList id="tileList" dataProvider="{collection}" width="450" height="500" columnCount="4" verticalScrollPolicy="on">
<mx:itemRenderer>
<mx:Component>
<mx:VBox>
<mx:Image source="{data.image}" />
<mx:Label text="{data.label}" />
</mx:VBox>
</mx:Component>
</mx:itemRenderer>
</mx:TileList>
</mx:HBox>

</mx:Application>

Align an a display object to its center

When you create dinamically a display object in ActionScript the registration point is at the top right (obviously it depends also on the way you design the object into the library) and expecially in Flex it can represent an issue when you want to align an object to a point considering the center of this object.
In order to avoid this issue it's enough to calculate the dispalcement between the center of the object and the actual X and Y coordinates, the following script is the function you have to use to calculate the diaplacement, attached there is a .fla file that show you a complete sample (please register in order to download the file).
function displacement(target:DisplayObjectContainer, x:Number, y:Number):Point{

var bounds:Rectangle = target.getBounds(this);

var centerX:Number = bounds.x + (bounds.width / 2);
var centerY:Number = bounds.y + (bounds.height / 2);

var deltaX:Number = target.x - centerX;
var deltaY:Number = target.y - centerY;

var point:Point = new Point();
point.x = x + deltaX;
point.y = y + deltaY;

return point;

}

Removing trailing nulls in ActionScript

When reading a byte array in ActionScript (like in C) the null value is read as a string termination. When you try use the readUTFBytes method over a ByteArray if the data contain a null value (0x00) the ActionScript interpreter stop the reading and retunr you a truncated string, in order to avoid this issue you can simply parse the data before using the method readUTFBytes.
Following a small sample where the variable bytedata represents the raw data recovered from your read operation.


var ba:ByteArray = new ByteArray();

for(var i:int = 0; i < bytedata.length; i++){

if(bytedata[i] != 0x00){

ba.writeByte(bytedata[i])

}else{

ba.writeByte(0x0A)

}

}

ba.position = 0;

var data:String = ba.readUTFBytes( ba.length );