You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2016/06/16 22:59:42 UTC
[25/50] [abbrv] git commit: [flex-asjs] [refs/heads/spark] - Merge
branch 'develop' into spark
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/utils/ObjectUtil.as
----------------------------------------------------------------------
diff --cc frameworks/projects/MX/src/main/flex/mx/utils/ObjectUtil.as
index b38d635,0000000..4b65a97
mode 100644,000000..100644
--- a/frameworks/projects/MX/src/main/flex/mx/utils/ObjectUtil.as
+++ b/frameworks/projects/MX/src/main/flex/mx/utils/ObjectUtil.as
@@@ -1,1700 -1,0 +1,1700 @@@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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.utils.ByteArray;
+ import flash.utils.Dictionary;
+ import flash.xml.XMLNode;
+}
+import mx.collections.IList;
+
+import org.apache.flex.reflection.DefinitionWithMetaData;
+import org.apache.flex.reflection.MetaDataArgDefinition;
+import org.apache.flex.reflection.MetaDataDefinition;
+import org.apache.flex.reflection.MethodDefinition;
+import org.apache.flex.reflection.TypeDefinition;
+import org.apache.flex.reflection.getQualifiedClassName;
+
+/**
+ * The ObjectUtil class is an all-static class with methods for
+ * working with Objects within Flex.
+ * You do not create instances of ObjectUtil;
+ * instead you simply call static methods such as the
+ * <code>ObjectUtil.isSimple()</code> method.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public class ObjectUtil
+{
+ include "../core/Version.as";
+
+ /**
+ * Array of properties to exclude from debugging output.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ private static var defaultToStringExcludes:Array = ["password", "credentials"];
+
+ //--------------------------------------------------------------------------
+ //
+ // Class methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Compares the Objects and returns an integer value
+ * indicating if the first item is less than greater than or equal to
+ * the second item.
+ * This method will recursively compare properties on nested objects and
+ * will return as soon as a non-zero result is found.
+ * By default this method will recurse to the deepest level of any property.
+ * To change the depth for comparison specify a non-negative value for
+ * the <code>depth</code> parameter.
+ *
+ * @param a Object.
+ *
+ * @param b Object.
+ *
+ * @param depth Indicates how many levels should be
+ * recursed when performing the comparison.
+ * Set this value to 0 for a shallow comparison of only the primitive
+ * representation of each property.
+ * For example:<pre>
+ * var a:Object = {name:"Bob", info:[1,2,3]};
+ * var b:Object = {name:"Alice", info:[5,6,7]};
+ * var c:int = ObjectUtil.compare(a, b, 0);</pre>
+ *
+ * <p>In the above example the complex properties of <code>a</code> and
+ * <code>b</code> will be flattened by a call to <code>toString()</code>
+ * when doing the comparison.
+ * In this case the <code>info</code> property will be turned into a string
+ * when performing the comparison.</p>
+ *
+ * @return Return 0 if a and b are null, NaN, or equal.
+ * Return 1 if a is null or greater than b.
+ * Return -1 if b is null or greater than a.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function compare(a:Object, b:Object, depth:int = -1):int
+ {
+ return internalCompare(a, b, 0, depth, new CircularReferenceManager());
+ }
+
+ /**
+ * Copies the specified Object and returns a reference to the copy.
+ * The copy is made using a native serialization technique.
+ * This means that custom serialization will be respected during the copy.
+ *
+ * <p>This method is designed for copying data objects,
+ * such as elements of a collection. It is not intended for copying
+ * a UIComponent object, such as a TextInput control. If you want to create copies
+ * of specific UIComponent objects, you can create a subclass of the component and implement
+ * a <code>clone()</code> method, or other method to perform the copy.</p>
+ *
+ * @param value Object that should be copied.
+ *
+ * @return Copy of the specified Object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function copy(value:Object):Object
+ {
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ var buffer:ByteArray = new ByteArray();
+ buffer.writeObject(value);
+ buffer.position = 0;
+ var result:Object = buffer.readObject();
+ return result;
+ }
+ COMPILE::JS
+ {
+ return copyObject(value);
+ }
+ }
+
+ COMPILE::JS
+ private static function copyObject(value:*):*
+ {
+ var t:String = typeof(value);
+ if (t === "undefined")
+ return undefined;
+ else if (t === "boolean")
+ return value;
+ else if (t === "string")
+ return value;
+ else if (t === "function")
+ return value; // need to copy?
+ else if (t === null)
+ return null;
+
+ var newObj:Object;
+ if (value.constructor)
+ newObj = new value.constructor(); // what about required constuctor args?
+ else
+ newObj = {};
+ for (var p:String in value)
+ {
+ newObj[p] = copyObject(value[p]);
+ }
+ return newObj;
+ }
+
+ /**
+ * Clones the specified Object and returns a reference to the clone.
+ * The clone is made using a native serialization technique.
+ * This means that custom serialization will be respected during the
+ * cloning. clone() differs from copy() in that the uid property of
+ * each object instance is retained.
+ *
+ * <p>This method is designed for cloning data objects,
+ * such as elements of a collection. It is not intended for cloning
+ * a UIComponent object, such as a TextInput control. If you want to clone
+ * specific UIComponent objects, you can create a subclass of the component
+ * and implement a <code>clone()</code> method.</p>
+ *
+ * @param value Object that should be cloned.
+ *
+ * @return Clone of the specified Object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 4
+ */
+ public static function clone(value:Object):Object
+ {
+ var result:Object = copy(value);
+ cloneInternal(result, value);
+ return result;
+ }
+
+ /**
+ * Recursive helper used by the public clone method.
+ * @private
+ */
+ private static function cloneInternal(result:Object, value:Object):void
+ {
+ if (value && value.hasOwnProperty("uid"))
+ result.uid = value.uid;
+
+ var classInfo:Object = getClassInfo(value);
+ var v:Object;
+ for each (var p:* in classInfo.properties)
+ {
+ v = value[p];
+ if (v && v.hasOwnProperty("uid"))
+ cloneInternal(result[p], v);
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if the object reference specified
+ * is a simple data type. The simple data types include the following:
+ * <ul>
+ * <li><code>String</code></li>
+ * <li><code>Number</code></li>
+ * <li><code>uint</code></li>
+ * <li><code>int</code></li>
+ * <li><code>Boolean</code></li>
+ * <li><code>Date</code></li>
+ * <li><code>Array</code></li>
+ * </ul>
+ *
+ * @param value Object inspected.
+ *
+ * @return <code>true</code> if the object specified
+ * is one of the types above; <code>false</code> otherwise.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isSimple(value:Object):Boolean
+ {
+ var objectType:String = typeof(value);
+ switch (objectType)
+ {
+ case "number":
+ case "string":
+ case "boolean":
+ {
+ return true;
+ }
+
+ case "object":
+ {
+ return (value is Date) || (value is Array);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Compares two numeric values.
+ *
+ * @param a First number.
+ *
+ * @param b Second number.
+ *
+ * @return 0 is both numbers are NaN.
+ * 1 if only <code>a</code> is a NaN.
+ * -1 if only <code>b</code> is a NaN.
+ * -1 if <code>a</code> is less than <code>b</code>.
+ * 1 if <code>a</code> is greater than <code>b</code>.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function numericCompare(a:Number, b:Number):int
+ {
+ if (isNaN(a) && isNaN(b))
+ return 0;
+
+ if (isNaN(a))
+ return 1;
+
+ if (isNaN(b))
+ return -1;
+
+ if (a < b)
+ return -1;
+
+ if (a > b)
+ return 1;
+
+ return 0;
+ }
+
+ /**
+ * Compares two String values.
+ *
+ * @param a First String value.
+ *
+ * @param b Second String value.
+ *
+ * @param caseInsensitive Specifies to perform a case insensitive compare,
+ * <code>true</code>, or not, <code>false</code>.
+ *
+ * @return 0 is both Strings are null.
+ * 1 if only <code>a</code> is null.
+ * -1 if only <code>b</code> is null.
+ * -1 if <code>a</code> precedes <code>b</code>.
+ * 1 if <code>b</code> precedes <code>a</code>.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function stringCompare(a:String, b:String,
+ caseInsensitive:Boolean = false):int
+ {
+ if (a == null && b == null)
+ return 0;
+
+ if (a == null)
+ return 1;
+
+ if (b == null)
+ return -1;
+
+ // Convert to lowercase if we are case insensitive.
+ if (caseInsensitive)
+ {
+ a = a.toLocaleLowerCase();
+ b = b.toLocaleLowerCase();
+ }
+
+ var result:int = a.localeCompare(b);
+
+ if (result < -1)
+ result = -1;
+ else if (result > 1)
+ result = 1;
+
+ return result;
+ }
+
+ /**
+ * Compares the two Date objects and returns an integer value
+ * indicating if the first Date object is before, equal to,
+ * or after the second item.
+ *
+ * @param a Date object.
+ *
+ * @param b Date object.
+ *
+ * @return 0 if <code>a</code> and <code>b</code> are equal
+ * (or both are <code>null</code>);
+ * -1 if <code>a</code> is before <code>b</code>
+ * (or <code>b</code> is <code>null</code>);
+ * 1 if <code>a</code> is after <code>b</code>
+ * (or <code>a</code> is <code>null</code>);
+ * 0 is both dates getTime's are NaN;
+ * 1 if only <code>a</code> getTime is a NaN;
+ * -1 if only <code>b</code> getTime is a NaN.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function dateCompare(a:Date, b:Date):int
+ {
+ if (a == null && b == null)
+ return 0;
+
+ if (a == null)
+ return 1;
+
+ if (b == null)
+ return -1;
+
+ var na:Number = a.getTime();
+ var nb:Number = b.getTime();
+
+ if (na < nb)
+ return -1;
+
+ if (na > nb)
+ return 1;
+
+ if (isNaN(na) && isNaN(nb))
+ return 0;
+
+ if (isNaN(na))
+ return 1;
+
+ if (isNaN(nb))
+ return -1;
+
+ return 0;
+ }
+
+ /**
+ * Pretty-prints the specified Object into a String.
+ * All properties will be in alpha ordering.
+ * Each object will be assigned an id during printing;
+ * this value will be displayed next to the object type token
+ * preceded by a '#', for example:
+ *
+ * <pre>
+ * (mx.messaging.messages::AsyncMessage)#2.</pre>
+ *
+ * <p>This id is used to indicate when a circular reference occurs.
+ * Properties of an object that are of the <code>Class</code> type will
+ * appear only as the assigned type.
+ * For example a custom definition like the following:</p>
+ *
+ * <pre>
+ * public class MyCustomClass {
+ * public var clazz:Class;
+ * }</pre>
+ *
+ * <p>With the <code>clazz</code> property assigned to <code>Date</code>
+ * will display as shown below:</p>
+ *
+ * <pre>
+ * (somepackage::MyCustomClass)#0
+ * clazz = (Date)</pre>
+ *
+ * @param value Object to be pretty printed.
+ *
+ * @param namespaceURIs Array of namespace URIs for properties
+ * that should be included in the output.
+ * By default only properties in the public namespace will be included in
+ * the output.
+ * To get all properties regardless of namespace pass an array with a
+ * single element of "*".
+ *
+ * @param exclude Array of the property names that should be
+ * excluded from the output.
+ * Use this to remove data from the formatted string.
+ *
+ * @return String containing the formatted version
+ * of the specified object.
+ *
+ * @example
+ * <pre>
+ * // example 1
+ * var obj:AsyncMessage = new AsyncMessage();
+ * obj.body = [];
+ * obj.body.push(new AsyncMessage());
+ * obj.headers["1"] = { name: "myName", num: 15.3};
+ * obj.headers["2"] = { name: "myName", num: 15.3};
+ * obj.headers["10"] = { name: "myName", num: 15.3};
+ * obj.headers["11"] = { name: "myName", num: 15.3};
+ * trace(ObjectUtil.toString(obj));
+ *
+ * // will output to flashlog.txt
+ * (mx.messaging.messages::AsyncMessage)#0
+ * body = (Array)#1
+ * [0] (mx.messaging.messages::AsyncMessage)#2
+ * body = (Object)#3
+ * clientId = (Null)
+ * correlationId = ""
+ * destination = ""
+ * headers = (Object)#4
+ * messageId = "378CE96A-68DB-BC1B-BCF7FFFFFFFFB525"
+ * sequenceId = (Null)
+ * sequencePosition = 0
+ * sequenceSize = 0
+ * timeToLive = 0
+ * timestamp = 0
+ * clientId = (Null)
+ * correlationId = ""
+ * destination = ""
+ * headers = (Object)#5
+ * 1 = (Object)#6
+ * name = "myName"
+ * num = 15.3
+ * 10 = (Object)#7
+ * name = "myName"
+ * num = 15.3
+ * 11 = (Object)#8
+ * name = "myName"
+ * num = 15.3
+ * 2 = (Object)#9
+ * name = "myName"
+ * num = 15.3
+ * messageId = "1D3E6E96-AC2D-BD11-6A39FFFFFFFF517E"
+ * sequenceId = (Null)
+ * sequencePosition = 0
+ * sequenceSize = 0
+ * timeToLive = 0
+ * timestamp = 0
+ *
+ * // example 2 with circular references
+ * obj = {};
+ * obj.prop1 = new Date();
+ * obj.prop2 = [];
+ * obj.prop2.push(15.2);
+ * obj.prop2.push("testing");
+ * obj.prop2.push(true);
+ * obj.prop3 = {};
+ * obj.prop3.circular = obj;
+ * obj.prop3.deeper = new ErrorMessage();
+ * obj.prop3.deeper.rootCause = obj.prop3.deeper;
+ * obj.prop3.deeper2 = {};
+ * obj.prop3.deeper2.deeperStill = {};
+ * obj.prop3.deeper2.deeperStill.yetDeeper = obj;
+ * trace(ObjectUtil.toString(obj));
+ *
+ * // will output to flashlog.txt
+ * (Object)#0
+ * prop1 = Tue Apr 26 13:59:17 GMT-0700 2005
+ * prop2 = (Array)#1
+ * [0] 15.2
+ * [1] "testing"
+ * [2] true
+ * prop3 = (Object)#2
+ * circular = (Object)#0
+ * deeper = (mx.messaging.messages::ErrorMessage)#3
+ * body = (Object)#4
+ * clientId = (Null)
+ * code = (Null)
+ * correlationId = ""
+ * destination = ""
+ * details = (Null)
+ * headers = (Object)#5
+ * level = (Null)
+ * message = (Null)
+ * messageId = "14039376-2BBA-0D0E-22A3FFFFFFFF140A"
+ * rootCause = (mx.messaging.messages::ErrorMessage)#3
+ * sequenceId = (Null)
+ * sequencePosition = 0
+ * sequenceSize = 0
+ * timeToLive = 0
+ * timestamp = 0
+ * deeper2 = (Object)#6
+ * deeperStill = (Object)#7
+ * yetDeeper = (Object)#0
+ *
+ * // example 3 with Dictionary
+ * var point:Point = new Point(100, 100);
+ * var point2:Point = new Point(100, 100);
+ * var obj:Dictionary = new Dictionary();
+ * obj[point] = "point";
+ * obj[point2] = "point2";
+ * obj["1"] = { name: "one", num: 1};
+ * obj["two"] = { name: "2", num: 2};
+ * obj[3] = 3;
+ * trace(ObjectUtil.toString(obj));
+ *
+ * // will output to flashlog.txt
+ * (flash.utils::Dictionary)#0
+ * {(flash.geom::Point)#1
+ * length = 141.4213562373095
+ * x = 100
+ * y = 100} = "point2"
+ * {(flash.geom::Point)#2
+ * length = 141.4213562373095
+ * x = 100
+ * y = 100} = "point"
+ * {1} = (Object)#3
+ * name = "one"
+ * num = 1
+ * {3} = 3
+ * {"two"} = (Object)#4
+ * name = "2"
+ * num = 2
+ *
+ * </pre>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function toString(value:Object,
+ namespaceURIs:Array = null,
+ exclude:Array = null):String
+ {
+ if (exclude == null)
+ {
+ exclude = defaultToStringExcludes;
+ }
+
+ refCount = 0;
+ return internalToString(value, 0, null, namespaceURIs, exclude);
+ }
+
+ /**
+ * This method cleans up all of the additional parameters that show up in AsDoc
+ * code hinting tools that developers shouldn't ever see.
+ * @private
+ */
+ private static function internalToString(value:Object,
+ indent:int = 0,
+ refs:CircularReferenceManager = null,
+ namespaceURIs:Array = null,
+ exclude:Array = null):String
+ {
+ var str:String;
+ var objectType:String = value == null ? "null" : typeof(value);
+ switch (objectType)
+ {
+ case "boolean":
+ case "number":
+ {
+ return value.toString();
+ }
+
+ case "string":
+ {
+ return "\"" + value.toString() + "\"";
+ }
+
+ case "object":
+ {
+ if (value is Date)
+ {
+ return value.toString();
+ }
+ else if (isXMLNode(value))
+ {
+ return value.toString();
+ }
+ else if (value is Class)
+ {
+ return "(" + getQualifiedClassName(value) + ")";
+ }
+ else
+ {
+ var classInfo:Object = getClassInfo(value, exclude,
+ { includeReadOnly: true, uris: namespaceURIs });
+
+ var properties:Array = classInfo.properties;
+
+ str = "(" + classInfo.name + ")";
+
+ // refs help us avoid circular reference infinite recursion.
+ // Each time an object is encoumtered it is pushed onto the
+ // refs stack so that we can determine if we have visited
+ // this object already.
+ if (refs == null)
+ refs = new CircularReferenceManager();
+
+ // Check to be sure we haven't processed this object before
+ // Dictionary has some bugs, so we want to work around them as best we can
+ try
+ {
+ var id:Object = refs[value];
+ if (id != null)
+ {
+ str += "#" + int(id);
+ return str;
+ }
+ }
+ catch (e:Error)
+ {
+ //Since we can't test for infinite loop, we simply return toString.
+ return String(value);
+ }
+
+ if (value != null)
+ {
+ str += "#" + refCount.toString();
+ refs[value] = refCount;
+ refCount++;
+ }
+
+ var isArray:Boolean = value is Array;
+ var isDict:Boolean;
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ isDict = value is Dictionary;
+ }
+ var prop:*;
+ indent += 2;
+
+ // Print all of the variable values.
+ for (var j:int = 0; j < properties.length; j++)
+ {
+ str = newline(str, indent);
+ prop = properties[j];
+
+ if (isArray)
+ str += "[";
+ else if (isDict)
+ str += "{";
+
+
+ if (isDict)
+ {
+ // in dictionaries, recurse on the key, because it can be a complex object
+ str += internalToString(prop, indent, refs,
+ namespaceURIs, exclude);
+ }
+ else
+ {
+ str += prop.toString();
+ }
+
+ if (isArray)
+ str += "] ";
+ else if (isDict)
+ str += "} = ";
+ else
+ str += " = ";
+
+ try
+ {
+ // print the value
+ str += internalToString(value[prop], indent, refs,
+ namespaceURIs, exclude);
+ }
+ catch(e:Error)
+ {
+ // value[prop] can cause an RTE
+ // for certain properties of certain objects.
+ // For example, accessing the properties
+ // actionScriptVersion
+ // childAllowsParent
+ // frameRate
+ // height
+ // loader
+ // parentAllowsChild
+ // sameDomain
+ // swfVersion
+ // width
+ // of a Stage's loaderInfo causes
+ // Error #2099: The loading object is not
+ // sufficiently loaded to provide this information
+ // In this case, we simply output ? for the value.
+ str += "?";
+ }
+ }
+ indent -= 2;
+ return str;
+ }
+ break;
+ }
+
+ case "xml":
+ {
+ return value.toXMLString();
+ }
+
+ default:
+ {
+ return "(" + objectType + ")";
+ }
+ }
+
+ return "(unknown)";
+ }
+
+ /**
+ * @private
+ * This method will append a newline and the specified number of spaces
+ * to the given string.
+ */
+ private static function newline(str:String, n:int = 0):String
+ {
+ var result:String = str;
+ result += "\n";
+
+ for (var i:int = 0; i < n; i++)
+ {
+ result += " ";
+ }
+ return result;
+ }
+
+ private static function internalCompare(a:Object, b:Object,
+ currentDepth:int, desiredDepth:int,
+ refs:CircularReferenceManager):int
+ {
+ if (a == null && b == null)
+ return 0;
+
+ if (a == null)
+ return 1;
+
+ if (b == null)
+ return -1;
+
+ COMPILE::LATER
+ {
+ if (a is ObjectProxy)
+ a = ObjectProxy(a).object_proxy::object;
+
+ if (b is ObjectProxy)
+ b = ObjectProxy(b).object_proxy::object;
+ }
+
+ var typeOfA:String = typeof(a);
+ var typeOfB:String = typeof(b);
+
+ var result:int = 0;
+
+ if (typeOfA == typeOfB)
+ {
+ switch(typeOfA)
+ {
+ case "boolean":
+ {
+ result = numericCompare(Number(a), Number(b));
+ break;
+ }
+
+ case "number":
+ {
+ result = numericCompare(a as Number, b as Number);
+ break;
+ }
+
+ case "string":
+ {
+ result = stringCompare(a as String, b as String);
+ break;
+ }
+
+ case "object":
+ {
+ var newDepth:int = desiredDepth > 0 ? desiredDepth -1 : desiredDepth;
+
+ // refs help us avoid circular reference infinite recursion.
+ var aRef:Object = getRef(a,refs);
+ var bRef:Object = getRef(b,refs);
+
+ if (aRef == bRef)
+ return 0;
+ // the cool thing about our dictionary is that if
+ // we've seen objects and determined that they are unequal, then
+ // we would've already exited out of this compare() call. So the
+ // only info in the dictionary are sets of equal items
+
+ // let's first define them as equal
+ // this stops an "infinite loop" problem where A.i = B and B.i = A
+ // if we later find that an object (one of the subobjects) is in fact unequal,
+ // then we will return false and quit out of everything. These refs are thrown away
+ // so it doesn't matter if it's correct.
+ refs[bRef] = aRef;
+
+ if (desiredDepth != -1 && (currentDepth > desiredDepth))
+ {
+ // once we try to go beyond the desired depth we should
+ // toString() our way out
+ result = stringCompare(a.toString(), b.toString());
+ }
+ else if ((a is Array) && (b is Array))
+ {
+ result = arrayCompare(a as Array, b as Array, currentDepth, desiredDepth, refs);
+ }
+ else if ((a is Date) && (b is Date))
+ {
+ result = dateCompare(a as Date, b as Date);
+ }
+ else if ((a is IList) && (b is IList))
+ {
+ result = listCompare(a as IList, b as IList, currentDepth, desiredDepth, refs);
+ }
+ else if (areBothByteArrays(a, b))
+ {
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ result = byteArrayCompare(a as ByteArray, b as ByteArray);
+ }
+ }
+ else if (getQualifiedClassName(a) == getQualifiedClassName(b))
+ {
+ var aProps:Array = getClassInfo(a).properties;
+ var bProps:Array;
+
+ // if the objects are dynamic they could have different
+ // # of properties and should be treated on that basis first
+ var isObjectDynamic:Boolean = isDynamicObject(a);
+
+ // if it's dynamic, check to see that they have all the same properties
+ if (isObjectDynamic)
+ {
+ bProps = getClassInfo(b).properties;
+ result = arrayCompare(aProps, bProps, currentDepth, newDepth, refs);
+ if (result != 0)
+ return result;
+ }
+
+ // now that we know we have the same properties, let's compare the values
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ var propName:QName;
+ }
+ COMPILE::JS
+ {
+ var propName:String;
+ }
+ var aProp:Object;
+ var bProp:Object;
+ for (var i:int = 0; i < aProps.length; i++)
+ {
+ propName = aProps[i];
+ aProp = a[propName];
+ bProp = b[propName];
+ result = internalCompare(aProp, bProp, currentDepth+1, newDepth, refs);
+ if (result != 0)
+ {
+ return result;
+ }
+ }
+ }
+ else
+ {
+ // We must be unequal, so return 1
+ return 1;
+ }
+ break;
+ }
+ }
+ }
+ else // be consistent with the order we return here
+ {
+ return stringCompare(typeOfA, typeOfB);
+ }
+
+ return result;
+ }
+
+ private static function isXMLNode(value:Object):Boolean
+ {
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ return (value is XMLNode);
+ }
+ COMPILE::JS
+ {
+ return false;
+ }
+ }
+
+ private static function areBothByteArrays(a:Object, b:Object):Boolean
+ {
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ return (a is ByteArray) && (b is ByteArray)
+ }
+ COMPILE::JS
+ {
+ return false;
+ }
+ }
+ /**
+ * Returns information about the class, and properties of the class, for
+ * the specified Object.
+ *
+ * @param obj The Object to inspect.
+ *
+ * @param excludes Array of Strings specifying the property names that should be
+ * excluded from the returned result. For example, you could specify
+ * <code>["currentTarget", "target"]</code> for an Event object since these properties
+ * can cause the returned result to become large.
+ *
+ * @param options An Object containing one or more properties
+ * that control the information returned by this method.
+ * The properties include the following:
+ *
+ * <ul>
+ * <li><code>includeReadOnly</code>: If <code>false</code>,
+ * exclude Object properties that are read-only.
+ * The default value is <code>true</code>.</li>
+ * <li><code>includeTransient</code>: If <code>false</code>,
+ * exclude Object properties and variables that have <code>[Transient]</code> metadata.
+ * The default value is <code>true</code>.</li>
+ * <li><code>uris</code>: Array of Strings of all namespaces that should be included in the output.
+ * It does allow for a wildcard of "~~".
+ * By default, it is null, meaning no namespaces should be included.
+ * For example, you could specify <code>["mx_internal", "mx_object"]</code>
+ * or <code>["~~"]</code>.</li>
+ * </ul>
+ *
+ * @return An Object containing the following properties:
+ * <ul>
+ * <li><code>name</code>: String containing the name of the class.</li>
+ * <li><code>properties</code>: Sorted list of the property names of the specified object,
+ * or references to the original key if the specified object is a Dictionary. The individual
+ * array elements are QName instances, which contain both the local name of the property as well as the URI.</li>
+ * </ul>
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function getClassInfo(obj:Object,
+ excludes:Array = null,
+ options:Object = null):Object
+ {
+ var n:int;
+ var i:int;
+
+ COMPILE::LATER
+ {
+ if (obj is ObjectProxy)
+ obj = ObjectProxy(obj).object_proxy::object;
+ }
+
+ if (options == null)
+ options = { includeReadOnly: true, uris: null, includeTransient: true };
+
+ var result:Object;
+ var propertyNames:Array = [];
+ var cacheKey:String;
+
+ var className:String;
+ var classAlias:String;
+ COMPILE::LATER
+ {
+ var properties:XMLList;
+ var prop:XML;
+ }
+ var propertyList:Array;
+ var isDynamic:Boolean = false;
+ var metadataInfo:Object;
+
+ if (typeof(obj) == "xml")
+ {
+ COMPILE::LATER
+ {
+ className = "XML";
+ properties = obj.text();
+ if (properties.length())
+ propertyNames.push("*");
+ properties = obj.attributes();
+ }
+ }
+ else
+ {
+ var classInfo:TypeDefinition = DescribeTypeCache.describeType(obj).typeDescription;
+ className = classInfo.name;
+ COMPILE::LATER
+ {
+ classAlias = classInfo.@alias.toString();
+ }
+ isDynamic = classInfo.dynamic;
+
+ propertyList.concat(classInfo.accessors);
+ propertyList.concat(classInfo.variables);
+
+ COMPILE::LATER
+ {
+ if (options.includeReadOnly)
+ properties = classInfo..accessor.(@access != "writeonly") + classInfo..variable;
+ else
+ properties = classInfo..accessor.(@access == "readwrite") + classInfo..variable;
+ }
+
+ var numericIndex:Boolean = false;
+ }
+
+ // If type is not dynamic, check our cache for class info...
+ if (!isDynamic)
+ {
+ cacheKey = getCacheKey(obj, excludes, options);
+ result = CLASS_INFO_CACHE[cacheKey];
+ if (result != null)
+ return result;
+ }
+
+ result = {};
+ result["name"] = className;
+ result["alias"] = classAlias;
+ result["properties"] = propertyNames;
+ result["dynamic"] = isDynamic;
+ result["metadata"] = metadataInfo = recordMetadata(propertyList);
+
+ var excludeObject:Object = {};
+ if (excludes)
+ {
+ n = excludes.length;
+ for (i = 0; i < n; i++)
+ {
+ excludeObject[excludes[i]] = 1;
+ }
+ }
+
+ var isArray:Boolean = (obj is Array);
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ var isDict:Boolean = (obj is Dictionary);
+ }
+ COMPILE::JS
+ {
+ var isDict:Boolean = false;
+ }
+
+ if (isDict)
+ {
+ // dictionaries can have multiple keys of the same type,
+ // (they can index by reference rather than QName, String, or number),
+ // which cannot be looked up by QName, so use references to the actual key
+ for (var key:* in obj)
+ {
+ propertyNames.push(key);
+ }
+ }
+ else if (isDynamic)
+ {
+ for (var p:String in obj)
+ {
+ if (excludeObject[p] != 1)
+ {
+ if (isArray)
+ {
+ var pi:Number = parseInt(p);
+ if (isNaN(pi))
+ propertyNames.push(new QName("", p));
+ else
+ propertyNames.push(pi);
+ }
+ else
+ {
+ propertyNames.push(new QName("", p));
+ }
+ }
+ }
+ numericIndex = isArray && !isNaN(Number(p));
+ }
+
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ var allDone:Boolean = isArray || isDict || className == "Object";
+ }
+ COMPILE::JS
+ {
+ var allDone:Boolean = isArray || className == "Object";
+ }
+
+ if (allDone)
+ {
+ // Do nothing since we've already got the dynamic members
+ }
+ else if (className == "XML")
+ {
+ COMPILE::LATER
+ {
+ n = properties.length();
+ for (i = 0; i < n; i++)
+ {
+ p = properties[i].name();
+ if (excludeObject[p] != 1)
+ propertyNames.push(new QName("", "@" + p));
+ }
+ }
+ }
+ else
+ {
+ n = propertyList.length;
+ var uris:Array = options.uris;
+ var uri:String;
+ var qName:QName;
+ for (i = 0; i < n; i++)
+ {
+ var member:DefinitionWithMetaData = propertyList[i] as DefinitionWithMetaData;
+ p = member.name;
+ COMPILE::LATER
+ {
+ uri = prop.@uri.toString();
+ }
+ uri = "";
+
+ if (excludeObject[p] == 1)
+ continue;
+
+ if (!options.includeTransient && internalHasMetadata(metadataInfo, p, "Transient"))
+ continue;
+
+ if (uris != null)
+ {
+ COMPILE::LATER
+ {
+ if (uris.length == 1 && uris[0] == "*")
+ {
+ qName = new QName(uri, p);
+ try
+ {
+ obj[qName]; // access the property to ensure it is supported
+ propertyNames.push();
+ }
+ catch(e:Error)
+ {
+ // don't keep property name
+ }
+ }
+ else
+ {
+ for (var j:int = 0; j < uris.length; j++)
+ {
+ uri = uris[j];
+ if (prop.@uri.toString() == uri)
+ {
+ qName = new QName(uri, p);
+ try
+ {
+ obj[qName];
+ propertyNames.push(qName);
+ }
+ catch(e:Error)
+ {
+ // don't keep property name
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (uri.length == 0)
+ {
+ qName = new QName(uri, p);
+ try
+ {
+ obj[qName];
+ propertyNames.push(qName);
+ }
+ catch(e:Error)
+ {
+ // don't keep property name
+ }
+ }
+ }
+ }
+
+ propertyNames.sort(Array.CASEINSENSITIVE |
+ (numericIndex ? Array.NUMERIC : 0));
+
+ // dictionary keys can be indexed by an object reference
+ // there's a possibility that two keys will have the same toString()
+ // so we don't want to remove dupes
+ if (!isDict)
+ {
+ // for Arrays, etc., on the other hand...
+ // remove any duplicates, i.e. any items that can't be distingushed by toString()
+ for (i = 0; i < propertyNames.length - 1; i++)
+ {
+ // the list is sorted so any duplicates should be adjacent
+ // two properties are only equal if both the uri and local name are identical
+ if (propertyNames[i].toString() == propertyNames[i + 1].toString())
+ {
+ propertyNames.splice(i, 1);
+ i--; // back up
+ }
+ }
+ }
+
+ // For normal, non-dynamic classes we cache the class info
+ // Don't cache XML as it can be dynamic
+ if (!isDynamic && className != "XML")
+ {
+ cacheKey = getCacheKey(obj, excludes, options);
+ CLASS_INFO_CACHE[cacheKey] = result;
+ }
+
+ return result;
+ }
+
+ /**
+ * Uses <code>getClassInfo</code> and examines the metadata information to
+ * determine whether a property on a given object has the specified
+ * metadata.
+ *
+ * @param obj The object holding the property.
+ * @param propName The property to check for metadata.
+ * @param metadataName The name of the metadata to check on the property.
+ * @param excludes If any properties need to be excluded when generating class info. (Optional)
+ * @param options If any options flags need to changed when generating class info. (Optional)
+ * @return true if the property has the specified metadata.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function hasMetadata(obj:Object,
+ propName:String,
+ metadataName:String,
+ excludes:Array = null,
+ options:Object = null):Boolean
+ {
+ var classInfo:Object = getClassInfo(obj, excludes, options);
+ var metadataInfo:Object = classInfo["metadata"];
+ return internalHasMetadata(metadataInfo, propName, metadataName);
+ }
+
+ /**
+ * Returns <code>true</code> if the object is an instance of a dynamic class.
+ *
+ * @param obj The object.
+ *
+ * @return <code>true</code> if the object is an instance of a dynamic class.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function isDynamicObject(obj:Object):Boolean
+ {
+ try
+ {
+ // this test for checking whether an object is dynamic or not is
+ // pretty hacky, but it assumes that no-one actually has a
+ // property defined called "wootHackwoot"
+ obj["wootHackwoot"];
+ }
+ catch (e:Error)
+ {
+ // our object isn't from a dynamic class
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns the value at the end of the property chain <code>path</code>.
+ * If the value cannot be reached due to null links on the chain,
+ * <code>undefined</code> is returned.
+ *
+ * @param obj The object at the beginning of the property chain
+ * @param path The path to inspect (e.g. "address.street")
+ *
+ * @return the value at the end of the property chain, <code>undefined</code>
+ * if it cannot be reached, or the object itself when <code>path</code> is empty.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function getValue(obj:Object, path:Array):*
+ {
+ if(!obj)
+ return undefined;
+
+ if(!path || !path.length)
+ return obj;
+
+ var result:* = obj;
+ var i:int = -1;
+ while(++i < path.length && result)
+ result = result.hasOwnProperty(path[i]) ? result[path[i]] : undefined;
+
+ return result;
+ }
+
+
+ /**
+ * Sets a new value at the end of the property chain <code>path</code>.
+ * If the value cannot be reached due to null links on the chain,
+ * <code>false</code> is returned.
+ *
+ * @param obj The object at the beginning of the property chain
+ * @param path The path to traverse (e.g. "address.street")
+ * @param newValue The value to set (e.g. "Fleet Street")
+ *
+ * @return <code>true</code> if the value is successfully set,
+ * <code>false</code> otherwise. Note that the function does not
+ * use a try/catch block. You can implement one in the calling
+ * function if there's a risk of type mismatch or other errors during
+ * the assignment.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public static function setValue(obj:Object, path:Array, newValue:*):Boolean
+ {
+ if(!obj || !path || !path.length)
+ return false;
+
+ var secondToLastLink:* = getValue(obj, path.slice(0, -1));
+ if(secondToLastLink && secondToLastLink.hasOwnProperty(path[path.length - 1]))
+ {
+ secondToLastLink[path[path.length - 1]] = newValue;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @private
+ */
+ private static function internalHasMetadata(metadataInfo:Object, propName:String, metadataName:String):Boolean
+ {
+ if (metadataInfo != null)
+ {
+ var metadata:Object = metadataInfo[propName];
+ if (metadata != null)
+ {
+ if (metadata[metadataName] != null)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @private
+ */
+ private static function recordMetadata(properties:Array):Object
+ {
+ var result:Object = null;
+
+ try
+ {
+ for each (var prop:DefinitionWithMetaData in properties)
+ {
+ var propName:String = prop.name;
+ var metadataList:Array = prop.metadata;
+
+ if (metadataList.length > 0)
+ {
+ if (result == null)
+ result = {};
+
+ var metadata:Object = {};
+ result[propName] = metadata;
+
+ for each (var md:MetaDataDefinition in metadataList)
+ {
+ var mdName:String = md.name;
+
+ var argsList:Array = md.args;
+ var value:Object = {};
+
+ for each (var arg:MetaDataArgDefinition in argsList)
+ {
+ var argKey:String = arg.name;
+ if (argKey != null)
+ {
+ var argValue:String = arg.value;
+ value[argKey] = argValue;
+ }
+ }
+
+ var existing:Object = metadata[mdName];
+ if (existing != null)
+ {
+ var existingArray:Array;
+ if (existing is Array)
+ existingArray = existing as Array;
+ else
+ {
+ existingArray = [existing];
+ delete metadata[mdName];
+ }
+ existingArray.push(value);
+ existing = existingArray;
+ }
+ else
+ {
+ existing = value;
+ }
+ metadata[mdName] = existing;
+ }
+ }
+ }
+ }
+ catch(e:Error)
+ {
+ }
+
+ return result;
+ }
+
+
+ /**
+ * @private
+ */
+ private static function getCacheKey(o:Object, excludes:Array = null, options:Object = null):String
+ {
+ var key:String = getQualifiedClassName(o);
+
+ if (excludes != null)
+ {
+ var length:int = excludes.length;
+ for (var i:uint = 0; i < length; i++)
+ {
+ var excl:String = excludes[i] as String;
+ if (excl != null)
+ key += excl;
+ }
+ }
+
+ if (options != null)
+ {
+ for (var flag:String in options)
+ {
+ key += flag;
+ var value:String = options[flag];
+ if (value != null)
+ key += value.toString();
+ }
+ }
+ return key;
+ }
+
+ /**
+ * @private
+ */
+ private static function arrayCompare(a:Array, b:Array,
+ currentDepth:int, desiredDepth:int,
+ refs:CircularReferenceManager):int
+ {
+ var result:int = 0;
+
+ if (a.length != b.length)
+ {
+ if (a.length < b.length)
+ result = -1;
+ else
+ result = 1;
+ }
+ else
+ {
+ var key:Object;
+ for (key in a)
+ {
+ if (b.hasOwnProperty(key))
+ {
+ result = internalCompare(a[key], b[key], currentDepth,
+ desiredDepth, refs);
+
+ if (result != 0)
+ return result;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+
+ for (key in b)
+ {
+ if (!a.hasOwnProperty(key))
+ {
+ return 1;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @private
+ */
- COMPILE::AS3
++ COMPILE::SWF
+ private static function byteArrayCompare(a:ByteArray, b:ByteArray):int
+ {
+ var result:int = 0;
+
+ if (a == b)
+ return result;
+
+ if (a.length != b.length)
+ {
+ if (a.length < b.length)
+ result = -1;
+ else
+ result = 1;
+ }
+ else
+ {
+ for (var i:int = 0; i < a.length; i++)
+ {
+ result = numericCompare(a[i], b[i]);
+ if (result != 0)
+ {
+ i = a.length;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @private
+ */
+ private static function listCompare(a:IList, b:IList, currentDepth:int,
+ desiredDepth:int, refs:CircularReferenceManager):int
+ {
+ var result:int = 0;
+
+ if (a.length != b.length)
+ {
+ if (a.length < b.length)
+ result = -1;
+ else
+ result = 1;
+ }
+ else
+ {
+ for (var i:int = 0; i < a.length; i++)
+ {
+ result = internalCompare(a.getItemAt(i), b.getItemAt(i),
+ currentDepth+1, desiredDepth, refs);
+ if (result != 0)
+ {
+ i = a.length;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * @private
+ * This is the "find" for our union-find algorithm when doing object searches.
+ * The dictionary keeps track of sets of equal objects
+ */
+ private static function getRef(o:Object, refs:CircularReferenceManager):Object
+ {
+ var oRef:Object = refs[o];
+ while (oRef && oRef != refs[oRef])
+ {
+ oRef = refs[oRef];
+ }
+ if (!oRef)
+ oRef = o;
+ if (oRef != refs[o])
+ refs[o] = oRef;
+
+ return oRef;
+ }
+
+ /**
+ * @private
+ */
+ private static var refCount:int = 0;
+
+ /**
+ * @private
+ */
+ private static var CLASS_INFO_CACHE:Object = {};
+}
+
+}
+
- COMPILE::AS3
++COMPILE::SWF
+{
+ import flash.utils.Dictionary;
+}
+
+class CircularReferenceManager
+{
- COMPILE::AS3
++ COMPILE::SWF
+ private var dict:Dictionary = new Dictionary(true);
+
+ COMPILE::JS
+ private var array:Array = [];
+
+ public function CircularReferenceManager()
+ {
+ }
+
+ public function put(obj:Object):void
+ {
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ dict[obj] = 1;
+ }
+ COMPILE::JS
+ {
+ array.push(obj);
+ }
+ }
+
+ public function contains(obj:Object):Boolean
+ {
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ return (dict[obj] == 1);
+ }
+ COMPILE::JS
+ {
+ return array.indexOf(obj) != -1;
+ }
+ }
+
- }
++}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/utils/OnDemandEventDispatcher.as
----------------------------------------------------------------------
diff --cc frameworks/projects/MX/src/main/flex/mx/utils/OnDemandEventDispatcher.as
index 013d4bd,0000000..57b3498
mode 100644,000000..100644
--- a/frameworks/projects/MX/src/main/flex/mx/utils/OnDemandEventDispatcher.as
+++ b/frameworks/projects/MX/src/main/flex/mx/utils/OnDemandEventDispatcher.as
@@@ -1,169 -1,0 +1,169 @@@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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.events.Event;
+}
+COMPILE::JS
+{
+ import org.apache.flex.events.Event;
+}
+ import org.apache.flex.events.IEventDispatcher;
+ import org.apache.flex.events.EventDispatcher;
+
+ /**
+ * OnDemandEventDispatcher serves as a base class for classes that dispatch events but expect listeners
+ * to be infrequent. When a class extends OnDemandEventDispatcher instead of the standard EventDispatcher,
+ * it is trading off a small overhead on every single instance for a slightly larger overhead on only the instances
+ * that actually have listeners attached to them.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public class OnDemandEventDispatcher implements IEventDispatcher
+ {
+ private var _dispatcher:EventDispatcher;
+
+
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+ /**
+ * Constructor.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function OnDemandEventDispatcher()
+ {
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @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
+ {
+ if (_dispatcher == null)
+ {
+ _dispatcher = new EventDispatcher(this);
+ }
+ _dispatcher.addEventListener(type,listener,useCapture,priority,useWeakReference);
+ }
+ COMPILE::JS
+ public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, handlerScope:Object = null):void
+ {
+ if (_dispatcher == null)
+ {
+ _dispatcher = new EventDispatcher(this);
+ }
+ _dispatcher.addEventListener(type,listener,useCapture);
+ }
+
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
- COMPILE::AS3
++ COMPILE::SWF
+ public function dispatchEvent(event:Event):Boolean
+ {
+ if (_dispatcher != null)
+ return _dispatcher.dispatchEvent(event);
+ return true;
+ }
+ COMPILE::JS
+ public function dispatchEvent(event:Object):Boolean
+ {
+ if (_dispatcher != null)
+ return _dispatcher.dispatchEvent(event);
+ return true;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function hasEventListener(type:String):Boolean
+ {
+ if (_dispatcher != null)
+ return _dispatcher.hasEventListener(type);
+ return false;
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @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
+ {
+ if (_dispatcher != null)
+ _dispatcher.removeEventListener(type,listener,useCapture);
+ }
+ COMPILE::JS
+ public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false, handlerScope:Object = null):void
+ {
+ if (_dispatcher != null)
+ _dispatcher.removeEventListener(type,listener,useCapture);
+ }
+
+ /**
+ * @inheritDoc
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
- COMPILE::AS3
++ COMPILE::SWF
+ public function willTrigger(type:String):Boolean
+ {
+ if (_dispatcher != null)
+ return _dispatcher.willTrigger(type);
+ return false;
+ }
+
+ }
- }
++}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/utils/OrderedObject.as
----------------------------------------------------------------------
diff --cc frameworks/projects/MX/src/main/flex/mx/utils/OrderedObject.as
index f1e05cb,0000000..b20c30e
mode 100644,000000..100644
--- a/frameworks/projects/MX/src/main/flex/mx/utils/OrderedObject.as
+++ b/frameworks/projects/MX/src/main/flex/mx/utils/OrderedObject.as
@@@ -1,355 -1,0 +1,355 @@@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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.utils.Proxy;
- COMPILE::AS3
++COMPILE::SWF
+{
+import flash.utils.flash_proxy;
+import mx.utils.object_proxy;
+
+use namespace flash_proxy;
+use namespace object_proxy;
+}
+
+/**
+ * OrderedObject acts as a wrapper to Object to preserve the ordering of the
+ * properties as they are added.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+public dynamic class OrderedObject extends Proxy
+{
+ //--------------------------------------------------------------------------
+ //
+ // Constructor
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Constructor.
+ *
+ * @param item An Object containing name/value pairs.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ public function OrderedObject(item:Object=null)
+ {
+ super();
+
+ propertyList = [];
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Variables
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Contains a list of all of the property names for the proxied object.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
- COMPILE::AS3
++ COMPILE::SWF
+ object_proxy var propertyList:Array;
+ COMPILE::JS
+ protected var propertyList:Array;
+
+ //--------------------------------------------------------------------------
+ //
+ // Properties
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * @private
+ *
+ * Work around for the Flash Player bug #232854. The Proxy bug occurs when
+ * the Proxy class is used in a sibling ApplicationDomain of the main
+ * application's ApplicationDomain. When the Proxy class is used in a
+ * sibling ApplicationDomain the RTE looks like this:
+ *
+ * ArgumentError: Error #1063: Argument count mismatch on
+ * Object/http://adobe.com/AS3/2006/builtin::hasOwnProperty().
+ * Expected 0, got 2.
+ *
+ * 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.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
- COMPILE::AS3
++ COMPILE::SWF
+ object_proxy function getObjectProperty(name:*):*
+ {
+ return getProperty(name);
+ }
+
+ /**
+ * @private
+ *
+ * Work around for the Flash Player bug #232854. See the comments in
+ * getObjectProperty() for more details.
+ *
+ * Call this method to set a property value instead of hashing into an
+ * OrderObject which would end up calling setProperty().
+ *
+ * Updates the specified property on the proxied object.
+ *
+ * @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
+ object_proxy function setObjectProperty(name:*, value:*):void
+ {
+ setProperty(name, value);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // Overridden methods
+ //
+ //--------------------------------------------------------------------------
+
+ /**
+ * Deletes the specified property on 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 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 deleted:Boolean = delete valueMap[name];
+
+ var deleteIndex:int = -1;
+ for (var i:int = 0; i < propertyList.length; i++)
+ {
+ if (propertyList[i] == name)
+ {
+ deleteIndex = i;
+ break;
+ }
+ }
+ if (deleteIndex > -1)
+ {
+ propertyList.splice(deleteIndex, 1);
+ }
+
+ return deleted;
+ }
+
+ /**
+ * Deletes the specified property on 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 A Boolean indicating if the property was deleted.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
+ COMPILE::JS
+ override public function deleteProperty(name:String):Boolean
+ {
+ var deleted:Boolean = delete valueMap[name];
+
+ var deleteIndex:int = -1;
+ for (var i:int = 0; i < propertyList.length; i++)
+ {
+ if (propertyList[i] == name)
+ {
+ deleteIndex = i;
+ break;
+ }
+ }
+ if (deleteIndex > -1)
+ {
+ propertyList.splice(deleteIndex, 1);
+ }
+
+ return deleted;
+ }
+
+ /**
+ * This is an internal function that must be implemented by a subclass of
+ * flash.utils.Proxy.
+ *
+ * @param name The property name that should be tested for existence.
+ *
+ * @return If the property exists, <code>true</code>; otherwise
+ * <code>false</code>.
+ *
+ * @see flash.utils.Proxy#hasProperty()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
- COMPILE::AS3
++ COMPILE::SWF
+ override flash_proxy function hasProperty(name:*):Boolean
+ {
+ return(name in valueMap);
+ }
+ COMPILE::JS
+ override public function hasProperty(name:String):Boolean
+ {
+ return(name in valueMap);
+ }
+
+ /**
+ * This is an internal function that must be implemented by a subclass of
+ * flash.utils.Proxy.
+ *
+ * @param index The zero-based index value of the object's property.
+ *
+ * @return The property's name.
+ *
+ * @see flash.utils.Proxy#nextName()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
- COMPILE::AS3
++ COMPILE::SWF
+ override flash_proxy function nextName(index:int):String
+ {
+ return propertyList[index -1];
+ }
+ COMPILE::JS
+ override public function elementNames():Array
+ {
+ return propertyList.slice();
+ }
+
+ /**
+ * This is an internal function that must be implemented by a subclass of
+ * flash.utils.Proxy.
+ *
+ * @param index The zero-based index value of the object's property.
+ *
+ * @return The property's value.
+ *
+ * @see flash.utils.Proxy#nextValue()
+ *
+ * @langversion 3.0
+ * @playerversion Flash 9
+ * @playerversion AIR 1.1
+ * @productversion Flex 3
+ */
- COMPILE::AS3
++ COMPILE::SWF
+ override flash_proxy function nextValue(index:int):*
+ {
+ return valueMap[propertyList[index -1]];
+ }
+
+ /**
+ * Updates the specified property on the proxied object.
+ *
+ * @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:* = valueMap[name];
+ if (oldVal !== value)
+ {
+ // Update item.
+ valueMap[name] = value;
+
+ for (var i:int = 0; i < propertyList.length; i++)
+ {
+ if (propertyList[i] == name)
+ {
+ return;
+ }
+ }
+ propertyList.push(name);
+ }
+ }
+ COMPILE::JS
+ override public function setProperty(name:String, value:*):void
+ {
+ var oldVal:* = valueMap[name];
+ if (oldVal !== value)
+ {
+ // Update item.
+ valueMap[name] = value;
+
+ for (var i:int = 0; i < propertyList.length; i++)
+ {
+ if (propertyList[i] == name)
+ {
+ return;
+ }
+ }
+ propertyList.push(name);
+ }
+ }
+
+}
+
- }
++}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/77148f4a/frameworks/projects/MX/src/main/flex/mx/utils/Platform.as
----------------------------------------------------------------------
diff --cc frameworks/projects/MX/src/main/flex/mx/utils/Platform.as
index e954380,0000000..2fb50eb
mode 100644,000000..100644
--- a/frameworks/projects/MX/src/main/flex/mx/utils/Platform.as
+++ b/frameworks/projects/MX/src/main/flex/mx/utils/Platform.as
@@@ -1,344 -1,0 +1,344 @@@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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.system.Capabilities;
+}
+import org.apache.flex.utils.Platform;
+import org.apache.flex.reflection.getDefinitionByName;
+
+/**
+ * The Platform utility class contains several static methods to check what
+ * desktop or mobile platform the application is running on.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+public class Platform
+{
+ include "../core/Version.as";
+
+ protected static var _initialized:Boolean;
+ protected static var _isAndroid:Boolean;
+ protected static var _isIOS:Boolean;
+ protected static var _isIPad:Boolean;
+ protected static var _isBlackBerry:Boolean;
+ protected static var _isMobile:Boolean;
+ protected static var _isMac:Boolean;
+ protected static var _isWindows:Boolean;
+ protected static var _isLinux:Boolean;
+ protected static var _isDesktop:Boolean;
+ protected static var _isBrowser:Boolean;
+ protected static var _isAir:Boolean;
+ private static var _osVersion: String = null;
+
+ /**
+ * This value is set from AndroidPlatformVersionOverride
+ *
+ */
+ mx_internal static var androidVersionOverride:String;
+
+ /**
+ * This value is set from IOSPlatformVersionOverride
+ *
+ */
+ mx_internal static var iosVersionOverride:String;
+
+ /**
+ * Returns true if the application is running on IOS.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isIOS():Boolean
+ {
+ getPlatforms();
+
+ return _isIOS;
+ }
+
+ /**
+ * Returns true if the application is running on an iPad.
+ * Note this returns false in the AIR mobile device simulator.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isIPad():Boolean
+ {
+ getPlatforms();
+
+ return _isIPad;
+ }
+
+ /**
+ * Returns true if the application is running on a BlackBerry.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isBlackBerry():Boolean
+ {
+ getPlatforms();
+
+ return _isBlackBerry;
+ }
+
+ /**
+ * Returns true if the application is running on Android.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isAndroid():Boolean
+ {
+ getPlatforms();
+
+ return _isAndroid;
+ }
+
+ /**
+ * Returns true if the application is running on Windows.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isWindows():Boolean
+ {
+ getPlatforms();
+
+ return _isWindows;
+ }
+
+ /**
+ * Returns true if the application is running on a Mac.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isMac():Boolean
+ {
+ getPlatforms();
+
+ return _isMac;
+ }
+
+ /**
+ * Returns true if the application is running on Linux.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isLinux():Boolean
+ {
+ getPlatforms();
+
+ return _isLinux;
+ }
+
+ /**
+ * Returns true if the application is running on a Desktop OS.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isDesktop():Boolean
+ {
+ getPlatforms();
+
+ return _isDesktop;
+ }
+
+ /**
+ * Returns true if the application is running on a Mobile device.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isMobile():Boolean
+ {
+ getPlatforms();
+
+ return _isMobile;
+ }
+
+ /**
+ * Returns true if the application is running on a desktop AIR.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isAir():Boolean
+ {
+ getPlatforms();
+
+ return _isAir;
+ }
+
+ /**
+ * Returns true if the application is running in a browser.
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.12
+ */
+ public static function get isBrowser():Boolean
+ {
+ getPlatforms();
+
+ return _isBrowser;
+ }
+
+ /**
+ * Returns the version of the OS the application is running on
+ *
+ * @langversion 3.0
+ * @playerversion Flash 10
+ * @playerversion AIR 2.0
+ * @productversion Flex 4.13
+ */
+ public static function get osVersion(): String
+ {
+ //We needed to compute _osVersion later than getPlatforms, because it relies on resources that ready later
+ if (_osVersion == null){
+ if(mx_internal::androidVersionOverride == null && mx_internal::iosVersionOverride == null)
+ {
+ _osVersion = computeOSVersionString();
+ }
+ else if(mx_internal::androidVersionOverride != null)
+ {
+ _osVersion = mx_internal::androidVersionOverride;
+ }
+ else if(mx_internal::iosVersionOverride != null)
+ {
+ _osVersion = mx_internal::iosVersionOverride;
+ }
+ }
+ return _osVersion;
+ }
+
+ /* Notes on Capabilities.os for mobile apps:
+ - on ADL => returns the OS where the ADL is running ( eg. Windows 7, or Mac OS )
+ - on device => returns the OS of the device (eg. iPhone OS ... for iOS devices )
+ * */
+ protected static function getPlatforms():void {
+ if (!_initialized)
+ {
+ var p:String = org.apache.flex.utils.Platform.platform;
+
+ _isAndroid = p == org.apache.flex.utils.Platform.ANDROID;
+ _isIOS = p == org.apache.flex.utils.Platform.IOS;
+ _isBlackBerry = p == org.apache.flex.utils.Platform.BLACKBERRY;
+ _isMobile = _isAndroid || _isIOS || _isBlackBerry;
+
+ _isMac = p == org.apache.flex.utils.Platform.MAC;
+ _isWindows = p == org.apache.flex.utils.Platform.WINDOWS;
+ _isLinux = p == org.apache.flex.utils.Platform.LINUX; // note that Android is also Linux
+ _isIPad = org.apache.flex.utils.Platform.isIPad;
+ _isDesktop = !_isMobile;
+
+ _isAir = org.apache.flex.utils.Platform.isAir;
+ _isBrowser = org.apache.flex.utils.Platform.isBrowser;
+
+ _initialized = true;
+ }
+ }
+
+ /** @private
+ * extract OS version information from Capabilities.os
+ * os is typically a non-numeric string (such as Windows, iPhone OS, Android, etc...) followed by a number sequence.
+ * if no number is found, OS version is set to 0.
+ * os on ADL will return the host OS and not the device OS.
+ *
+ * That's why we need to check for a specific sequence for iOS and Android.
+ * On Android, os is the Linux kernel version (such as Linux 3.4.34-1790463).
+ * So the version information must be retrieved from an internal file.
+ * Since reading files API is only available on AIR, it's delegated to PlatformMobileHelper in mobilecomponents.swc
+ * @see spark.utils.PlatformMobileHelper
+ *
+ * @return version number string, or empty string if could not retrieve the version.
+ * */
+ private static function computeOSVersionString(): String
+ {
- COMPILE::AS3
++ COMPILE::SWF
+ {
+ var os: String = Capabilities.os;
+ var osVersionMatch: Array;
+ var version: String = "";
+
+ if (isIOS) {
+ osVersionMatch = os.match(/iPhone OS\s([\d\.]+)/);
+ if (osVersionMatch && osVersionMatch.length == 2)
+ version = osVersionMatch[1];
+ }
+ else if (isAndroid) {
+ try {
+ var mobileHelperClass: Class = Class(getDefinitionByName("spark.utils::PlatformMobileHelper"));
+ if (mobileHelperClass != null) {
+ version = mobileHelperClass["computeOSVersionForAndroid"]();
+ }
+ }
+ catch (e: Error) {
+ trace("Error: " + e.message);
+ }
+ }
+ else {
+ //on other OS, extract version
+ osVersionMatch = os.match(/[A-Za-z\s]+([\d\.]+)/);
+ if (osVersionMatch && osVersionMatch.length == 2)
+ version = osVersionMatch[1];
+ }
+ return version;
+ }
+ COMPILE::JS
+ {
+ // TODO (aharui): Do something better someday?
+ return "0";
+ }
+ }
+
+}
+}