http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/utils/LoaderUtil.as ---------------------------------------------------------------------- diff --cc frameworks/projects/MX/src/main/flex/mx/utils/LoaderUtil.as index 26f2e4e,0000000..94166ac mode 100644,000000..100644 --- a/frameworks/projects/MX/src/main/flex/mx/utils/LoaderUtil.as +++ b/frameworks/projects/MX/src/main/flex/mx/utils/LoaderUtil.as @@@ -1,679 -1,0 +1,679 @@@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.utils +{ - COMPILE::AS3 ++COMPILE::SWF +{ +import flash.display.DisplayObject; +import flash.display.Loader; +import flash.display.LoaderInfo; +import flash.events.IEventDispatcher; +import flash.system.Capabilities; +import flash.utils.Dictionary; +} +COMPILE::JS +{ +} +COMPILE::LATER +{ +import mx.core.ApplicationDomainTarget; +import mx.core.RSLData; +} +import mx.core.IFlexModuleFactory; +import mx.core.mx_internal; +import mx.events.Request; +import mx.managers.SystemManagerGlobals; +import mx.utils.Platform; + +use namespace mx_internal; + + /** + * The LoaderUtil class defines utility methods for use with Flex RSLs and + * generic Loader instances. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public class LoaderUtil + { + + include "../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Class variables + // + //-------------------------------------------------------------------------- + + /** + * @private + * + * An array of search strings and filters. These are used in the normalizeURL + * method. normalizeURL is used to remove special Flash Player markup from + * urls, but the array could be appended to by the user to modify urls in other + * ways. + * + * Each object in the array has two fields: + * + * 1. searchString - the string to search the url + * 2. filterFunction - a function that accepts an url and an index to the first + * occurrence of the search string in the url. The function may modify the url + * and return a new url. A filterFunction is only called once, for the first + * occurrence of where the searchString was found. If there + * are multiple strings in the url that need to be processed the filterFunction + * should handle all of them on the call. A filter function should + * be defined as follows: + * + * @param url the url to process. + * @param index the index of the first occurrence of the seachString in the url. + * @return the new url. + * + * function filterFunction(url:String, index:int):String + * + */ + mx_internal static var urlFilters:Array = + [ + { searchString: "/[[DYNAMIC]]/", filterFunction: dynamicURLFilter}, + { searchString: "/[[IMPORT]]/", filterFunction: importURLFilter} + ]; + + //-------------------------------------------------------------------------- + // + // Class methods + // + //-------------------------------------------------------------------------- + + /** + * The root URL of a cross-domain RSL contains special text + * appended to the end of the URL. + * This method normalizes the URL specified in the specified LoaderInfo instance + * to remove the appended text, if present. + * Classes accessing <code>LoaderInfo.url</code> should call this method + * to normalize the URL before using it. + * This method also encodes the url by calling the encodeURI() method + * on it. If you want the unencoded url, you must call unencodeURI() on + * the results. + * + * @param loaderInfo A LoaderInfo instance or url string. + * + * @return A normalized <code>LoaderInfo.url</code> property. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static function normalizeURL(loaderInfo:Object):String + { + var url:String; - COMPILE::AS3 ++ COMPILE::SWF + { + if (loaderInfo is LoaderInfo) + url = loaderInfo.url; + else + url = loaderInfo.toString(); + } + COMPILE::JS + { + url = loaderInfo.toString(); + } + var index:int; + var searchString:String; + var urlFilter:Function; + var n:uint = LoaderUtil.urlFilters.length; + + for (var i:uint = 0; i < n; i++) + { + searchString = LoaderUtil.urlFilters[i].searchString; + if ((index = url.indexOf(searchString)) != -1) + { + urlFilter = LoaderUtil.urlFilters[i].filterFunction; + url = urlFilter(url, index); + } + } + + // On the mac, the player doesn't like filenames with high-ascii + // characters. Calling encodeURI fixes this problem. We restrict + // this call to mac-only since it causes problems on Windows. + if (Platform.isMac) + return encodeURI(url); + + return url; + } + + /** + * @private + * + * Use this method when you want to load resources with relative URLs. + * + * Combine a root url with a possibly relative url to get a absolute url. + * Use this method to convert a relative url to an absolute URL that is + * relative to a root URL. + * + * @param rootURL An url that will form the root of the absolute url. + * If the <code>rootURL</code> does not specify a file name it must be + * terminated with a slash. For example, "http://a.com" is incorrect, it + * should be terminated with a slash, "http://a.com/". If the rootURL is + * taken from loaderInfo, it must be passed thru <code>normalizeURL</code> + * before being passed to this function. + * + * When loading resources relative to an application, the rootURL is + * typically the loaderInfo.url of the application. + * + * @param url The url of the resource to load (may be relative). + * + * @return If <code>url</code> is already an absolute URL, then it is + * returned as is. If <code>url</code> is relative, then an absolute URL is + * returned where <code>url</code> is relative to <code>rootURL</code>. + */ + public static function createAbsoluteURL(rootURL:String, url:String):String + { + var absoluteURL:String = url; + + // make relative paths relative to the SWF loading it, not the top-level SWF + if (rootURL && + !(url.indexOf(":") > -1 || url.indexOf("/") == 0 || url.indexOf("\\") == 0)) + { + // First strip off the search string and then any url fragments. + var index:int; + + if ((index = rootURL.indexOf("?")) != -1 ) + rootURL = rootURL.substring(0, index); + + if ((index = rootURL.indexOf("#")) != -1 ) + rootURL = rootURL.substring(0, index); + + // If the url starts from the current directory, then just skip + // over the "./". + // If the url start from the parent directory, the we need to + // modify the rootURL. + var lastIndex:int = Math.max(rootURL.lastIndexOf("\\"), rootURL.lastIndexOf("/")); + if (url.indexOf("./") == 0) + { + url = url.substring(2); + } + else + { + while (url.indexOf("../") == 0) + { + url = url.substring(3); + lastIndex = Math.max(rootURL.lastIndexOf("\\", lastIndex - 1), + rootURL.lastIndexOf("/", lastIndex - 1)); + } + } + + if (lastIndex != -1) + absoluteURL = rootURL.substr(0, lastIndex + 1) + url; + } + + return absoluteURL; + } + + /** + * @private + * + * Takes a list of required rsls and determines: + * - which RSLs have not been loaded + * - the application domain and IModuleFactory where the + * RSL should be loaded + * + * @param moduleFactory The module factory of the application or module + * to get load information for. If the moduleFactory has not loaded the + * module, then its parent is asked for load information. Each successive + * parent is asked until the load information is found or there are no + * more parents to ask. Only parents in parent ApplicationDomains are + * searched. Applications in different security domains or sibling + * ApplicationDomains do not share RSLs. + * + * @param rsls An array of RSLs that are required for + * <code>moduleFactory</code>. Each RSL is in an array of RSLData where + * the first element is the primary RSL and the remaining elements are + * failover RSLs. + * @return Array of RSLData that represents the RSLs to load. RSLs that are + * already loaded are not in the listed. + */ + COMPILE::LATER + mx_internal static function processRequiredRSLs(moduleFactory:IFlexModuleFactory, + rsls:Array):Array + { + var rslsToLoad:Array = []; // of Array, where each element is an array + // of RSLData (primary and failover), return value + var topLevelModuleFactory:IFlexModuleFactory = SystemManagerGlobals.topLevelSystemManagers[0]; + var currentModuleFactory:IFlexModuleFactory = topLevelModuleFactory; + var parentModuleFactory:IFlexModuleFactory = null; + var loaded:Dictionary = new Dictionary(); // contains rsls that are loaded + var loadedLength:int = 0; + var resolved:Dictionary = new Dictionary(); // contains rsls that have the app domain resolved + var resolvedLength:int = 0; + var moduleFactories:Array = null; + + // Start at the top level module factory and work our way down the + // module factory chain checking if the any of the rsls are loaded + // and resolving application domain targets. + // We start at the top level module factory because the default rsls + // will all be loaded here and we won't often have to check other + // module factories. + while (currentModuleFactory != moduleFactory) + { + // Need to loop over all the rsls, to see which one are loaded + // and resolve application domains. + var n:int = rsls.length; + for (var i:int = 0; i < n; i++) + { + var rsl:Array = rsls[i]; + + // Check if the RSL has already been loaded. + if (!loaded[rsl]) + { + if (isRSLLoaded(currentModuleFactory, rsl[0].digest)) + { + loaded[rsl] = 1; + loadedLength++; + + // We may find an rsl loaded in a module factory as we work + // our way down the module factory list. If we find one then + // remove it. + if (currentModuleFactory != topLevelModuleFactory) + { + var index:int = rslsToLoad.indexOf(rsl); + if (index != -1) + rslsToLoad.splice(index, 1); + } + } + else if (rslsToLoad.indexOf(rsl) == -1) + { + rslsToLoad.push(rsl); // assume we have to load it + } + } + + // If the rsl is already loaded or already resolved then + // skip resolving it. + if (!loaded[rsl] && resolved[rsl] == null) + { + // Get the parent module factory if we are going to need to + // resolve the application domain target. + if (!parentModuleFactory && + RSLData(rsl[0]).applicationDomainTarget == ApplicationDomainTarget.PARENT) + { + parentModuleFactory = getParentModuleFactory(moduleFactory); + } + + // Resolve the application domain target. + if (resolveApplicationDomainTarget(rsl, + moduleFactory, + currentModuleFactory, + parentModuleFactory, + topLevelModuleFactory)) + { + resolved[rsl] = 1; + resolvedLength++; + } + } + } + + // If process all rsls then get out. + if (loadedLength + resolvedLength >= rsls.length) + break; + + // If we didn't find everything in the top level module factory then work + // down towards the rsl's owning module factory. + // Build up the module factory parent chain so we can traverse it. + if (!moduleFactories) + { + moduleFactories = [moduleFactory]; + currentModuleFactory = moduleFactory; + while (currentModuleFactory != topLevelModuleFactory) + { + + currentModuleFactory = getParentModuleFactory(currentModuleFactory); + + // If we couldn't get the parent module factory, then we + // will have to load into the highest application domain + // that is available. We won't be able to get a parent + // if a module was loaded without specifying a parent + // module factory. + if (!currentModuleFactory) + break; + + if (currentModuleFactory != topLevelModuleFactory) + moduleFactories.push(currentModuleFactory); + + if (!parentModuleFactory) + parentModuleFactory = currentModuleFactory; + } + } + + currentModuleFactory = moduleFactories.pop(); + } + + return rslsToLoad; + } + + /** + * @private + * Test whether a url is on the local filesystem. We can only + * really tell this with URLs that begin with "file:" or a + * Windows-style drive notation such as "C:". This fails some + * cases like the "/" notation on Mac/Unix. + * + * @param url + * the url to check against + * + * @return + * true if url is local, false if not or unable to determine + **/ + mx_internal static function isLocal(url:String):Boolean + { + return (url.indexOf("file:") == 0 || url.indexOf(":") == 1); + } + + /** + * @private + * Currently (FP 10.x) the ActiveX player (Explorer on Windows) does not + * handle encoded URIs containing UTF-8 on the local filesystem, but + * it does handle those same URIs unencoded. The plug-in requires + * encoded URIs. + * + * @param url + * url to properly encode, may be fully or partially encoded with encodeURI + * + * @param local + * true indicates the url is on the local filesystem + * + * @return + * encoded url that may be loaded with a URLRequest + **/ - COMPILE::AS3 ++ COMPILE::SWF + mx_internal static function OSToPlayerURI(url:String, local:Boolean):String + { + + // First strip off the search string and any url fragments so + // they will not be decoded/encoded. + // Next decode the url. + // Before returning the decoded or encoded string add the search + // string and url fragment back. + var searchStringIndex:int; + var fragmentUrlIndex:int; + var decoded:String = url; + + if ((searchStringIndex = decoded.indexOf("?")) != -1 ) + { + decoded = decoded.substring(0, searchStringIndex); + } + + if ((fragmentUrlIndex = decoded.indexOf("#")) != -1 ) + decoded = decoded.substring(0, fragmentUrlIndex); + + try + { + // decode the url + decoded = decodeURI(decoded); + } + catch (e:Error) + { + // malformed url, but some are legal on the file system + } + + // create the string to hold the the search string url fragments. + var extraString:String = null; + if (searchStringIndex != -1 || fragmentUrlIndex != -1) + { + var index:int = searchStringIndex; + + if (searchStringIndex == -1 || + (fragmentUrlIndex != -1 && fragmentUrlIndex < searchStringIndex)) + { + index = fragmentUrlIndex; + } + + extraString = url.substr(index); + } + + if (local && flash.system.Capabilities.playerType == "ActiveX") + { + if (extraString) + return decoded + extraString; + else + return decoded; + } + + if (extraString) + return encodeURI(decoded) + extraString; + else + return encodeURI(decoded); + } + + /** + * @private + * Get the parent module factory. + * + * @param moduleFactory The module factory to get the parent of. + * + * @return the parent module factory if available, null otherwise. + */ - COMPILE::AS3 ++ COMPILE::SWF + private static function getParentModuleFactory(moduleFactory:IFlexModuleFactory):IFlexModuleFactory + { + var request:Request = new Request(Request.GET_PARENT_FLEX_MODULE_FACTORY_REQUEST); + DisplayObject(moduleFactory).dispatchEvent(request); + return request.value as IFlexModuleFactory; + } + + /** + * @private + * Resolve the application domain target. + * + * @param rsl to resolve. + * @param moduleFactory The module factory loading the RSLs. + * @param currentModuleFactory The module factory to search for placeholders. + * @param parentModuleFactory The rsl's parent module factory. + * @param topLevelModuleFactory The top-level module factory. + * + * @return true if the application domain target was resolved, + * false otherwise. + */ + COMPILE::LATER + private static function resolveApplicationDomainTarget(rsl:Array, + moduleFactory:IFlexModuleFactory, + currentModuleFactory:IFlexModuleFactory, + parentModuleFactory:IFlexModuleFactory, + topLevelModuleFactory:IFlexModuleFactory):Boolean + { + var resolvedRSL:Boolean = false; + var targetModuleFactory:IFlexModuleFactory = null; + + var applicationDomainTarget:String = rsl[0].applicationDomainTarget; + if (isLoadedIntoTopLevelApplicationDomain(moduleFactory)) + { + targetModuleFactory = topLevelModuleFactory; + } + else if (applicationDomainTarget == ApplicationDomainTarget.DEFAULT) + { + if (hasPlaceholderRSL(currentModuleFactory, rsl[0].digest)) + { + targetModuleFactory = currentModuleFactory; + } + } + else if (applicationDomainTarget == ApplicationDomainTarget.TOP_LEVEL) + { + targetModuleFactory = topLevelModuleFactory; + } + else if (applicationDomainTarget == ApplicationDomainTarget.CURRENT) + { + resolvedRSL = true; + } + else if (applicationDomainTarget == ApplicationDomainTarget.PARENT) + { + // If there is no parent, ignore the target and load into the current + // app domain. + targetModuleFactory = parentModuleFactory; + } + else + { + resolvedRSL = true; // bogus target, load into current application domain + } + + if (resolvedRSL || targetModuleFactory) + { + if (targetModuleFactory) + updateRSLModuleFactory(rsl, targetModuleFactory); + return true; + } + + return false; + } + + /** + * @private + * Determine if the moduleFactory has loaded an rsl that matches the + * specified digest. + * + * @param moduleFactory The module factory to search. + * @param digest The digest to search for. + * @return true if a loaded rsl matching the digest was found. + */ + COMPILE::LATER + private static function isRSLLoaded(moduleFactory:IFlexModuleFactory, digest:String):Boolean + { + var preloadedRSLs:Dictionary = moduleFactory.preloadedRSLs; + + if (preloadedRSLs) + { + // loop over the rsls to find a matching digest + for each (var rsl:Vector.<RSLData> in preloadedRSLs) + { + var n:int = rsl.length; + for (var i:int = 0; i < n; i++) + { + if (rsl[i].digest == digest) + { + return true; + } + } + } + } + + return false; + } + + /** + * @private + * + * Determine if the moduleFactory has a placeholder rsl that matches the + * specified digest. + * + * @param moduleFactory The module factory to search. + * @param digest The digest to search for. + * @return true if a placeholder rsl matching the digest was found. + */ + private static function hasPlaceholderRSL(moduleFactory:IFlexModuleFactory, digest:String):Boolean + { + var phRSLs:Array = moduleFactory.info()["placeholderRsls"]; + + if (phRSLs) + { + // loop over the rsls to find a matching digest + var n:int = phRSLs.length; + for (var i:int = 0; i < n; i++) + { + var rsl:Object = phRSLs[i]; + var m:int = rsl.length; + for (var j:int = 0; j < m; j++) + { + if (rsl[j].digest == digest) + { + return true; + } + } + } + } + + return false; + } + + /** + * @private + * Test if a module factory has been loaded into the top-level application domain. + * + * @return true if loaded into the top-level application domain, false otherwise. + */ + COMPILE::LATER + private static function isLoadedIntoTopLevelApplicationDomain(moduleFactory:IFlexModuleFactory):Boolean + { + if (moduleFactory is DisplayObject) + { + var displayObject:DisplayObject = DisplayObject(moduleFactory); + var loaderInfo:LoaderInfo = displayObject.loaderInfo; + if (loaderInfo && loaderInfo.applicationDomain && + loaderInfo.applicationDomain.parentDomain == null) + { + return true; + } + } + + return false; + } + + /** + * @private + * + * Update the module factory of an rsl, both the primary rsl and all + * failover rsls. + * + * @param rsl One RSL represented by an array of RSLData. The + * first element in the array is the primary rsl, the others are failovers. + * @param moduleFactory The moduleFactory to set in the primary and + * failover rsls. + */ + COMPILE::LATER + private static function updateRSLModuleFactory(rsl:Array, moduleFactory:IFlexModuleFactory):void + { + var n:int = rsl.length; + for (var i:int = 0; i < n; i++) + { + rsl[i].moduleFactory = moduleFactory; + } + } + + /** + * @private + * + * Strip off the DYNAMIC string(s) appended to the url. + */ + private static function dynamicURLFilter(url:String, index:int):String + { + return url.substring(0, index); + } + + /** + * @private + * + * Add together the protocol plus everything after "/[[IMPORT]]/". + */ + private static function importURLFilter(url:String, index:int):String + { + var protocolIndex:int = url.indexOf("://"); + return url.substring(0,protocolIndex + 3) + url.substring(index + 12); + } + + } - } ++}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/utils/NameUtil.as ---------------------------------------------------------------------- diff --cc frameworks/projects/MX/src/main/flex/mx/utils/NameUtil.as index 4f8f53d,0000000..7782458 mode 100644,000000..100644 --- a/frameworks/projects/MX/src/main/flex/mx/utils/NameUtil.as +++ b/frameworks/projects/MX/src/main/flex/mx/utils/NameUtil.as @@@ -1,195 -1,0 +1,195 @@@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.utils +{ + +import org.apache.flex.reflection.getQualifiedClassName; + +import mx.core.IRepeaterClient; +import mx.core.IUIComponent; + +/** + * The NameUtil utility class defines static methods for + * creating names for Flex objects. + * You do not create instances of NameUtil; + * instead you call static methods of the class, such as + * the <code>NameUtil.createName()</code> method. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public class NameUtil +{ + include "../core/Version.as"; + + //-------------------------------------------------------------------------- + // + // Class variables + // + //-------------------------------------------------------------------------- + + /** + * @private + */ + private static var counter:int = 0; + + //-------------------------------------------------------------------------- + // + // Class methods + // + //-------------------------------------------------------------------------- + + /** + * Creates a unique name for any Object instance, such as "Button12", by + * combining the unqualified class name with an incrementing counter. + * + * @param object Object requiring a name. + * + * @return String containing the unique name. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static function createUniqueName(object:Object):String + { + if (!object) + return null; + + var name:String = getQualifiedClassName(object); + + // If there is a package name, strip it off. + var index:int = name.indexOf("::"); + if (index != -1) + name = name.substr(index + 2); + + // If the class name ends with a digit (which some autogenerated + // classes do), then append an underscore before appending + // the counter. + var charCode:int = name.charCodeAt(name.length - 1); + if (charCode >= 48 && charCode <= 57) + name += "_"; + + return name + counter++; + } + + /** + * Returns a string, such as + * "MyApplication0.addressForm.lastName.TextField17", + * for a DisplayObject object that indicates its position in the + * hierarchy of DisplayObject objects in an application. + * + * @param displayObject A DisplayObject object whose hierarchy in the application + * is desired. + * + * @return String containing the position of <code>displayObject</code> + * in the hierarchy of DisplayObject objects in an application. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + * + * @flexjsignorecoercion mx.core.IUIComponent + */ + public static function displayObjectToString( + displayObject:IUIComponent):String + { + var result:String; + + // Start at the specified object and walk up the parent chain + // to build up the string to return. + try + { + for (var o:IUIComponent = displayObject; + o != null; + o = o.parent as IUIComponent) + { + // If this object is in the display tree, + // stop after we've prepended the topmost Application instance. + if (o.parent && o.topOfDisplayList && o.parent == o.topOfDisplayList) + break; + + // Prefer id over name if specified. + var s:String = "id" in o && o["id"] ? o["id"] : o.name; + + if (o is IRepeaterClient) + { + var indices:Array = IRepeaterClient(o).instanceIndices; + if (indices) + s += "[" + indices.join("][") + "]"; + } + + result = result == null ? s : s + "." + result; + } + } + catch (e:Error) + { - COMPILE::AS3 ++ COMPILE::SWF + { + if (!(e is SecurityError)) + throw e; + } + // Ignore error and continue with what we have. + // We may not have access to our parent if we are loaded into a sandbox. + } + + return result; + } + + /** + * Returns the name of the specified object's class, + * such as <code>"Button"</code> + * + * <p>This string does not include the package name. + * If you need the package name as well, call the + * <code>getQualifiedClassName()</code> method in the flash.utils package. + * It will return a string such as <code>"mx.controls::Button"</code>.</p> + * + * @param object The object. + * + * @return The name of the specified object's class. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public static function getUnqualifiedClassName(object:Object):String + { + var name:String; + if (object is String) + name = object as String; + else + name = getQualifiedClassName(object); + + // If there is a package name, strip it off. + var index:int = name.indexOf("::"); + if (index != -1) + name = name.substr(index + 2); + + return name; + } +} + +} http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/utils/ObjectProxy.as ---------------------------------------------------------------------- diff --cc frameworks/projects/MX/src/main/flex/mx/utils/ObjectProxy.as index a6f1591,0000000..2d0e0ee mode 100644,000000..100644 --- a/frameworks/projects/MX/src/main/flex/mx/utils/ObjectProxy.as +++ b/frameworks/projects/MX/src/main/flex/mx/utils/ObjectProxy.as @@@ -1,946 -1,0 +1,946 @@@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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. +// +//////////////////////////////////////////////////////////////////////////////// + +package mx.utils +{ + +import org.apache.flex.events.EventDispatcher; +import org.apache.flex.reflection.getQualifiedClassName; - COMPILE::AS3 ++COMPILE::SWF +{ +import flash.events.Event; +import flash.utils.IDataInput; +import flash.utils.IDataOutput; +import flash.utils.IExternalizable; +import flash.utils.flash_proxy; +} +COMPILE::JS +{ + import org.apache.flex.events.Event; + import flex.utils.IExternalizable; +} +import org.apache.flex.utils.Proxy; +import mx.core.IPropertyChangeNotifier; +import mx.events.PropertyChangeEvent; +import mx.events.PropertyChangeEventKind; + - COMPILE::AS3 ++COMPILE::SWF +{ +use namespace flash_proxy; +use namespace object_proxy; +} + +[Bindable("propertyChange")] +[RemoteClass(alias="flex.messaging.io.ObjectProxy")] + +/** + * This class provides the ability to track changes to an item + * managed by this proxy. + * Any number of objects can "listen" for changes on this + * object, by using the <code>addEventListener()</code> method. + * + * @example + * <pre> + * import mx.events.PropertyChangeEvent; + * import mx.utils.ObjectUtil; + * import mx.utils.ObjectProxy; + * import mx.utils.StringUtil; + * + * var a:Object = { name: "Tyler", age: 5, ssnum: "555-55-5555" }; + * var p:ObjectProxy = new ObjectProxy(a); + * p.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, updateHandler); + * p.name = "Jacey"; + * p.age = 2; + * delete p.ssnum; + * + * // handler function + * function updateHandler(event:ChangeEvent):void + * { + * trace(StringUtil.substitute("updateHandler('{0}', {1}, {2}, {3}, '{4}')", + * event.kind, + * event.property, + * event.oldValue, + * event.newValue, + * event.target.object_proxy::UUID)); + * } + * + * // The trace output appears as: + * // updateHandler('opUpdate', name, Tyler, Jacey, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2') + * // updateHandler('opUpdate', age, 5, 2, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2') + * // updateHandler('opDelete', ssnum, 555-55-5555, null, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2') + * </pre> + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ +public dynamic class ObjectProxy extends Proxy + implements IExternalizable, + IPropertyChangeNotifier +{ + //-------------------------------------------------------------------------- + // + // Constructor + // + //-------------------------------------------------------------------------- + + /** + * Initializes this proxy with the specified object, id and proxy depth. + * + * @param item Object to proxy. + * If no item is specified, an anonymous object will be constructed + * and assigned. + * + * @param uid String containing the unique id + * for this object instance. + * Required for IPropertyChangeNotifier compliance as every object must + * provide a unique way of identifying it. + * If no value is specified, a random id will be assigned. + * + * @param proxyDepth An integer indicating how many levels in a complex + * object graph should have a proxy created during property access. + * The default is -1, meaning "proxy to infinite depth". + * + * @example + * + * <pre> + * import mx.events.PropertyChangeEvent; + * import mx.utils.ObjectUtil; + * import mx.utils.ObjectProxy; + * import mx.utils.StringUtil; + * + * var a:Object = { name: "Tyler", age: 5, ssnum: "555-55-5555" }; + * var p:ObjectProxy = new ObjectProxy(a); + * p.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, updateHandler); + * p.name = "Jacey"; + * p.age = 2; + * delete p.ssnum; + * + * // handler function + * function updateHandler(event:PropertyChangeEvent):void + * { + * trace(StringUtil.substitute("updateHandler('{0}', {1}, {2}, {3}, '{4}')", + * event.kind, + * event.property, + * event.oldValue, + * event.newValue, + * event.target.uid)); + * } + * + * // trace output + * updateHandler('opUpdate', name, Jacey, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2') + * updateHandler('opUpdate', age, 2, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2') + * updateHandler('opDelete', ssnum, null, '698AF8CB-B3D9-21A3-1AFFDGHT89075CD2') + * </pre> + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function ObjectProxy(item:Object = null, uid:String = null, + proxyDepth:int = -1) + { + super(); + + if (!item) + item = {}; + _item = item; + + _proxyLevel = proxyDepth; + + notifiers = {}; + + dispatcher = new EventDispatcher(this); + + // If we got an id, use it. Otherwise the UID is lazily + // created in the getter for UID. + if (uid) + _id = uid; + } + + //-------------------------------------------------------------------------- + // + // Variables + // + //-------------------------------------------------------------------------- + + /** + * A reference to the EventDispatcher for this proxy. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + protected var dispatcher:EventDispatcher; + + /** + * A hashmap of property change notifiers that this proxy is + * listening for changes from; the key of the map is the property name. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + protected var notifiers:Object; + + /** + * Indicates what kind of proxy to create + * when proxying complex properties. + * Subclasses should assign this value appropriately. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + protected var proxyClass:Class = ObjectProxy; + + /** + * Contains a list of all of the property names for the proxied object. + * Descendants need to fill this list by overriding the + * <code>setupPropertyList()</code> method. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + protected var propertyList:Array; + + /** + * Indicates how deep proxying should be performed. + * If -1 (default), always proxy; + * if this value is zero, no proxying will be performed. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + private var _proxyLevel:int; + + //-------------------------------------------------------------------------- + // + // Properties + // + //-------------------------------------------------------------------------- + + //---------------------------------- + // object + //---------------------------------- + + /** + * Storage for the object property. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + private var _item:Object; + + /** + * The object being proxied. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + COMPILE::LATER + object_proxy function get object():Object + { + return _item; + } + + //---------------------------------- + // type + //---------------------------------- + + /** + * @private + * Storage for the qualified type name. + */ + COMPILE::LATER + private var _type:QName; + + /** + * The qualified type name associated with this object. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + COMPILE::LATER + object_proxy function get type():QName + { + return _type; + } + + /** + * @private + */ + COMPILE::LATER + object_proxy function set type(value:QName):void + { + _type = value; + } + + //---------------------------------- + // uid + //---------------------------------- + + /** + * @private + * Storage for the uid property. + */ + private var _id:String; + + /** + * The unique identifier for this object. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function get uid():String + { + if (_id === null) + _id = UIDUtil.createUID(); + + return _id; + } + + /** + * @private + */ + public function set uid(value:String):void + { + _id = value; + } + + //-------------------------------------------------------------------------- + // + // Overridden methods + // + //-------------------------------------------------------------------------- + + /** + * Returns the specified property value of the proxied object. + * + * @param name Typically a string containing the name of the property, + * or possibly a QName where the property name is found by + * inspecting the <code>localName</code> property. + * + * @return The value of the property. + * In some instances this value may be an instance of + * <code>ObjectProxy</code>. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + override flash_proxy function getProperty(name:*):* + { + // if we have a data proxy for this then + var result:*; + + if (notifiers[name.toString()]) + return notifiers[name]; + + result = _item[name]; + + if (result) + { + if (_proxyLevel == 0 || ObjectUtil.isSimple(result)) + { + return result; + } + else + { + result = object_proxy::getComplexProperty(name, result); + } // if we are proxying + } + + return result; + } + COMPILE::JS + override public function getProperty(name:String):* + { + // if we have a data proxy for this then + var result:*; + + if (notifiers[name.toString()]) + return notifiers[name]; + + result = _item[name]; + + if (result) + { + if (_proxyLevel == 0 || ObjectUtil.isSimple(result)) + { + return result; + } + else + { + result = object_proxy::getComplexProperty(name, result); + } // if we are proxying + } + + return result; + } + + /** + * Returns the value of the proxied object's method with the specified name. + * + * @param name The name of the method being invoked. + * + * @param rest An array specifying the arguments to the + * called method. + * + * @return The return value of the called method. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + override flash_proxy function callProperty(name:*, ... rest):* + { + return _item[name].apply(_item, rest) + } + + /** + * Deletes the specified property on the proxied object and + * sends notification of the delete to the handler. + * + * @param name Typically a string containing the name of the property, + * or possibly a QName where the property name is found by + * inspecting the <code>localName</code> property. + * + * @return A Boolean indicating if the property was deleted. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + override flash_proxy function deleteProperty(name:*):Boolean + { + var notifier:IPropertyChangeNotifier = IPropertyChangeNotifier(notifiers[name]); + if (notifier) + { + notifier.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, + propertyChangeHandler); + delete notifiers[name]; + } + + var oldVal:* = _item[name]; + var deleted:Boolean = delete _item[name]; + + if (dispatcher.hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE)) + { + var event:PropertyChangeEvent = new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE); + event.kind = PropertyChangeEventKind.DELETE; + event.property = name; + event.oldValue = oldVal; + event.source = this; + dispatcher.dispatchEvent(event); + } + + return deleted; + } + COMPILE::JS + override public function deleteProperty(name:String):Boolean + { + var notifier:IPropertyChangeNotifier = IPropertyChangeNotifier(notifiers[name]); + if (notifier) + { + notifier.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, + propertyChangeHandler); + delete notifiers[name]; + } + + var oldVal:* = _item[name]; + var deleted:Boolean = delete _item[name]; + + if (dispatcher.hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE)) + { + var event:PropertyChangeEvent = new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE); + event.kind = PropertyChangeEventKind.DELETE; + event.property = name; + event.oldValue = oldVal; + event.source = this; + dispatcher.dispatchEvent(event); + } + + return deleted; + } + + /** + * @private + */ - COMPILE::AS3 ++ COMPILE::SWF + override flash_proxy function hasProperty(name:*):Boolean + { + return(name in _item); + } + COMPILE::JS + override public function hasProperty(name:String):Boolean + { + return(name in _item); + } + + /** + * @private + */ - COMPILE::AS3 ++ COMPILE::SWF + override flash_proxy function nextName(index:int):String + { + return propertyList[index -1]; + } + + /** + * @private + */ - COMPILE::AS3 ++ COMPILE::SWF + override flash_proxy function nextNameIndex(index:int):int + { + if (index == 0) + { + setupPropertyList(); + } + + if (index < propertyList.length) + { + return index + 1; + } + else + { + return 0; + } + } + + /** + * @private + */ - COMPILE::AS3 ++ COMPILE::SWF + override flash_proxy function nextValue(index:int):* + { + return _item[propertyList[index -1]]; + } + + /** + * Updates the specified property on the proxied object + * and sends notification of the update to the handler. + * + * @param name Object containing the name of the property that + * should be updated on the proxied object. + * + * @param value Value that should be set on the proxied object. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + override flash_proxy function setProperty(name:*, value:*):void + { + var oldVal:* = _item[name]; + if (oldVal !== value) + { + // Update item. + _item[name] = value; + + // Stop listening for events on old item if we currently are. + var notifier:IPropertyChangeNotifier = + IPropertyChangeNotifier(notifiers[name]); + if (notifier) + { + notifier.removeEventListener( + PropertyChangeEvent.PROPERTY_CHANGE, + propertyChangeHandler); + delete notifiers[name]; + } + + // Notify anyone interested. + if (dispatcher.hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE)) + { + if (name is QName) + name = QName(name).localName; + var event:PropertyChangeEvent = + PropertyChangeEvent.createUpdateEvent( + this, name.toString(), oldVal, value); + dispatcher.dispatchEvent(event); + } + } + } + COMPILE::JS + override public function setProperty(name:String, value:*):void + { + var oldVal:* = _item[name]; + if (oldVal !== value) + { + // Update item. + _item[name] = value; + + // Stop listening for events on old item if we currently are. + var notifier:IPropertyChangeNotifier = + IPropertyChangeNotifier(notifiers[name]); + if (notifier) + { + notifier.removeEventListener( + PropertyChangeEvent.PROPERTY_CHANGE, + propertyChangeHandler); + delete notifiers[name]; + } + + // Notify anyone interested. + if (dispatcher.hasEventListener(PropertyChangeEvent.PROPERTY_CHANGE)) + { + COMPILE::LATER + { + if (name is QName) + name = QName(name).localName; + } + var event:PropertyChangeEvent = + PropertyChangeEvent.createUpdateEvent( + this, name.toString(), oldVal, value); + dispatcher.dispatchEvent(event); + } + } + } + + //-------------------------------------------------------------------------- + // + // object_proxy methods + // + //-------------------------------------------------------------------------- + + /** + * Provides a place for subclasses to override how a complex property that + * needs to be either proxied or daisy chained for event bubbling is managed. + * + * @param name Typically a string containing the name of the property, + * or possibly a QName where the property name is found by + * inspecting the <code>localName</code> property. + * + * @param value The property value. + * + * @return The property value or an instance of <code>ObjectProxy</code>. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + object_proxy function getComplexProperty(name:*, value:*):* + { + if (value is IPropertyChangeNotifier) + { + value.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, + propertyChangeHandler); + notifiers[name] = value; + return value; + } + + if (getQualifiedClassName(value) == "Object") + { + value = new proxyClass(_item[name], null, + _proxyLevel > 0 ? _proxyLevel - 1 : _proxyLevel); + value.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, + propertyChangeHandler); + notifiers[name] = value; + return value; + } + + return value; + } + + //-------------------------------------------------------------------------- + // + // IExternalizable Methods + // + //-------------------------------------------------------------------------- + + /** + * Since Flex only uses ObjectProxy to wrap anonymous objects, + * the server flex.messaging.io.ObjectProxy instance serializes itself + * as a Map that will be returned as a plain ActionScript object. + * You can then set the object_proxy object property to this value. + * + * @param input The source object from which the ObjectProxy is + * deserialized. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + public function readExternal(input:IDataInput):void + { + var value:Object = input.readObject(); + _item = value; + } + + /** + * Since Flex only serializes the inner ActionScript object that it wraps, + * the server flex.messaging.io.ObjectProxy populates itself + * with this anonymous object's contents and appears to the user + * as a Map. + * + * @param output The source object from which the ObjectProxy is + * deserialized. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + public function writeExternal(output:IDataOutput):void + { + output.writeObject(_item); + } + + //-------------------------------------------------------------------------- + // + // Methods + // + //-------------------------------------------------------------------------- + + /** + * Registers an event listener object + * so that the listener receives notification of an event. + * For more information, including descriptions of the parameters see + * <code>addEventListener()</code> in the + * flash.events.EventDispatcher class. + * + * @param type The type of event. + * + * @param listener The listener function that processes the event. This function must accept + * an Event object as its only parameter and must return nothing. + * + * @param useCapture Determines whether the listener works in the capture phase or the + * target and bubbling phases. If <code>useCapture</code> is set to <code>true</code>, + * the listener processes the event only during the capture phase and not in the + * target or bubbling phase. If <code>useCapture</code> is <code>false</code>, the + * listener processes the event only during the target or bubbling phase. To listen for + * the event in all three phases, call <code>addEventListener</code> twice, once with + * <code>useCapture</code> set to <code>true</code>, then again with + * <code>useCapture</code> set to <code>false</code>. + * + * @param priority The priority level of the event listener. + * + * @param useWeakReference Determines whether the reference to the listener is strong or + * weak. A strong reference (the default) prevents your listener from being garbage-collected. + * A weak reference does not. + * + * @see flash.events.EventDispatcher#addEventListener() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + public function addEventListener(type:String, listener:Function, + useCapture:Boolean = false, + priority:int = 0, + useWeakReference:Boolean = false):void + { + dispatcher.addEventListener(type, listener, useCapture, + priority, useWeakReference); + } + + /** + * Removes an event listener. + * If there is no matching listener registered with the EventDispatcher object, + * a call to this method has no effect. + * For more information, see + * the flash.events.EventDispatcher class. + * + * @param type The type of event. + * + * @param listener The listener object to remove. + * + * @param useCapture Specifies whether the listener was registered for the capture + * phase or the target and bubbling phases. If the listener was registered for both + * the capture phase and the target and bubbling phases, two calls to + * <code>removeEventListener()</code> are required to remove both, one call with + * <code>useCapture</code> + * set to <code>true</code>, and another call with <code>useCapture</code> + * set to <code>false</code>. + * + * @see flash.events.EventDispatcher#removeEventListener() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + public function removeEventListener(type:String, listener:Function, + useCapture:Boolean = false):void + { + dispatcher.removeEventListener(type, listener, useCapture); + } + + /** + * Dispatches an event into the event flow. + * For more information, see + * the flash.events.EventDispatcher class. + * + * @param event The Event object that is dispatched into the event flow. If the + * event is being redispatched, a clone of the event is created automatically. + * After an event is dispatched, its target property cannot be changed, so you + * must create a new copy of the event for redispatching to work. + * + * @return Returns <code>true</code> if the event was successfully dispatched. + * A value + * of <code>false</code> indicates failure or that <code>preventDefault()</code> + * was called on the event. + * + * @see flash.events.EventDispatcher#dispatchEvent() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + public function dispatchEvent(event:Event):Boolean + { + return dispatcher.dispatchEvent(event); + } + + /** + * Checks whether there are any event listeners registered + * for a specific type of event. + * This allows you to determine where an object has altered handling + * of an event type in the event flow hierarchy. + * For more information, see + * the flash.events.EventDispatcher class. + * + * @param type The type of event + * + * @return Returns <code>true</code> if a listener of the specified type is + * registered; <code>false</code> otherwise. + * + * @see flash.events.EventDispatcher#hasEventListener() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + public function hasEventListener(type:String):Boolean + { + return dispatcher.hasEventListener(type); + } + + /** + * Checks whether an event listener is registered with this object + * or any of its ancestors for the specified event type. + * This method returns <code>true</code> if an event listener is triggered + * during any phase of the event flow when an event of the specified + * type is dispatched to this object or any of its descendants. + * For more information, see the flash.events.EventDispatcher class. + * + * @param type The type of event. + * + * @return Returns <code>true</code> if a listener of the specified type will + * be triggered; <code>false</code> otherwise. + * + * @see flash.events.EventDispatcher#willTrigger() + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ - COMPILE::AS3 ++ COMPILE::SWF + public function willTrigger(type:String):Boolean + { + return dispatcher.willTrigger(type); + } + + /** + * Called when a complex property is updated. + * + * @param event An event object that has changed. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + public function propertyChangeHandler(event:PropertyChangeEvent):void + { + dispatcher.dispatchEvent(event); + } + + //-------------------------------------------------------------------------- + // + // Protected Methods + // + //-------------------------------------------------------------------------- + + /** + * This method creates an array of all of the property names for the + * proxied object. + * Descendants must override this method if they wish to add more + * properties to this list. + * Be sure to call <code>super.setupPropertyList</code> before making any + * changes to the <code>propertyList</code> property. + * + * @langversion 3.0 + * @playerversion Flash 9 + * @playerversion AIR 1.1 + * @productversion Flex 3 + */ + protected function setupPropertyList():void + { + if (getQualifiedClassName(_item) == "Object") + { + propertyList = []; + for (var prop:String in _item) + propertyList.push(prop); + } + else + { + propertyList = ObjectUtil.getClassInfo(_item, null, {includeReadOnly:true, uris:["*"]}).properties; + } + } +} + +}
