You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cf...@apache.org on 2012/06/18 18:26:16 UTC

svn commit: r1351406 [3/3] - in /incubator/flex/trunk/frameworks/javascript: ./ FABridge/ FABridge/samples/ FABridge/samples/srcview/ FABridge/samples/srcview/source/ FABridge/samples/srcview/source/fabridge/ FABridge/samples/srcview/source/fabridge/ac...

Added: incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.as?rev=1351406&view=auto
==============================================================================
--- incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.as (added)
+++ incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.as Mon Jun 18 16:26:14 2012
@@ -0,0 +1,943 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+/*
+ * The Bridge class, responsible for navigating JS instances
+ */
+package bridge
+{
+
+/*
+ * imports
+ */
+import flash.external.ExternalInterface;
+import flash.utils.Timer;
+import flash.events.*;
+import flash.display.DisplayObject;
+import flash.system.ApplicationDomain;
+import flash.utils.Dictionary;
+import flash.utils.setTimeout;
+
+import mx.collections.errors.ItemPendingError;
+import mx.core.IMXMLObject;
+
+import flash.utils.getQualifiedClassName;
+import flash.utils.describeType;
+import flash.events.TimerEvent;
+
+/**
+ * The FABridge class, responsible for proxying AS objects into javascript
+ */
+public class FABridge extends EventDispatcher implements IMXMLObject
+{
+
+    //holds a list of stuff to call later, to break the recurrence of the js <> as calls
+    //you must use the full class name, as returned by the getQualifiedClassName() function
+    public static const MethodsToCallLater:Object = new Object();
+    MethodsToCallLater["mx.collections::ArrayCollection"]="refresh,removeItemAt";
+
+    public static const EventsToCallLater:Object = new Object();
+    EventsToCallLater["mx.data.events::UnresolvedConflictsEvent"]="true";
+    EventsToCallLater["mx.events::PropertyChangeEvent"]="true";
+    
+    public static const INITIALIZED:String = "bridgeInitialized";
+
+    // constructor
+    public function FABridge()
+    {
+        super();
+        initializeCallbacks();
+    }
+
+    // private vars
+
+    /**
+     * stores a cache of descriptions of AS types suitable for sending to JS
+     */
+    private var localTypeMap:Dictionary = new Dictionary();
+
+    /**
+     * stores an id-referenced dictionary of objects exported to JS
+     */
+    private var localInstanceMap:Dictionary = new Dictionary();
+
+    /**
+     * stores an id-referenced dictionary of functions exported to JS
+     */
+    private var localFunctionMap:Dictionary = new Dictionary();
+
+    /**
+     * stores an id-referenced dictionary of proxy functions imported from JS
+     */
+    private var remoteFunctionCache:Dictionary = new Dictionary();
+
+    /**
+     * stores a list of custom serialization functions
+     */
+    private var customSerializersMap:Dictionary = new Dictionary();
+
+    /**
+     * stores a map of object ID's and their reference count
+     */
+    private var refMap:Dictionary = new Dictionary();
+    /**
+     * a local counter for generating unique IDs
+     */
+    private var nextID:Number = 0;
+
+    private var lastRef:int;
+
+    /* values that can't be serialized natively across the bridge are packed and identified by type.
+       These constants represent different serialization types */
+    public static const TYPE_ASINSTANCE:uint = 1;
+    public static const TYPE_ASFUNCTION:uint = 2;
+    public static const TYPE_JSFUNCTION:uint = 3;
+    public static const TYPE_ANONYMOUS:uint = 4;
+
+    private var _initChecked:Boolean = false;
+
+    // properties
+
+    //getters and setters for the main component in the swf - the root
+    public function get rootObject():DisplayObject {return _rootObject;}
+    public function set rootObject(value:DisplayObject):void
+    {
+        _rootObject = value;
+        checkInitialized();
+    }
+    
+    /**
+     * the bridge name
+     */
+    public var bridgeName:String;
+    private var _registerComplete:Boolean = false;
+    
+    /**
+     * increment the reference count for an object being passed over the bridge
+     */
+    public function incRef(objId:int):void
+    {
+        if(refMap[objId] == null) {
+            //the object is being created; we now add it to the map and set its refCount = 1
+            refMap[objId] = 1;
+        } else {
+            refMap[objId] = refMap[objId] +1;
+        }
+    }
+
+    /**
+     * when an object has been completely passed to JS its reference count is decreased with 1
+     */
+    public function releaseRef(objId:int):void
+    {
+        if(refMap[objId] != null)
+        {
+            var newRefVal:int = refMap[objId] - 1;
+            // if the object exists in the referenceMap and its count equals or has dropped under 0 we clean it up
+            if(refMap[objId] != null && newRefVal <= 0)
+            {
+                delete refMap[objId];
+                delete localInstanceMap[objId];
+            }
+            else
+            {
+                refMap[objId] = newRefVal;
+            }
+        }
+    }
+
+    /**
+     * attaches the callbacks to external interface
+     */
+    public function initializeCallbacks():void
+    {
+        if (ExternalInterface.available == false)
+        {
+            return;
+        }
+
+        ExternalInterface.addCallback("getRoot", js_getRoot);
+        ExternalInterface.addCallback("getPropFromAS", js_getPropFromAS);
+        ExternalInterface.addCallback("setPropInAS", js_setPropertyInAS);
+        ExternalInterface.addCallback("invokeASMethod", js_invokeMethod);
+        ExternalInterface.addCallback("invokeASFunction", js_invokeFunction);
+        ExternalInterface.addCallback("releaseASObjects", js_releaseASObjects);
+        ExternalInterface.addCallback("create", js_create);
+        ExternalInterface.addCallback("releaseNamedASObject",js_releaseNamedASObject);
+        ExternalInterface.addCallback("incRef", incRef);
+        ExternalInterface.addCallback("releaseRef", releaseRef);
+    }
+
+    private var _rootObject:DisplayObject;
+
+    private var _document:DisplayObject;
+    
+    /**
+     * called to check whether the bridge has been initialized for the specified document/id pairs
+     */
+    public function initialized(document:Object, id:String):void
+    {
+        _document = (document as DisplayObject);
+
+        if (_document != null)
+        {
+            checkInitialized();
+        }
+    }
+    
+    private function get baseObject():DisplayObject
+    {
+        return (rootObject == null)? _document:rootObject;
+    }
+
+
+    private function checkInitialized():void
+    {
+        if(_initChecked== true)
+        {
+            return;
+        }
+        _initChecked = true;
+
+        // oops! timing error. Player team is working on it.
+        var t:Timer = new Timer(200,1);
+        t.addEventListener(TimerEvent.TIMER,auxCheckInitialized);
+        t.start();
+    }
+
+    /** 
+     * auxiliary initialization check that is called after the timing has occurred
+     */
+    private function auxCheckInitialized(e:Event):void
+    {
+
+        var bCanGetParams:Boolean = true;
+
+        try
+        {
+            var params:Object = baseObject.root.loaderInfo.parameters;
+        }
+        catch (e:Error)
+        {
+            bCanGetParams = false;
+        }
+
+        if (bCanGetParams == false)
+        {
+            var t:Timer = new Timer(100);
+            var timerFunc:Function = function(e:TimerEvent):void
+            {
+                if(baseObject.root != null)
+                {
+                    try
+                    {
+                        bCanGetParams = true;
+                        var params:Object = baseObject.root.loaderInfo.parameters;
+                    }
+                    catch (err:Error)
+                    {
+                        bCanGetParams = false;
+                    }
+                    if (bCanGetParams)
+                    {
+                        t.removeEventListener(TimerEvent.TIMER, timerFunc);
+                        t.stop();
+                        dispatchInit();
+                    }
+                }
+            }
+            t.addEventListener(TimerEvent.TIMER, timerFunc);
+            t.start();
+        }
+        else
+        {
+            dispatchInit();
+        }
+    }
+
+    /**
+     * call into JS to annunce that the bridge is ready to be used
+     */
+    private function dispatchInit(e:Event = null):void
+    {
+        if(_registerComplete == true)
+        {
+            return;
+        }
+
+        if (ExternalInterface.available == false)
+        {
+            return;
+        }
+
+        if (bridgeName == null)
+        {
+            bridgeName = baseObject.root.loaderInfo.parameters["bridgeName"];
+
+            if(bridgeName == null)
+            {
+                bridgeName = "flash";
+            }
+        }
+
+        _registerComplete = ExternalInterface.call("FABridge__bridgeInitialized", [bridgeName]);
+        dispatchEvent(new Event(FABridge.INITIALIZED));
+    }
+
+    // serialization/deserialization
+
+    /** serializes a value for transfer across the bridge.  primitive types are left as is.  Arrays are left as arrays, but individual
+     * values in the array are serialized according to their type.  Functions and class instances are inserted into a hash table and sent
+     * across as keys into the table.
+     *
+     * For class instances, if the instance has been sent before, only its id is passed. If This is the first time the instance has been sent,
+     * a ref descriptor is sent associating the id with a type string. If this is the first time any instance of that type has been sent
+     * across, a descriptor indicating methods, properties, and variables of the type is also sent across
+     */
+    public function serialize(value:*, keep_refs:Boolean=false):*
+    {
+        var result:* = {};
+        result.newTypes = [];
+        result.newRefs = {};
+
+        if (value is Number || value is Boolean || value is String || value == null || value == undefined  || value is int || value is uint)
+        {
+            result = value;
+        }
+        else if (value is Array)
+        {
+            result = [];
+            for(var i:int = 0; i < value.length; i++)
+            {
+                result[i] = serialize(value[i], keep_refs);
+            }
+        }
+        else if (value is Function)
+        {
+            // serialize a class
+            result.type = TYPE_ASFUNCTION;
+            result.value = getFunctionID(value, true);
+        }
+        else if (getQualifiedClassName(value) == "Object")
+        {
+            result.type = TYPE_ANONYMOUS;
+            result.value = value;
+        }
+        else
+        {
+            // serialize a class
+            result.type = TYPE_ASINSTANCE;
+            // make sure the type info is available
+            var className:String = getQualifiedClassName(value);
+
+            var serializer:Function = customSerializersMap[className];
+
+            // try looking up the serializer under an alternate name
+            if (serializer == null)
+            {
+                if (className.indexOf('$') > 0)
+                {
+                    var split:int = className.lastIndexOf(':');
+                    if (split > 0)
+                    {
+                        var alternate:String = className.substring(split+1);
+                        serializer = customSerializersMap[alternate];
+                    }
+                }
+            }
+
+            if (serializer != null)
+            {
+                return serializer.apply(null, [value, keep_refs]);
+            }
+            else
+            {
+                if (retrieveCachedTypeDescription(className, false) == null)
+                {
+                    try
+                    {
+                        result.newTypes.push(retrieveCachedTypeDescription(className, true));
+                    }
+                    catch(err:Error)
+                    {
+                        var interfaceInfo:XMLList = describeType(value).implementsInterface;
+                        for each (var interf:XML in interfaceInfo)
+                        {
+                            className = interf.@type.toString();
+                            if (retrieveCachedTypeDescription(className, false) == null){
+                                result.newTypes.push(retrieveCachedTypeDescription(className, true));
+                            } //end if push new data type
+                       
+                        } //end for going through interfaces
+                        var baseClass:String = describeType(value).@base.toString();
+                        if (retrieveCachedTypeDescription(baseClass, false) == null){
+                            result.newTypes.push(retrieveCachedTypeDescription(baseClass, true));
+                        } //end if push new data type
+                    }
+                }
+
+                // make sure the reference is known
+                var objRef:Number = getRef(value, false);
+                var should_keep_ref:Boolean = false;
+                if (isNaN(objRef))
+                {
+                    //create the reference if necessary
+                    objRef = getRef(value, true);
+                    should_keep_ref = true;
+                }
+                
+                result.newRefs[objRef] = className;
+                //trace("serializing new reference: " + className + " with value" + value);
+                
+                //the result is a getProperty / invokeMethod call. How can we know how much you will need the object ? 
+                if (keep_refs && should_keep_ref) {
+                    incRef(objRef);
+                }
+                result.value = objRef;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * deserializes a value passed in from javascript. See serialize for details on how values are packed and
+     * unpacked for transfer across the bridge.
+     */
+    public function deserialize(valuePackage:*):*
+    {
+        var result:*;
+        if (valuePackage is Number || valuePackage is Boolean || valuePackage is String || valuePackage === null || valuePackage === undefined  || valuePackage is int || valuePackage is uint)
+        {
+            result = valuePackage;
+        }
+        else if(valuePackage is Array)
+        {
+            result = [];
+            for (var i:int = 0; i < valuePackage.length; i++)
+            {
+                result[i] = deserialize(valuePackage[i]);
+            }
+        }
+        else if (valuePackage.type == FABridge.TYPE_JSFUNCTION)
+        {
+            result = getRemoteFunctionProxy(valuePackage.value, true);
+        }
+        else if (valuePackage.type == FABridge.TYPE_ASFUNCTION)
+        {
+            throw new Error("as functions can't be passed back to as yet");
+        }
+        else if (valuePackage.type == FABridge.TYPE_ASINSTANCE)
+        {
+            result = resolveRef(valuePackage.value);
+        }
+        else if (valuePackage.type == FABridge.TYPE_ANONYMOUS)
+        {
+            result = valuePackage.value;
+        }
+        return result;
+    }
+
+    public function addCustomSerialization(className:String, serializationFunction:Function):void
+    {
+        customSerializersMap[className] = serializationFunction;
+    }
+
+
+    // type management
+
+    /**
+     * retrieves a type description for the type indicated by className, building one and caching it if necessary
+     */
+    public function retrieveCachedTypeDescription(className:String, createifNecessary:Boolean):Object
+    {
+        if(localTypeMap[className] == null && createifNecessary == true)
+        {
+            localTypeMap[className] = buildTypeDescription(className);
+        }
+        return localTypeMap[className];
+    }
+
+    public function addCachedTypeDescription(className:String, desc:Object):Object
+    {
+        if (localTypeMap[className] == null)
+        {
+            localTypeMap[className] = desc;
+        }
+        return localTypeMap[className];
+    }
+
+    /**
+     * builds a type description for the type indiciated by className
+     */
+    public function buildTypeDescription(className:String):Object
+    {
+        var desc:Object = {};
+
+        className = className.replace(/::/,".");
+
+        var objClass:Class = Class(ApplicationDomain.currentDomain.getDefinition(className));
+
+        var xData:XML = describeType(objClass);
+
+        desc.name = xData.@name.toString();
+
+        var methods:Array = [];
+        var xMethods:XMLList = xData.factory.method;
+        for (var i:int = 0; i < xMethods.length(); i++)
+        {
+            methods.push(xMethods[i].@name.toString());
+        }
+        desc.methods = methods;
+
+        var accessors:Array = [];
+        var xAcc:XMLList = xData.factory.accessor;
+        for (i = 0; i < xAcc.length(); i++)
+        {
+            accessors.push(xAcc[i].@name.toString());
+        }
+        xAcc = xData.factory.variable;
+        for (i = 0; i < xAcc.length(); i++)
+        {
+            accessors.push(xAcc[i].@name.toString());
+        }
+        desc.accessors = accessors;
+
+        return desc;
+    }
+
+// instance mgmt
+
+    /**
+     * resolves an instance id passed from JS to an instance previously cached for representing in JS
+     */
+    private function resolveRef(objRef:Number):Object
+    {
+        try
+        {
+            return (objRef == -1)? baseObject : localInstanceMap[objRef];
+        }
+        catch(e:Error)
+        {
+            return serialize("__FLASHERROR__"+"||"+e.message);
+        }
+
+        return (objRef == -1)? baseObject : localInstanceMap[objRef];
+    }
+
+    /**
+     * returns an id associated with the object provided for passing across the bridge to JS
+     */
+    public function getRef(obj:Object, createIfNecessary:Boolean):Number
+    {
+        try
+        {
+            var ref:Number;
+
+            if (createIfNecessary)
+            {
+                var newRef:Number = nextID++;
+                localInstanceMap[newRef] = obj;
+                ref = newRef;
+            }
+            else
+            {
+                for (var key:* in localInstanceMap)
+                {
+                    if (localInstanceMap[key] === obj)
+                    {
+                        ref = key;
+                        break;
+                    }
+                }
+            }
+        }
+        catch(e:Error)
+        {
+             return serialize("__FLASHERROR__"+"||"+e.message)
+        }
+        
+        return ref;
+    }
+
+
+    // function management
+
+    /**
+     * resolves a function ID passed from JS to a local function previously cached for representation in JS
+     */
+    private function resolveFunctionID(funcID:Number):Function
+    {
+        return localFunctionMap[funcID];
+    }
+
+    /**
+     * associates a unique ID with a local function suitable for passing across the bridge to proxy in Javascript
+     */
+    public function getFunctionID(f:Function, createIfNecessary:Boolean):Number
+    {
+        var ref:Number;
+
+        if (createIfNecessary)
+        {
+            var newID:Number = nextID++;
+            localFunctionMap[newID] = f;
+            ref = newID;
+        }
+        else
+        {
+            for (var key:* in localFunctionMap)
+            {
+                if (localFunctionMap[key] === f) {
+                    ref = key;
+                }
+                break;
+            }
+        }
+
+        return ref;
+    }
+
+    /**
+     * returns a proxy function that represents a function defined in javascript. This function can be called syncrhonously, and will
+     * return any values returned by the JS function
+     */
+    public function getRemoteFunctionProxy(functionID:Number, createIfNecessary:Boolean):Function
+    {
+        try
+        {
+            if (remoteFunctionCache[functionID] == null)
+            {
+                remoteFunctionCache[functionID] = function(...args):*
+                {
+                    var externalArgs:Array = args.concat();
+                    externalArgs.unshift(functionID);
+                    var serializedArgs:* = serialize(externalArgs, true);
+                    
+                    if(checkToThrowLater(serializedArgs[1]))
+                    {
+                        setTimeout(function a():* {   
+                            try {                            
+                                var retVal:* = ExternalInterface.call("FABridge__invokeJSFunction", serializedArgs);
+                                for(var i:int = 0; i<serializedArgs.length; i++)
+                                {
+                                    if(typeof(serializedArgs[i]) == "object" && serializedArgs[i]!=null) 
+                                    {
+                                        releaseRef(serializedArgs[i].value);
+                                    }
+                                }
+                                return retVal;
+                            }
+                            catch(e:Error)
+                            {
+                                return serialize("__FLASHERROR__"+"||"+e.message);
+                            }
+                        },1);
+                    }
+                    else
+                    {
+                        var retVal:* = ExternalInterface.call("FABridge__invokeJSFunction", serializedArgs);
+                        for(var i:int = 0; i<serializedArgs.length; i++)
+                        {
+                            if(typeof(serializedArgs[i]) == "object" && serializedArgs[i]!=null) 
+                            {
+                                releaseRef(serializedArgs[i].value);
+                            }
+                        }
+                        return retVal;
+                    }
+                }
+            }
+        }
+        catch(e:Error)
+        {
+            return serialize("__FLASHERROR__"+"||"+e.message);
+        }
+
+        return remoteFunctionCache[functionID];
+    }
+    
+    /**
+     * function that checks if the object on which we are working demands that it should be called at a later time, breaking the call chain
+     * we check the actual object, as well as the bsae class and interfaces
+     */
+    private function checkToThrowLater(obj:Object):Boolean
+    {
+        obj = resolveRef(obj.value);
+        var className:String = getQualifiedClassName(obj);
+        var classInfo:XML = describeType(obj);
+        
+        if (FABridge.EventsToCallLater[className] != null) {
+                return true;
+        }
+
+        //check if this class doesn't inherit from one of the entries in the table
+        var inheritanceInfo:XMLList = describeType(obj).extendsClass;
+        for each (var inherit:XML in inheritanceInfo)
+        {
+            className = inherit.@type.toString();
+            if (FABridge.EventsToCallLater[className] != null) {
+                    return true;
+            }
+        } //end for going through inheritance tree
+        
+        //if we're still here, check the interfaces as well
+
+        var interfaceInfo:XMLList = describeType(obj).implementsInterface;
+        for each (var interf:XML in interfaceInfo)
+        {
+            className = interf.@type.toString();
+            if (FABridge.EventsToCallLater[className] != null) {
+                    return true;
+            }
+        } //end for going through inheritance tree
+
+        //if nothing was found, return false, so the function gets executed
+        return false;        
+    }
+
+    // callbacks exposed to JS
+
+    /**
+     * called to fetch a named property off the instanced associated with objID
+     */
+    public function js_getPropFromAS(objID:Number, propName:String):*
+    {
+        incRef(objID);
+        try
+        {
+            var obj:Object = resolveRef(objID); 
+            var ret:* = serialize(obj[propName], true);
+            releaseRef(objID);
+            return ret;
+        }
+        catch (e:ItemPendingError)
+        {
+            releaseRef(objID);
+            //ItemPendingError
+            //return serialize("an error occcured with" + obj[propName]);
+        }
+        catch(e:Error)
+        {
+            releaseRef(objID);
+            return serialize("__FLASHERROR__" + "||" + e.message);
+        }    
+    }
+
+    /**
+     * called to set a named property on the instance associated with objID
+     */
+    private function js_setPropertyInAS(objID:Number, propRef:String, value:*):*
+    {
+        incRef(objID);
+        try {
+            var obj:Object = resolveRef(objID);
+            obj[propRef] = deserialize(value);
+            releaseRef(objID);
+        }
+        catch(e:Error)
+        {
+            releaseRef(objID);
+            return serialize("__FLASHERROR__" + "||" + e.message);
+        }
+    }
+
+    /**
+     * accessor for retrieveing a proxy to the root object from JS
+     */
+    private function js_getRoot():*
+    {
+        try
+        {
+            //always get the root; this is the same as the get property, only it is the root object
+            var objRef:Number = getRef(baseObject, false);
+            if (isNaN(objRef))
+            {
+                //create the reference if necessary
+                objRef = getRef(baseObject, true);
+                incRef(objRef);
+            }
+            return serialize(baseObject);
+        }
+        catch(e:Error)
+        {
+            return serialize("__FLASHERROR__"+"||"+e.message);
+        }
+    }
+
+    /** 
+     * called to invoke a function or closure associated with funcID
+     */
+    private function js_invokeFunction(funcID:Number, args:Object):*
+    {
+        var result:*;
+        try
+        {
+            var func:Function = resolveFunctionID(funcID);
+            if(func != null)
+                result = func.apply(null, deserialize(args));
+
+            return serialize(result, true);
+        }
+        catch(e:Error)
+        {
+            return serialize("__FLASHERROR__"+"||"+e.message);
+        }
+    }
+
+    /**
+     * called to invoke a named method on the object associated with objID
+     */
+    private function js_invokeMethod(objID:Number, methodName:String, args:Object):*
+    {
+        incRef(objID);
+        try
+        {
+            var obj:Object = resolveRef(objID);
+            var result:*;
+
+            //check if the method is callable right now, or later
+            var callLater:Boolean = checkToExecuteLater(obj, methodName);
+
+            if (callLater) {
+                var t:Timer = new Timer(200, 1);
+                t.addEventListener(TimerEvent.TIMER, function():void {
+                    var ret_inner:* = serialize(obj[methodName].apply(null, deserialize(args)), true);
+                    releaseRef(objID);
+                });
+                t.start();
+            } else {
+                var ret:* = serialize(obj[methodName].apply(null, deserialize(args)), true);
+                releaseRef(objID);
+                return ret;
+            }
+        }
+        catch (e:ItemPendingError)
+        {
+            releaseRef(objID);
+            // ignore ItemPendingError
+        }
+        catch(e:Error)
+        {
+            releaseRef(objID);
+            return serialize("__FLASHERROR__" + "||" + e.message);
+        }
+    }
+    
+    /**
+     * method that performs a check on the specified object and method to see if their execution should be delayed or not
+     * it checks the object, its base class and implemented interfaces
+     */
+    private function checkToExecuteLater(obj:Object, methodName:String):Boolean
+    {
+        var methods:String;
+        var className:String = getQualifiedClassName(obj);
+        var classInfo:XML = describeType(obj);
+        
+        if (FABridge.MethodsToCallLater[className] != null) {
+            methods = FABridge.MethodsToCallLater[className];
+            //must call later
+            if(methods.match(methodName)) 
+            {
+                return true;
+            }
+        }
+
+        //check if this class doesn't inherit from one of the entries in the table
+        var inheritanceInfo:XMLList = describeType(obj).extendsClass;
+        for each (var inherit:XML in inheritanceInfo)
+        {
+            className = inherit.@type.toString();
+            if (FABridge.MethodsToCallLater[className] != null) {
+                methods = FABridge.MethodsToCallLater[className];
+                //must call later
+                if(methods.match(methodName)) 
+                {
+                    return true;
+                }
+            }
+        } //end for going through inheritance tree
+        
+        //if we're still here, check the interfaces as well
+
+        var interfaceInfo:XMLList = describeType(obj).implementsInterface;
+        for each (var interf:XML in interfaceInfo)
+        {
+            className = interf.@type.toString();
+            if (FABridge.MethodsToCallLater[className] != null) {
+                methods = FABridge.MethodsToCallLater[className];
+                //must call later
+                if(methods.match(methodName)) 
+                {
+                    return true;
+                }
+            }
+        } //end for going through inheritance tree
+
+        //if nothing was found, return false, so the function gets executed
+        return false;        
+    }
+
+    /**
+     * callback from JS to release all AS Objects from the local cache maps
+     */
+    private function js_releaseASObjects():void
+    {
+        localTypeMap = new Dictionary();
+        localInstanceMap = new Dictionary();
+        localFunctionMap = new Dictionary();
+    }
+   
+    /**
+     * callback from JS to release a specific object, identified by its ID
+     */
+    private function js_releaseNamedASObject(objId:int):Boolean
+    {  
+        var retVal:Boolean = false;
+        if (localInstanceMap[objId] != null)
+        {
+            delete refMap[objId];
+            delete localInstanceMap[objId];        
+            retVal = true;
+        }
+        return retVal;    
+    }    
+    
+    /**
+     * callback for js to create a new class instance.
+     */
+
+    private function js_create(className:String):*
+    {
+        try
+        {
+            var c:Class = Class(ApplicationDomain.currentDomain.getDefinition(className));
+            var instance:Object = new c();
+        }
+        catch(e:Error)
+        {
+            return serialize("__FLASHERROR__" + "||" + e.message);
+        }
+
+        // make sure the reference is known
+        var objRef:Number = getRef(instance, true);
+        incRef(objRef);
+        return serialize(instance);
+    }
+
+}
+}

Propchange: incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.as
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.as
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.js
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.js?rev=1351406&view=auto
==============================================================================
--- incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.js (added)
+++ incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.js Mon Jun 18 16:26:14 2012
@@ -0,0 +1,590 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+/*
+ * The Bridge class, responsible for navigating AS instances
+ */
+function FABridge(target,bridgeName)
+{
+    this.target = target;
+    this.remoteTypeCache = {};
+    this.remoteInstanceCache = {};
+    this.remoteFunctionCache = {};
+    this.localFunctionCache = {};
+    this.bridgeID = FABridge.nextBridgeID++;
+    this.name = bridgeName;
+    this.nextLocalFuncID = 0;
+    FABridge.instances[this.name] = this;
+    FABridge.idMap[this.bridgeID] = this;
+
+    return this;
+}
+
+// type codes for packed values
+FABridge.TYPE_ASINSTANCE =  1;
+FABridge.TYPE_ASFUNCTION =  2;
+
+FABridge.TYPE_JSFUNCTION =  3;
+FABridge.TYPE_ANONYMOUS =   4;
+
+FABridge.initCallbacks = {}
+
+FABridge.argsToArray = function(args)
+{
+    var result = [];
+    for (var i = 0; i < args.length; i++)
+    {
+        result[i] = args[i];
+    }
+    return result;
+}
+
+function instanceFactory(objID)
+{
+    this.fb_instance_id = objID;
+    return this;
+}
+
+function FABridge__invokeJSFunction(args)
+{  
+    var funcID = args[0];
+    var throughArgs = args.concat();//FABridge.argsToArray(arguments);
+    throughArgs.shift();
+   
+    var bridge = FABridge.extractBridgeFromID(funcID);
+    return bridge.invokeLocalFunction(funcID, throughArgs);
+}
+
+FABridge.addInitializationCallback = function(bridgeName, callback)
+{
+    var inst = FABridge.instances[bridgeName];
+    if (inst != undefined)
+    {
+        callback.call(inst);
+        return;
+    }
+
+    var callbackList = FABridge.initCallbacks[bridgeName];
+    if(callbackList == null)
+    {
+        FABridge.initCallbacks[bridgeName] = callbackList = [];
+    }
+
+    callbackList.push(callback);
+}
+
+function FABridge__bridgeInitialized(bridgeName) {
+    var objects = document.getElementsByTagName("object");
+    var ol = objects.length;
+    var activeObjects = [];
+    if (ol > 0) {
+		for (var i = 0; i < ol; i++) {
+			if (typeof objects[i].SetVariable != "undefined") {
+				activeObjects[activeObjects.length] = objects[i];
+			}
+		}
+	}
+    var embeds = document.getElementsByTagName("embed");
+    var el = embeds.length;
+    var activeEmbeds = [];
+    if (el > 0) {
+		for (var j = 0; j < el; j++) {
+			if (typeof embeds[j].SetVariable != "undefined") {
+            	activeEmbeds[activeEmbeds.length] = embeds[j];
+            }
+        }
+    }
+    var aol = activeObjects.length;
+    var ael = activeEmbeds.length;
+    var searchStr = "bridgeName="+ bridgeName;
+    if ((aol == 1 && !ael) || (aol == 1 && ael == 1)) {
+    	FABridge.attachBridge(activeObjects[0], bridgeName);	 
+    }
+    else if (ael == 1 && !aol) {
+    	FABridge.attachBridge(activeEmbeds[0], bridgeName);
+        }
+    else {
+                var flash_found = false;
+		if (aol > 1) {
+			for (var k = 0; k < aol; k++) {
+				 var params = activeObjects[k].childNodes;
+				 for (var l = 0; l < params.length; l++) {
+					var param = params[l];
+					if (param.nodeType == 1 && param.tagName.toLowerCase() == "param" && param["name"].toLowerCase() == "flashvars" && param["value"].indexOf(searchStr) >= 0) {
+						FABridge.attachBridge(activeObjects[k], bridgeName);
+                            flash_found = true;
+                            break;
+                        }
+                    }
+                if (flash_found) {
+                    break;
+                }
+            }
+        }
+		if (!flash_found && ael > 1) {
+			for (var m = 0; m < ael; m++) {
+				var flashVars = activeEmbeds[m].attributes.getNamedItem("flashVars").nodeValue;
+				if (flashVars.indexOf(searchStr) >= 0) {
+					FABridge.attachBridge(activeEmbeds[m], bridgeName);
+					break;
+    }
+            }
+        }
+    }
+    return true;
+}
+
+// used to track multiple bridge instances, since callbacks from AS are global across the page.
+
+FABridge.nextBridgeID = 0;
+FABridge.instances = {};
+FABridge.idMap = {};
+FABridge.refCount = 0;
+
+FABridge.extractBridgeFromID = function(id)
+{
+    var bridgeID = (id >> 16);
+    return FABridge.idMap[bridgeID];
+}
+
+FABridge.attachBridge = function(instance, bridgeName)
+{
+    var newBridgeInstance = new FABridge(instance, bridgeName);
+
+    FABridge[bridgeName] = newBridgeInstance;
+
+/*  FABridge[bridgeName] = function() {
+        return newBridgeInstance.root();
+    }
+*/
+    var callbacks = FABridge.initCallbacks[bridgeName];
+    if (callbacks == null)
+    {
+        return;
+    }
+    for (var i = 0; i < callbacks.length; i++)
+    {
+        callbacks[i].call(newBridgeInstance);
+    }
+    delete FABridge.initCallbacks[bridgeName]
+}
+
+// some methods can't be proxied.  You can use the explicit get,set, and call methods if necessary.
+
+FABridge.blockedMethods =
+{
+    toString: true,
+    get: true,
+    set: true,
+    call: true
+};
+
+FABridge.prototype =
+{
+
+
+// bootstrapping
+
+    root: function()
+    {
+        return this.deserialize(this.target.getRoot());
+    },
+//clears all of the AS objects in the cache maps
+    releaseASObjects: function()
+    {
+        return this.target.releaseASObjects();
+    },
+//clears a specific object in AS from the type maps
+    releaseNamedASObject: function(value)
+    {
+        if(typeof(value) != "object")
+        {
+            return false;
+        }
+        else
+        {
+            var ret =  this.target.releaseNamedASObject(value.fb_instance_id);
+            return ret;
+        }
+    },
+//create a new AS Object
+    create: function(className)
+    {
+        return this.deserialize(this.target.create(className));
+    },
+
+
+    // utilities
+
+    makeID: function(token)
+    {
+        return (this.bridgeID << 16) + token;
+    },
+
+
+    // low level access to the flash object
+
+//get a named property from an AS object
+    getPropertyFromAS: function(objRef, propName)
+    {
+        if (FABridge.refCount > 0)
+        {
+            throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
+        }
+        else
+        {
+            FABridge.refCount++;
+            retVal = this.target.getPropFromAS(objRef, propName);
+            retVal = this.handleError(retVal);
+            FABridge.refCount--;
+            return retVal;
+        }
+    },
+//set a named property on an AS object
+    setPropertyInAS: function(objRef,propName, value)
+    {
+        if (FABridge.refCount > 0)
+        {
+            throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
+        }
+        else
+        {
+            FABridge.refCount++;
+            retVal = this.target.setPropInAS(objRef,propName, this.serialize(value));
+            retVal = this.handleError(retVal);
+            FABridge.refCount--;
+            return retVal;
+        }
+    },
+
+//call an AS function
+    callASFunction: function(funcID, args)
+    {
+        if (FABridge.refCount > 0)
+        {
+            throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
+        }
+        else
+        {
+            FABridge.refCount++;
+            retVal = this.target.invokeASFunction(funcID, this.serialize(args));
+            retVal = this.handleError(retVal);
+            FABridge.refCount--;
+            return retVal;
+        }
+    },
+//call a method on an AS object
+    callASMethod: function(objID, funcName, args)
+    {
+        if (FABridge.refCount > 0)
+        {
+            throw new Error("You are trying to call recursively into the Flash Player which is not allowed. In most cases the JavaScript setTimeout function, can be used as a workaround.");
+        }
+        else
+        {
+            FABridge.refCount++;
+            args = this.serialize(args);
+            retVal = this.target.invokeASMethod(objID, funcName, args);
+            retVal = this.handleError(retVal);
+            FABridge.refCount--;
+            return retVal;
+        }
+    },
+
+    // responders to remote calls from flash
+
+    //callback from flash that executes a local JS function
+    //used mostly when setting js functions as callbacks on events
+    invokeLocalFunction: function(funcID, args)
+    {
+        var result;
+        var func = this.localFunctionCache[funcID];
+
+        if(func != undefined)
+        {
+            result = this.serialize(func.apply(null, this.deserialize(args)));
+        }
+
+        return result;
+    },
+
+    // Object Types and Proxies
+	
+    // accepts an object reference, returns a type object matching the obj reference.
+    getTypeFromName: function(objTypeName)
+    {
+        return this.remoteTypeCache[objTypeName];
+    },
+    //create an AS proxy for the given object ID and type
+    createProxy: function(objID, typeName)
+    {
+        var objType = this.getTypeFromName(typeName);
+	        instanceFactory.prototype = objType;
+	        var instance = new instanceFactory(objID);
+        this.remoteInstanceCache[objID] = instance;
+        return instance;
+    },
+    //return the proxy associated with the given object ID
+    getProxy: function(objID)
+    {
+        return this.remoteInstanceCache[objID];
+    },
+
+    // accepts a type structure, returns a constructed type
+    addTypeDataToCache: function(typeData)
+    {
+        newType = new ASProxy(this, typeData.name);
+        var accessors = typeData.accessors;
+        for (var i = 0; i < accessors.length; i++)
+        {
+            this.addPropertyToType(newType, accessors[i]);
+        }
+
+        var methods = typeData.methods;
+        for (var i = 0; i < methods.length; i++)
+        {
+            if (FABridge.blockedMethods[methods[i]] == undefined)
+            {
+                this.addMethodToType(newType, methods[i]);
+            }
+        }
+
+
+        this.remoteTypeCache[newType.typeName] = newType;
+        return newType;
+    },
+
+    //add a property to a typename; used to define the properties that can be called on an AS proxied object
+    addPropertyToType: function(ty, propName)
+    {
+        var c = propName.charAt(0);
+        var setterName;
+        var getterName;
+        if(c >= "a" && c <= "z")
+        {
+            getterName = "get" + c.toUpperCase() + propName.substr(1);
+            setterName = "set" + c.toUpperCase() + propName.substr(1);
+        }
+        else
+        {
+            getterName = "get" + propName;
+            setterName = "set" + propName;
+        }
+        ty[setterName] = function(val)
+        {
+            this.bridge.setPropertyInAS(this.fb_instance_id, propName, val);
+        }
+        ty[getterName] = function()
+        {
+            return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
+        }
+    },
+
+    //add a method to a typename; used to define the methods that can be callefd on an AS proxied object
+    addMethodToType: function(ty, methodName)
+    {
+        ty[methodName] = function()
+        {
+            return this.bridge.deserialize(this.bridge.callASMethod(this.fb_instance_id, methodName, FABridge.argsToArray(arguments)));
+        }
+    },
+
+    // Function Proxies
+
+    //returns the AS proxy for the specified function ID
+    getFunctionProxy: function(funcID)
+    {
+        var bridge = this;
+        if (this.remoteFunctionCache[funcID] == null)
+        {
+            this.remoteFunctionCache[funcID] = function()
+            {
+                bridge.callASFunction(funcID, FABridge.argsToArray(arguments));
+            }
+        }
+        return this.remoteFunctionCache[funcID];
+    },
+    
+    //reutrns the ID of the given function; if it doesnt exist it is created and added to the local cache
+    getFunctionID: function(func)
+    {
+        if (func.__bridge_id__ == undefined)
+        {
+            func.__bridge_id__ = this.makeID(this.nextLocalFuncID++);
+            this.localFunctionCache[func.__bridge_id__] = func;
+        }
+        return func.__bridge_id__;
+    },
+
+    // serialization / deserialization
+
+    serialize: function(value)
+    {
+        var result = {};
+
+        var t = typeof(value);
+        //primitives are kept as such
+        if (t == "number" || t == "string" || t == "boolean" || t == null || t == undefined)
+        {
+            result = value;
+        }
+        else if (value instanceof Array)
+        {
+            //arrays are serializesd recursively
+            result = [];
+            for (var i = 0; i < value.length; i++)
+            {
+                result[i] = this.serialize(value[i]);
+            }
+        }
+        else if (t == "function")
+        {
+            //js functions are assigned an ID and stored in the local cache 
+            result.type = FABridge.TYPE_JSFUNCTION;
+            result.value = this.getFunctionID(value);
+        }
+        else if (value instanceof ASProxy)
+        {
+            result.type = FABridge.TYPE_ASINSTANCE;
+            result.value = value.fb_instance_id;
+        }
+        else
+        {
+            result.type = FABridge.TYPE_ANONYMOUS;
+            result.value = value;
+        }
+
+        return result;
+    },
+
+    //on deserialization we always check the return for the specific error code that is used to marshall NPE's into JS errors
+    // the unpacking is done by returning the value on each pachet for objects/arrays 
+    deserialize: function(packedValue)
+    {
+
+        var result;
+
+        var t = typeof(packedValue);
+        if (t == "number" || t == "string" || t == "boolean" || packedValue == null || packedValue == undefined)
+        {
+            result = this.handleError(packedValue);
+        }
+        else if (packedValue instanceof Array)
+        {
+            result = [];
+            for (var i = 0; i < packedValue.length; i++)
+            {
+                result[i] = this.deserialize(packedValue[i]);
+            }
+        }
+        else if (t == "object")
+        {
+            for(var i = 0; i < packedValue.newTypes.length; i++)
+            {
+                this.addTypeDataToCache(packedValue.newTypes[i]);
+            }
+            for (var aRefID in packedValue.newRefs)
+            {
+                this.createProxy(aRefID, packedValue.newRefs[aRefID]);
+            }
+            if (packedValue.type == FABridge.TYPE_PRIMITIVE)
+            {
+                result = packedValue.value;
+            }
+            else if (packedValue.type == FABridge.TYPE_ASFUNCTION)
+            {
+                result = this.getFunctionProxy(packedValue.value);
+            }
+            else if (packedValue.type == FABridge.TYPE_ASINSTANCE)
+            {
+                result = this.getProxy(packedValue.value);
+            }
+            else if (packedValue.type == FABridge.TYPE_ANONYMOUS)
+            {
+                result = packedValue.value;
+            }
+        }
+        return result;
+    },
+    //increases the reference count for the given object
+    addRef: function(obj)
+    {
+        this.target.incRef(obj.fb_instance_id);
+    },
+    //decrease the reference count for the given object and release it if needed
+    release:function(obj)
+    {
+        this.target.releaseRef(obj.fb_instance_id);
+    },
+
+    // check the given value for the components of the hard-coded error code : __FLASHERROR
+    // used to marshall NPE's into flash
+    
+    handleError: function(value)
+    {
+        if (typeof(value)=="string" && value.indexOf("__FLASHERROR")==0)
+        {
+            var myErrorMessage = value.split("||");
+            if(FABridge.refCount > 0 )
+            {
+                FABridge.refCount--;
+            }
+            throw new Error(myErrorMessage[1]);
+            return value;
+        }
+        else
+        {
+            return value;
+        }   
+    }
+};
+
+// The root ASProxy class that facades a flash object
+
+ASProxy = function(bridge, typeName)
+{
+    this.bridge = bridge;
+    this.typeName = typeName;
+    return this;
+};
+//methods available on each ASProxy object
+ASProxy.prototype =
+{
+    get: function(propName)
+    {
+        return this.bridge.deserialize(this.bridge.getPropertyFromAS(this.fb_instance_id, propName));
+    },
+
+    set: function(propName, value)
+    {
+        this.bridge.setPropertyInAS(this.fb_instance_id, propName, value);
+    },
+
+    call: function(funcName, args)
+    {
+        this.bridge.callASMethod(this.fb_instance_id, funcName, args);
+    }, 
+    
+    addRef: function() {
+        this.bridge.addRef(this);
+    }, 
+    
+    release: function() {
+        this.bridge.release(this);
+    }
+};

Propchange: incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.js
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/flex/trunk/frameworks/javascript/FABridge/src/bridge/FABridge.js
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/flex/trunk/frameworks/javascript/build.xml
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/frameworks/javascript/build.xml?rev=1351406&view=auto
==============================================================================
--- incubator/flex/trunk/frameworks/javascript/build.xml (added)
+++ incubator/flex/trunk/frameworks/javascript/build.xml Mon Jun 18 16:26:14 2012
@@ -0,0 +1,134 @@
+<?xml version="1.0"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+-->
+<project name="frameworks" default="main" basedir=".">
+
+    <property name="FLEX_HOME" value="../.."/>
+	<property file="${FLEX_HOME}/build.properties"/>
+
+	<target name="main" depends="clean,samples,srcview" description="Clean build of FABridge"/>
+
+	<target name="clean" description="cleans all generated and staged files">
+		<delete>
+			<fileset dir="FABridge/samples/srcview" includes="SourceTree.html,swfobject.js,fabridge.zip"/>
+			<fileset dir="FABridge/samples/srcview/source">
+				<include name="app.swf"/>
+				<include name="EmptySwf.swf"/>
+				<include name="FABridgeSample.html"/>
+				<include name="FABridgeSample.js"/>
+				<include name="SimpleSample.html"/>
+			</fileset>
+		</delete>
+		<delete includeemptydirs="true" failonerror="false">
+			<fileset dir="FABridge/samples">
+			    <include name="**/*.swf"/>
+			</fileset>
+			<fileset dir="FABridge/samples/fabridge"/>
+			<fileset dir="FABridge/samples/srcview/source/fabridge/javascript"/>
+			<fileset dir="FABridge/samples/srcview/source/fabridge/swfobject"/>
+		</delete>
+  	</target>
+
+	<target name="samples" description="build samples" depends="compile-swfs">
+		<mkdir dir="FABridge/samples/fabridge/javascript"/>
+        <mkdir dir="FABridge/samples/fabridge/swfobject"/>
+		<copy file="FABridge/src/bridge/FABridge.js" todir="FABridge/samples/fabridge/javascript" />
+		<copy file="../../templates/swfobject/swfobject.js" todir="FABridge/samples/fabridge/swfobject" />
+	</target>
+	
+    <macrodef name="compile-sample">
+    <attribute name="file"/>
+        <sequential>
+            <echo message="Compiling @{file}"/>
+            <taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/lib/flexTasks.jar"/>
+            <mxmlc fork="true"
+                file="@{file}">
+                <jvmarg line="${mxmlc.jvm.args}"/>
+                <load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/>
+                <source-path path-element="${basedir}/FABridge/src"/>
+            </mxmlc>
+        </sequential>
+    </macrodef>
+
+	<target name="compile-swfs" description="Compile the sample swfs.">
+	    <compile-sample file="${basedir}/FABridge/samples/EmptySwf.as"/>
+	    <compile-sample file="${basedir}/FABridge/samples/app.mxml"/>
+	</target>
+	
+	<target name="srcview" description="build srcview app">
+        <copy file="../../templates/swfobject/swfobject.js" todir="FABridge/samples/srcview" />
+        
+        <!-- generate SourceTree.html using the standard html-wrapper template -->
+        <copy file="../../templates/swfobject/index.template.html" tofile="FABridge/samples/srcview/SourceTree.html" />
+		<replace file="FABridge/samples/srcview/SourceTree.html">
+			<replacefilter
+				token="$${expressInstallSwf}"
+				value="playerProductInstall.swf"/>
+			<replacefilter
+				token="$${useBrowserHistory}"
+				value=""/>
+			<replacefilter
+				token="$${version_major}"
+				value="10"/>
+			<replacefilter
+				token="$${version_minor}"
+				value="0"/>
+			<replacefilter
+				token="$${version_revision}"
+				value="0"/>
+			<replacefilter
+				token="$${title}"
+				value="SourceTree Application"/>
+			<replacefilter
+				token="$${bgcolor}"
+				value="#ffffff"/>
+			<replacefilter
+				token="$${width}"
+				value="100%"/>
+			<replacefilter
+				token="$${height}"
+				value="100%"/>
+			<replacefilter
+				token="$${swf}"
+				value="SourceTree"/>
+			<replacefilter
+				token="$${application}"
+				value="SourceTree"/>
+		</replace>
+		
+		<!-- stage the source area so the zipfile used by the srcview app can be build -->
+		<mkdir dir="FABridge/samples/srcview/source/fabridge/swfobject"/>
+        <mkdir dir="FABridge/samples/srcview/source/fabridge/javascript"/>
+		
+		<copy file="../../templates/swfobject/swfobject.js" todir="FABridge/samples/srcview/source/fabridge/swfobject" />
+ 		
+        <copy file="FABridge/src/bridge/FABridge.js" todir="FABridge/samples/srcview/source/fabridge/javascript" />
+        <copy todir="FABridge/samples/srcview/source">
+			<fileset dir="FABridge/samples">
+				<include name="FABridgeSample.html"/>
+				<include name="FABridgeSample.js"/>
+				<include name="SimpleSample.html"/>
+				<include name="app.swf"/>
+				<include name="EmptySwf.swf"/>
+			</fileset>
+		</copy>
+		<zip destfile="FABridge/samples/srcview/fabridge.zip" basedir="FABridge/samples/srcview/source"/>
+	</target>
+
+</project>

Propchange: incubator/flex/trunk/frameworks/javascript/build.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/flex/trunk/frameworks/javascript/build.xml
------------------------------------------------------------------------------
    svn:mime-type = text/plain