package votorola.g.web.gwt; // Copyright 2011-2012, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. import com.google.gwt.core.client.*; import java.util.*; /** An extended handle to a native JavaScript object. */ public class JavaScriptObjectX extends JavaScriptObject { protected JavaScriptObjectX() {} // "precisely one constructor... protected, empty, and no-argument" // /** Returns an empty array that is intended to be immutable. Do not modify it. // */ // public static JsArray _emptyArray() // { // assert EMPTY_ARRAY.length() == 0; // return EMPTY_ARRAY.cast(); // } // // // private static final JsArray EMPTY_ARRAY = createArray().cast(); /** Returns the names of all enumerable properties of this object, including any * inherited ones. * * @see #_in() * @see #_propertyIsEnumerable(String) */ public final native JsArrayString _enumerablePropertyNames() /*-{ var array = []; for( var name in this ) array.push( name ); return array; }-*/; /** Answers whether the specified object looks like an instance of a particular * JavaScriptObject subclass defined by the names of its non-inherited, {@linkplain * #_hasOwnProperty(String) own properties}. Returns true if it might be an * instance, false if it definitely is not. This duck typing is required * for instances of JavaScriptObject because they are typeless at runtime, having * only compile-time "overlay typing". * * @see Overlay typing and instanceof operator */ public static boolean _isDuckType( final JavaScriptObject js, final String... ownPropertyNames ) { assert ownPropertyNames.length > 0; for( final String name: ownPropertyNames ) if( !js._hasOwnProperty( name )) return false; return true; } /** Answers whether the specified object looks like an instance of a particular * JavaScriptObject subclass defined by the names of its non-inherited, {@linkplain * #_hasOwnProperty(String) own properties}. Returns true if it might be an * instance, false if it definitely is not. This duck typing is required * for instances of JavaScriptObject because they are typeless at runtime, having * only compile-time "overlay typing". * * @see Overlay typing and instanceof operator */ public static boolean _isDuckType( final Object o, final String... ownPropertyNames ) { return o instanceof JavaScriptObject? _isDuckType( (JavaScriptObject)o, ownPropertyNames ): false; } // - I t e r a b l e ------------------------------------------------------------------ /** Constructs an iterable over the enumerable property names of this object. This * allows for iteration over the property names of the underlying JavaScript object * (o), using something like JavaScript's for/in syntax:
      *
      *     for( var name in o ) window.alert( name ); // JavaScript
* *

The ideal equivalent in Java would probably be a foreach loop over * an iterable JavaScriptObject (jso), similar to this:

      *
      *     for( String name: jso ) Window.alert( name ); // not possible
* *

But that is not possible because a GWT bug prevents JavaScriptObject from * implementing Iterable. Hence this method, which allows for iteration over a * JavaScriptObjectX (jsox) like this:

      *
      *     for( String name: jsox._in() ) Window.alert( name );
* * @see #_enumerablePropertyNames() * @see JavaScriptObject with Iterable<T> breaks Development Mode */ // public final Iterator iterator() // { // return new IteratorA() public final Iterable _in() { return new Iterable() // OPT could cache this as property, but seems heavy handed { public Iterator iterator() { return new votorola.g.util.IteratorA() { private int n; private final JsArrayString names = _enumerablePropertyNames(); public boolean hasNext() { return n < names.length(); } public String next() { if( n >= names.length() ) throw new NoSuchElementException(); return names.get( n++ ); } }; } }; } }