123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672 |
- /*
- * Copyright 2011, The gwtquery team.
- *
- * Licensed 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 com.google.gwt.query.client.js;
-
- import static com.google.gwt.query.client.GQuery.browser;
-
- import com.google.gwt.core.client.GWT;
- import com.google.gwt.core.client.JavaScriptObject;
- import com.google.gwt.core.client.JsArray;
- import com.google.gwt.core.client.JsArrayMixed;
- import com.google.gwt.core.client.JsonUtils;
- import com.google.gwt.dom.client.Document;
- import com.google.gwt.dom.client.Element;
- import com.google.gwt.dom.client.Node;
- import com.google.gwt.dom.client.NodeList;
- import com.google.gwt.query.client.Function;
- import com.google.gwt.query.client.GQuery;
- import com.google.gwt.query.client.Properties;
- import com.google.gwt.user.client.Command;
- import com.google.gwt.user.client.DOM;
-
- /**
- * A bunch of utility methods for GQuery.
- */
- public class JsUtils {
-
- /**
- * A Function which wraps a javascript function.
- */
- public static class JsFunction extends Function implements Command {
- private JavaScriptObject jso = null;
-
- public JsFunction(JavaScriptObject f) {
- if (JsUtils.isFunction(f)) {
- jso = f;
- }
- }
-
- public boolean equals(Object obj) {
- return jso.equals(obj);
- }
-
- public int hashCode() {
- return jso.hashCode();
- }
-
- private native Object exec(JavaScriptObject f, Object data) /*-{
- return @com.google.gwt.query.client.js.JsCache::gwtBox(*)([ f(data) ]);
- }-*/;
-
- public void f() {
- if (jso != null) {
- setArguments(exec(jso, arguments(0)));
- }
- }
-
- public void execute() {
- f();
- }
- }
-
- /**
- * Wraps a GQuery function into a native javascript one so as we can
- * export Java methods without using JSNI.
- */
- public static native JavaScriptObject wrapFunction(Function f) /*-{
- return function(r) {
- var o = @java.util.ArrayList::new()();
- for (i in arguments) {
- r = @com.google.gwt.query.client.js.JsCache::gwtBox(*)([arguments[i]]);
- o.@java.util.ArrayList::add(Ljava/lang/Object;)(r);
- }
- o = o.@java.util.ArrayList::toArray()();
- f.@com.google.gwt.query.client.Function::setArguments([Ljava/lang/Object;)(o);
- return f.@com.google.gwt.query.client.Function::fe([Ljava/lang/Object;)(o);
- }
- }-*/;
-
- /**
- * Default JsUtils implementation.
- */
- public static class JsUtilsImpl {
- public Properties parseJSON(String json) {
- return JsonUtils.safeEval(json);
- }
-
- public native String JSON2String(JavaScriptObject o) /*-{
- return $wnd.JSON.stringify(o);
- }-*/;
-
- public native Element parseXML(String xml) /*-{
- return new DOMParser().parseFromString(xml, "text/xml").documentElement;
- }-*/;
-
- public String text(Element e) {
- return e.getInnerText();
- }
-
- public JsArray<Element> unique(JsArray<Element> a) {
- JsArray<Element> ret = JavaScriptObject.createArray().cast();
- JsCache cache = JsCache.create();
- for (int i = 0; i < a.length(); i++) {
- Element e = a.get(i);
- int id = e.hashCode();
- if (!cache.exists(id)) {
- cache.putNumber(id, 1);
- ret.push(e);
- }
- }
- return ret;
- }
-
- public native String XML2String(JavaScriptObject o) /*-{
- return (new XMLSerializer()).serializeToString(o);
- }-*/;
- }
-
- /**
- * IE JsUtils implemetation.
- */
- public static class JsUtilsImplIE6 extends JsUtilsImpl {
- @Override
- public Properties parseJSON(String json) {
- return JsonUtils.unsafeEval(json);
- }
-
- @Override
- public String JSON2String(JavaScriptObject js) {
- // This is a very basic implementation for IE6/IE7 of JSON.stringify
- // If many people demand a better one we could consider to use json2.js
- // @see https://github.com/douglascrockford/JSON-js/blob/master/json2.js
- Properties prop = js.cast();
- String ret = "";
- for (String k : prop.keys()) {
- String ky = k.matches("\\d+") ? k : "\"" + k + "\"";
- JsCache o = prop.getArray(k).cast();
- if (o != null) {
- ret += ky + ":[";
- for (int i = 0, l = o.length(); i < l; i++) {
- Properties p = o.<JsCache> cast().getJavaScriptObject(i);
- if (p != null) {
- ret += p.toJsonString() + ",";
- } else {
- ret += "\"" + o.getString(i) + "\",";
- }
- }
- ret += "],";
- } else {
- Properties p = prop.getJavaScriptObject(k);
- if (p != null) {
- ret += ky + ":" + p.toJsonString() + ",";
- } else {
- ret += ky + ":\"" + prop.getStr(k) + "\",";
- }
- }
- }
- return "{" + ret.replaceAll(",\\s*([\\]}]|$)", "$1")
- .replaceAll("([:,\\[])\"(-?[\\d\\.]+|null|false|true)\"", "$1$2")
- + "}";
- }
-
- @Override
- public native Element parseXML(String xml) /*-{
- var d = new ActiveXObject("Microsoft.XmlDom");
- d.loadXML(xml);
- return d.documentElement;
- }-*/;
-
- @Override
- public String text(Element e) {
- return isXML(e) ? xmlText(e) : super.text(e);
- }
-
- @Override
- public JsArray<Element> unique(JsArray<Element> a) {
- // in IE6 XML elements does not support adding hashId to the object
- if (browser.ie6 && isXML(a.get(0))) {
- return a;
- }
- return super.unique(a);
- }
-
- @Override
- public native String XML2String(JavaScriptObject o) /*-{
- return o.xml;
- }-*/;
-
- private native String xmlText(Element e) /*-{
- return e.text;
- }-*/;
- }
-
- private static JsUtilsImpl utilsImpl = GWT.create(JsUtilsImpl.class);
-
- /**
- * Returns a property present in a javascript object.
- */
- public static <T> T prop(JavaScriptObject o, Object id, Class<? extends T> type) {
- return o == null ? null : o.<JsCache> cast().get(id, type);
- }
-
- /**
- * Returns a property present in a javascript object.
- */
- public static <T> T prop(JavaScriptObject o, Object id) {
- return o == null ? null : o.<JsCache> cast().<T> get(id);
- }
-
- /**
- * Set a property to a javascript object.
- */
- public static void prop(JavaScriptObject o, Object id, Object val) {
- if (o != null) {
- o.<JsCache> cast().put(id, val);
- }
- }
-
- /**
- * Execute a native javascript function.
- */
- public static <T> T exec(JavaScriptObject jsFunction, Object... args) {
- assert isFunction(jsFunction);
- return jsni(jsFunction, "call", jsFunction, args);
- }
-
- /**
- * Assign a function to a property of the window object.
- */
- public static void export(String name, Function f) {
- export(GQuery.window, name, f);
- }
-
- /**
- * Export a function as a property of a javascript object.
- */
- public static void export(JavaScriptObject o, String name, Function f) {
- prop(o, name, (Object)(f != null ? wrapFunction(f) : null));
- }
-
- /**
- * Camelize style property names.
- * for instance: font-name -> fontName
- */
- public static native String camelize(String s) /*-{
- return s.replace(/\-(\w)/g, function(all, letter) {
- return letter.toUpperCase();
- });
- }-*/;
-
- /**
- * Merge the oldNodes list into the newNodes one. If oldNodes is null, a new
- * list will be created and returned. If oldNodes is not null, a new list will
- * be created depending on the create flag.
- */
- public static NodeList<Element> copyNodeList(NodeList<Element> oldNodes,
- NodeList<Element> newNodes, boolean create) {
- NodeList<Element> ret = oldNodes == null || create ? JsNodeArray.create()
- : oldNodes;
- JsCache idlist = JsCache.create();
- for (int i = 0; oldNodes != null && i < oldNodes.getLength(); i++) {
- Element e = oldNodes.getItem(i);
- idlist.put(e.hashCode(), 1);
- if (create) {
- ret.<JsNodeArray> cast().addNode(e, i);
- }
- }
- for (int i = 0, l = newNodes.getLength(), j = ret.getLength(); i < l; i++) {
- Element e = newNodes.getItem(i);
- if (!idlist.exists(e.hashCode())) {
- ret.<JsNodeArray> cast().addNode(newNodes.getItem(i), j++);
- }
- }
- return ret;
- }
-
- /**
- * Use the method in the gquery class.
- * $(elem).cur(prop, force);
- */
- @Deprecated
- public static double cur(Element elem, String prop, boolean force) {
- return GQuery.$(elem).cur(prop, force);
- }
-
- /**
- * Compare two numbers using javascript equality.
- */
- public static native boolean eq(double s1, double s2) /*-{
- return s1 == s2;
- }-*/;
-
- /**
- * Compare two objects using javascript equality.
- */
- public static native boolean eq(Object s1, Object s2) /*-{
- return s1 == s2;
- }-*/;
-
- /**
- * Returns the owner document element of an element.
- */
- public static Document getOwnerDocument(Node n) {
- return n == null || !isElement(n) ? null : n.getNodeType() == Node.DOCUMENT_NODE
- ? n.<Document> cast() : n.getOwnerDocument();
- }
-
- /**
- * Check if an object has a property with <code>name</code> defined.
- * It supports dots in the name meaning checking nested properties.
- *
- * Example:
- * <pre>
- * // Check whether a browser supports touch events
- * hasProperty(window, "ontouchstart");
- * </pre>
- */
- public static native boolean hasProperty(JavaScriptObject o, String name)/*-{
- var p = name.split('.');
- for (var i in p) {
- if (!(o && p[i] in o)) return false;
- o = o[p[i]];
- }
- return true;
- }-*/;
-
- /**
- * Check whether an element has an attribute, this is here since GWT Element.getAttribute
- * implementation returns an empty string instead of null when the attribute is not
- * present.
- */
- public static native boolean hasAttribute(Element o, String name) /*-{
- return !!(o && o.getAttribute(name) !== null);
- }-*/;
-
- /**
- * Hyphenize style property names.
- * for instance: fontName -> font-name
- */
- public static native String hyphenize(String name) /*-{
- return name.replace(/([A-Z])/g, "-$1").toLowerCase();
- }-*/;
-
- /**
- * Check is a javascript object can be used as an array.
- */
- public static native boolean isArray(JavaScriptObject o) /*-{
- return Object.prototype.toString.call(o) == '[object Array]'
- || typeof o.length == 'number';
- }-*/;
-
- /**
- * Check is a javascript object is a FormData.
- */
- public static native boolean isFormData(JavaScriptObject o) /*-{
- return Object.prototype.toString.call(o) == '[object FormData]';
- }-*/;
-
- /**
- * Return whether the event was prevented.
- */
- public static native boolean isDefaultPrevented(JavaScriptObject e) /*-{
- return e.defaultPrevented || e.returnValue === false || e.getPreventDefault
- && e.getPreventDefault() ? true : false;
- }-*/;
-
- /**
- * Return whether a node is detached to the DOM.
- *
- * Be careful : This method works only on node that should be inserted within the body node.
- */
- public static boolean isDetached(Node n) {
- assert n != null;
-
- if ("html".equalsIgnoreCase(n.getNodeName())) {
- return false;
- }
-
- return !getOwnerDocument(n).getBody().isOrHasChild(n);
- }
-
- /**
- * Check is a javascript object can be cast to an Element.
- */
- public static native boolean isElement(Object o) /*-{
- return !!o && 'nodeType' in o && 'nodeName' in o;
- }-*/;
-
- /**
- * Check is a javascript object can be cast to an Event.
- */
- public static boolean isEvent(JavaScriptObject o) {
- return hasProperty(o, "currentTarget");
- }
-
- /**
- * Check is a javascript object is a function.
- */
- public static native boolean isFunction(JavaScriptObject o) /*-{
- return Object.prototype.toString.call(o) == '[object Function]';
- }-*/;
-
- /**
- * Check is a javascript can be cast to a node list.
- */
- public static native boolean isNodeList(JavaScriptObject o) /*-{
- var r = Object.prototype.toString.call(o);
- return r == '[object HTMLCollection]' || r == '[object NodeList]'
- || (typeof o == 'object' && o.length && o[0] && o[0].tagName) ? true : false;
- }-*/;
-
- /**
- * Check is a javascript object is a Window.
- */
- public static boolean isWindow(JavaScriptObject o) {
- return hasProperty(o, "alert");
- }
-
- /**
- * Check if an element is a DOM or a XML node.
- */
- public static boolean isXML(Node o) {
- return o == null ? false
- : !"HTML".equals(getOwnerDocument(o).getDocumentElement().getNodeName());
- }
-
- /**
- * Load an external javascript library. The inserted script replaces the
- * element with the given id in the document.
- *
- * @deprecated use {@link com.google.gwt.query.client.plugins.ajax.Ajax#loadScript(String)}
- */
- @Deprecated
- public static void loadScript(String url, String id) {
- GQuery gs = GQuery.$(DOM.createElement("script"));
- GQuery gp = GQuery.$("#" + id).parent();
- if (gp.size() != 1) {
- gp = GQuery.$(GQuery.document.getBody());
- }
- GQuery.$("#" + id).remove();
- gp.append(gs.attr("src", url).attr("type", "text/javascript").attr("id", id));
- }
-
- /**
- * Return the element which is truth in the double scope.
- */
- public static native double or(double s1, double s2) /*-{
- return s1 || s2;
- }-*/;
-
- /**
- * Return the element which is truth in the javascript scope.
- */
- public static native <T> T or(T s1, T s2) /*-{
- return s1 || s2;
- }-*/;
-
- /**
- * Parses a json string returning a Object with useful method to get the
- * content.
- */
- public static Properties parseJSON(String json) {
- try {
- return utilsImpl.parseJSON(json);
- } catch (Exception e) {
- if (!GWT.isProdMode()) {
- System.err.println("Error while parsing json: " + e.getMessage() + ".\n" + json);
- }
- return Properties.create();
- }
- }
-
- /**
- * Parses a xml string and return the xml document element which can then be
- * passed to GQuery to create a typical GQuery object that can be traversed
- * and manipulated.
- */
- public static Element parseXML(String xml) {
- return utilsImpl.parseXML(xml);
- }
-
- public static String text(Element e) {
- return utilsImpl.text(e);
- }
-
- /**
- * Utility method to cast objects in production.
- * Useful for casting native implementations to interfaces like JsInterop
- */
- public static native <T> T cast(Object o) /*-{
- return o;
- }-*/;
-
- /**
- * Utility method to cast objects to array of string in production.
- */
- public static native String[] castArrayString(Object a) /*-{
- return a
- }-*/;
-
- /**
- * Call any arbitrary function present in a Javascript object.
- * It checks the existence of the function and object hierarchy before executing it.
- * It's very useful in order to avoid writing jsni blocks for very simple snippets.
- *
- * Note that GWT 3.0 jsinterop will come with a method similar, so we might deprecate
- * this in the future.
- *
- * Example
- * <pre>
- * // Create a svg node in our document.
- * Element svg = jsni(document, "createElementNS", "http://www.w3.org/2000/svg", "svg");
- * // Append it to the dom
- * $(svg).appendTo(document);
- * // show the svg element in the debug console
- * jsni("console.log", svg);
- * </pre>
- *
- * @param jso the object containing the method to execute
- * @param meth the literal name of the function to call, dot separators are allowed.
- * @param args an array with the arguments to pass to the function.
- * @return the java ready boxed object returned by the jsni method or null, if the
- * call return a number we will get a Double, if it returns a boolean we get a java
- * Boolean, strings comes as java String, otherwise we get the javascript object.
- */
- public static <T> T jsni(JavaScriptObject jso, String meth, Object... args) {
- return runJavascriptFunction(jso, meth, args);
- }
-
- /**
- * Run any arbitrary function in javascript scope using the window as the base object.
- * It checks the existence of the function and object hierarchy before executing it.
- * It's very useful in order to avoid writing jsni blocks for very simple snippets.
- *
- * Note that GWT 3.0 jsinterop will come with a method similar, so we might deprecate
- * this in the future.
- *
- * Example
- * <pre>
- * // Create a svg node in our document.
- * Element svg = jsni("document.createElementNS", "http://www.w3.org/2000/svg", "svg");
- * // Append it to the dom
- * $(svg).appendTo(document);
- * // show the svg element in the debug console
- * jsni("console.log", svg);
- * </pre>
- *
- * @param meth the literal name of the function to call, dot separators are allowed.
- * @param args an array with the arguments to pass to the function.
- * @return the java ready boxed object returned by the jsni method or null, if the
- * call return a number we will get a Double, if it returns a boolean we get a java
- * Boolean, strings comes as java String, otherwise we get the javascript object.
- */
- public static <T> T jsni(String meth, Object... args) {
- return runJavascriptFunction(null, meth, args);
- }
-
- /**
- * Call via jsni any arbitrary function present in a Javascript object.
- *
- * It's thought for avoiding to create jsni methods to call external functions and
- * facilitate the writing of js wrappers.
- *
- * Example
- * <pre>
- * // Create a svg node in our document.
- * Element svg = runJavascriptFunction(document, "createElementNS", "http://www.w3.org/2000/svg", "svg");
- * // Append it to the dom
- * $(svg).appendTo(document);
- * </pre>
- *
- * @param o the javascript object where the function is, it it is null we use window.
- * @param meth the literal name of the function to call, dot separators are allowed.
- * @param args an array with the arguments to pass to the function.
- * @return the java ready boxed object returned by the jsni method or null, if the
- * call return a number we will get a Double, if it returns a boolean we get a java
- * Boolean, strings comes as java String, otherwise we get the javascript object.
- *
- * @deprecated use jsni instead.
- */
- public static <T> T runJavascriptFunction(JavaScriptObject o, String meth, Object... args) {
- return runJavascriptFunctionImpl(o, meth, JsObjectArray.create().add(args).<JsArrayMixed>cast());
- }
-
- private static native <T> T runJavascriptFunctionImpl(JavaScriptObject o, String meth, JsArrayMixed args) /*-{
- var f = o || $wnd, p = meth.split('.');
- for (var i in p) {
- o = f;
- f = f[p[i]];
- if (!f) return null;
- }
- return @com.google.gwt.query.client.js.JsUtils::isFunction(*)(f)
- && @com.google.gwt.query.client.js.JsCache::gwtBox(*)([f.apply(o, args)]);
- }-*/;
-
- /**
- * Check if a number is true in the javascript scope.
- */
- public static native boolean truth(double a) /*-{
- return a ? true : false;
- }-*/;
-
- /**
- * Check if an object is true in the javascript scope.
- */
- public static native boolean truth(Object a) /*-{
- return a ? true : false;
- }-*/;
-
- /**
- * Remove duplicates from an elements array.
- */
- public static JsArray<Element> unique(JsArray<Element> a) {
- return utilsImpl.unique(a);
- }
-
- public static String XML2String(JavaScriptObject js) {
- return utilsImpl.XML2String(js);
- }
-
- public static String JSON2String(JavaScriptObject js) {
- return utilsImpl.JSON2String(js);
- }
-
- /**
- * Returns a QueryString representation of a JavascriptObject.
- *
- * TODO: jquery implementation accepts a second parameter (traditional)
- */
- public static String param(JavaScriptObject js) {
- Properties prop = js.cast();
- String ret = "";
- for (String k : prop.keys()) {
- ret += ret.isEmpty() ? "" : "&";
- JsCache o = prop.getArray(k).cast();
- if (o != null) {
- for (int i = 0, l = o.length(); i < l; i++) {
- ret += i > 0 ? "&" : "";
- Properties p = o.<JsCache> cast().getJavaScriptObject(i);
- if (p != null) {
- ret += k + "[]=" + p.toJsonString();
- } else {
- ret += k + "[]=" + o.getString(i);
- }
- }
- } else {
- Properties p = prop.getJavaScriptObject(k);
- if (p != null) {
- ret += k + "=" + p.tostring();
- } else {
- String v = prop.getStr(k);
- if (v != null && !v.isEmpty() && !"null".equalsIgnoreCase(v)) {
- ret += k + "=" + v;
- }
- }
- }
- }
- return ret;
- }
- }
|