]> source.dussan.org Git - gwtquery.git/commitdiff
Implementation of Ajax JSONP using script tags
authorManolo Carrasco <manolo@apache.org>
Wed, 8 Feb 2012 11:55:08 +0000 (11:55 +0000)
committerManolo Carrasco <manolo@apache.org>
Wed, 8 Feb 2012 11:55:08 +0000 (11:55 +0000)
gwtquery-core/src/main/java/com/google/gwt/query/client/Function.java
gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/ajax/Ajax.java
gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryAjaxTestGwt.java

index 75a023ceb559385260a47f890d120bb5f6934dcd..08f6415d8393ee37695c95a9935e41dadb307df6 100644 (file)
@@ -40,7 +40,7 @@ public abstract class Function {
   
   public void setEvent(Event e) {
     event = e;
-    element = e.getCurrentEventTarget().<com.google.gwt.dom.client.Element>cast();
+    element = e != null ? e.getCurrentEventTarget().<com.google.gwt.dom.client.Element>cast() : null;
   }
   
   public Event getEvent() {
@@ -59,6 +59,38 @@ public abstract class Function {
     this.data = data;
   }
   
+  public Object getDataObject() {
+    return getDataObject(0);
+  }
+
+  public Object getDataObject(int idx) {
+    return data.length > idx ? data[idx] : null;
+  }
+  
+  public Properties getDataProperties() {
+    return getDataProperties(0);
+  }
+  
+  public Properties getDataProperties(int idx) {
+    Object o = getDataObject(idx);
+    if (o != null && o instanceof JavaScriptObject) {
+      return (Properties)o;
+    }
+    return null;
+  }
+
+  public void setData(boolean b) {
+    setData(Boolean.valueOf(b));
+  }
+
+  public void setData(double b) {
+    setData(Double.valueOf(b));
+  }
+  
+  public void setDataObject(Object data) {
+    setData(data);
+  }
+  
   public int getIndex() {
     return index;
   }
@@ -183,7 +215,7 @@ public abstract class Function {
    */
   public boolean f(Event e) {
     setEvent(e);
-    f(e.getCurrentEventTarget().<com.google.gwt.dom.client.Element>cast());
+    f(element);
     return true;
   }
   
@@ -208,7 +240,7 @@ public abstract class Function {
   private boolean loop = false;
   public void f(com.google.gwt.user.client.Element e) {
     setElement(e);
-    Widget w = GQuery.getAssociatedWidget(e);
+    Widget w = e != null ? GQuery.getAssociatedWidget(e) : null;
     if (w != null){
       loop = true;
       f(w);
index 2bc9aa4547521a0a6b22774617f3d9edd04bae70..bf64308da48a62b20f7a45f37f7cb48624f5119d 100644 (file)
@@ -77,6 +77,8 @@ public class JsCache extends JavaScriptObject {
   }
 
   public final native <T> double getDouble(T id) /*-{
+    // HtmlUnit prints an 'Unknown property name in get valueOf' 
+    // error here, but it is ok.
     var r = this[id] ? Number(this[id]) : 0;
     return r ? r : 0;
   }-*/;
index d2881c2840182a28d61e7a6f201908e4c348e648..d30020c5e24c8195781e9403cc16d298f4afe894 100644 (file)
@@ -11,6 +11,7 @@ import com.google.gwt.http.client.Response;
 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.query.client.builders.JsonBuilder;
 import com.google.gwt.query.client.js.JsUtils;
 import com.google.gwt.query.client.plugins.Plugin;
 
@@ -33,159 +34,33 @@ public class Ajax extends GQuery {
   /**
    * Ajax Settings object
    */
-  public static class Settings {
-
-    private static final String CONTENT_TYPE_KEY = "contentType";
-    private static final String CONTEXT_KEY = "context";
-    private static final String DATA_KEY = "data";
-    private static final String DATA_STRING_KEY = "dataString";
-    private static final String DATA_TYPE_KEY = "dataType";
-    private static final String HEADERS_KEY = "headers";
-    private static final String PASSWORD_KEY = "password";
-    private static final String TIMEOUT_KEY = "timeout";
-    private static final String TYPE_KEY = "type";
-    private static final String URL_KEY = "url";
-    private static final String USERNAME_KEY = "username";
-
-    public Properties settings;
-    public Function onSuccess;
-    public Function onError;
-    
-    public Settings() {
-      settings = Properties.create();
-      initDefaults();
-    }
-
-    /**
-     * Init some settings with default value
-     */
-    private void initDefaults() {
-      setDataType("text");
-      setType("POST");
-      setContentType("application/x-www-form-urlencoded");
-    }
-
-    public String getContentType() {
-      return settings.getStr(CONTENT_TYPE_KEY);
-    }
-
-    public Element getContext() {
-      return settings.get(CONTEXT_KEY);
-    }
-
-    public Properties getData() {
-      return settings.get(DATA_KEY);
-    }
-
-    public String getDataString() {
-      return settings.get(DATA_STRING_KEY);
-    }
-
-    public String getDataType() {
-      return settings.get(DATA_TYPE_KEY);
-    }
-
-    public Function getError() {
-      return onError;
-    }
-
-    public Properties getHeaders() {
-      return settings.get(HEADERS_KEY);
-    }
-
-    public String getPassword() {
-      return settings.get(PASSWORD_KEY);
-    }
-
-    public Function getSuccess() {
-      return onSuccess;
-    }
-
-    public int getTimeout() {
-      Integer timeout = settings.get(TIMEOUT_KEY);
-      return timeout != null ? timeout.intValue() : 0;
-    }
-
-    public String getType() {
-      return settings.get(TYPE_KEY);
-    }
-
-    public String getUrl() {
-      return settings.get(URL_KEY);
-    }
-
-    public String getUsername() {
-      return settings.get(USERNAME_KEY);
-    }
-
-    public Settings setContentType(String t) {
-      settings.set(CONTENT_TYPE_KEY, t);
-      return this;
-    }
-
-    public Settings setContext(Element e) {
-      settings.set(CONTEXT_KEY, e);
-      return this;
-    }
-
-    public Settings setData(Properties p) {
-      settings.set(DATA_KEY, p);
-      return this;
-    }
-
-    public Settings setDataString(String d) {
-      settings.set(DATA_STRING_KEY, d);
-      return this;
-    }
-
-    public Settings setDataType(String t) {
-      settings.set(DATA_TYPE_KEY, t);
-      return this;
-    }
-
-    public Settings setError(Function f) {
-      onError = f;
-      return this;
-    }
-
-    public Settings setHeaders(Properties p) {
-      settings.set(HEADERS_KEY, p);
-      return this;
-    }
-
-    public Settings setPassword(String p) {
-      settings.set(PASSWORD_KEY, p);
-      return this;
-    }
-
-    public Settings setSuccess(Function f) {
-      onSuccess = f;
-      return this;
-    }
-
-    public Settings setTimeout(int t) {
-      settings.set(TIMEOUT_KEY, t);
-      return this;
-    }
-
-    public Settings setType(String t) {
-      settings.set(TYPE_KEY, t);
-      return this;
-    }
-
-    public Settings setUrl(String u) {
-      settings.set(URL_KEY, u);
-      return this;
-    }
-
-    public Settings setUsername(String u) {
-      settings.set(USERNAME_KEY, u);
-      return this;
-    }
-
-    public void load(Properties p) {
-      settings = p;
-    }
+  public interface Settings extends JsonBuilder {
+    String getContentType();
+    Element getContext();
+    Properties getData();
+    String getDataString();
+    String getDataType();
+    Function getError();
+    Properties getHeaders();
+    String getPassword();
+    Function getSuccess();
+    int getTimeout();
+    String getType();
+    String getUrl();
+    String getUsername();
+    Settings setContentType(String t);
+    Settings setContext(Element e);
+    Settings setData(Properties p);
+    Settings setDataString(String d);
+    Settings setDataType(String t);
+    Settings setError(Function f);
+    Settings setHeaders(Properties p);
+    Settings setPassword(String p);
+    Settings setSuccess(Function f);
+    Settings setTimeout(int t);
+    Settings setType(String t);
+    Settings setUrl(String u);
+    Settings setUsername(String u);
   }
 
   public static final Class<Ajax> Ajax = registerPlugin(Ajax.class, new Plugin<Ajax>() {
@@ -229,10 +104,6 @@ public class Ajax extends GQuery {
    */
   public static void ajax(Settings settings) {
 
-    final RequestBuilder requestBuilder = createRequestBuilder(settings);
-
-    final String dataType = settings.getDataType();
-
     final Function onSuccess = settings.getSuccess();
 
     if (onSuccess != null) {
@@ -244,6 +115,19 @@ public class Ajax extends GQuery {
     if (onError != null) {
       onError.setElement(settings.getContext());
     }
+    
+    
+    final String dataType = settings.getDataType();
+    if ("jsonp".equalsIgnoreCase(dataType)) {
+      Method httpMethod = resolveHttpMethod(settings);
+      String data = resolveData(settings);
+      String url = resolveUrl(settings, httpMethod, data);
+      int timeout = settings.getTimeout();
+      getJSONP(url, onSuccess, onError, timeout);
+      return;
+    }
+    
+    final RequestBuilder requestBuilder = createRequestBuilder(settings);
 
     requestBuilder.setCallback(new RequestCallback() {
 
@@ -323,7 +207,6 @@ public class Ajax extends GQuery {
   }
 
   private static String resolveUrl(Settings settings, Method httpMethod, String data) {
-    
     String url = settings.getUrl();
 
     assert url != null : "no url found in settings";
@@ -331,7 +214,6 @@ public class Ajax extends GQuery {
     if (data != null && httpMethod == RequestBuilder.GET) {
       url += (url.contains("?") ? "&" : "?") + data;
     }
-
     return url;
   }
 
@@ -341,18 +223,15 @@ public class Ajax extends GQuery {
     if (data == null && settings.getData() != null) {
       data = settings.getData().toQueryString();
     }
-
     return data;
   }
 
   private static Method resolveHttpMethod(Settings settings) {
-
     String method = settings.getType();
 
     if ("get".equalsIgnoreCase(method)) {
       return RequestBuilder.GET;
     }
-
     return RequestBuilder.POST;
   }
 
@@ -380,7 +259,7 @@ public class Ajax extends GQuery {
   }
 
   public static Settings createSettings() {
-    return new Settings();
+    return createSettings($$(""));
   }
 
   public static Settings createSettings(String prop) {
@@ -412,6 +291,30 @@ public class Ajax extends GQuery {
     s.setSuccess(onSuccess);
     ajax(s);
   }
+  
+  public static void getJSONP(String url, Properties data, Function onSuccess) {
+    Settings s = createSettings();
+    s.setUrl(url);
+    s.setDataType("jsonp");
+    s.setType("get");
+    s.setData(data);
+    s.setSuccess(onSuccess);
+    ajax(s);
+  }
+  
+  public static void getJSONP(String url, Function success, Function error, int timeout) {
+    System.err.println("EEE");
+
+    if (!url.contains("=?")) {
+      url += (url.contains("?") ? "&" : "?") + "callback=?";
+    }
+    url += "&_=" + System.currentTimeMillis();
+    Element e = $("head").get(0);
+    if (e == null) {
+      e = document.getDocumentElement();
+    }
+    getJsonpImpl(e, url, null, success, error == null ? success : error, timeout);
+  }
 
   public static void post(String url, Properties data, final Function onSuccess) {
     Settings s = createSettings();
@@ -447,4 +350,42 @@ public class Ajax extends GQuery {
     ajax(s);
     return this;
   }
+  
+  private static int callBackCounter = 0;
+  
+  public static native void getJsonpImpl(Element elem, String url, String charset, Function success, Function error, int timeout) /*-{
+    var fName = "__GQ_cb_" + @com.google.gwt.query.client.plugins.ajax.Ajax::callBackCounter ++;
+    var done = false;
+    $wnd[fName] = function(data) {
+      if (!done) {
+        done = true;
+        $wnd[fName] = null;
+        success.@com.google.gwt.query.client.Function::setDataObject(Ljava/lang/Object;)(data);
+        success.@com.google.gwt.query.client.Function::f()();
+      }
+    }
+    function err() {
+      if (!done) {
+        done = true;
+        $wnd[fName] = null;
+        if (error) error.@com.google.gwt.query.client.Function::f()();
+        else       success.@com.google.gwt.query.client.Function::f()();
+      }
+    }
+    if (timeout) {
+      setTimeout(err, timeout);
+    } 
+
+    url = url.replace(/=\?/g,'=' + fName);
+    var script = document.createElement("script" );
+    script.async = "async";
+    if (charset) script.charset = charset;
+    script.src = url;
+    script.onload = script.onreadystatechange = function(evt) {
+      script.onload = script.onreadystatechange = null;
+      elem.removeChild(script);
+      err();
+    };
+    elem.insertBefore(script, elem.firstChild);
+  }-*/;  
 }
index 5d3e8d6830044b5949d764a1a301f5df6dfb6139..98a850941fb64009cf56fe6cc1746284cae6c98a 100644 (file)
@@ -24,10 +24,14 @@ import java.util.List;
 
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.dom.client.Element;
+import com.google.gwt.junit.DoNotRunWith;
+import com.google.gwt.junit.Platform;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.query.client.builders.JsonBuilder;
 import com.google.gwt.query.client.builders.Name;
 import com.google.gwt.query.client.builders.XmlBuilder;
+import com.google.gwt.query.client.plugins.ajax.Ajax;
+import com.google.gwt.query.client.plugins.ajax.Ajax.Settings;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.RootPanel;
 
@@ -81,7 +85,7 @@ public class GQueryAjaxTestGwt extends GWTTestCase {
   }
   
   public void testJsonBuilder() {
-    String json = "[{a:1, b:{a:2,b:{a:3}},u:url, d:'2','t':['hola','adios'], 'z': true}]";
+    String json = "{a:1, b:{a:2,b:{a:3}},u:url, d:'2','t':['hola','adios'], 'z': true}";
     JsonExample c = GWT.create(JsonExample.class);
     assertEquals(0, c.getA());
     c.parse(json, true);
@@ -140,4 +144,52 @@ public class GQueryAjaxTestGwt extends GWTTestCase {
     assertEquals("X", x.getA());
     assertEquals(1234, x.getNumber());
   }
+  
+  public void testJsonValidService() {
+    delayTestFinish(5000);
+    String testJsonpUrl = "http://services.digg.com/stories/top?appkey=http://mashup.com&type=javascript&callback=?";
+    Ajax.getJSONP(testJsonpUrl, new Function(){
+      public void f() {
+        Properties p = getDataProperties();
+        assertTrue(0 < p.getInt("count"));
+        finishTest();
+      }
+    }, null, 0);
+  }
+
+  @DoNotRunWith({Platform.HtmlUnitLayout})
+  public void testJsonNonCallbackResponse() {
+    delayTestFinish(5000);
+    String testJsonpUrl = "http://www.google.com";
+    Ajax.getJSONP(testJsonpUrl, null, new Function(){
+      public void f() {
+        Properties p = getDataProperties();
+        assertNull(p);
+        finishTest();
+      }
+    }, 500);
+  }
+  
+  public void testJsonTimeout() {
+    delayTestFinish(5000);
+    String nonJsonpUrl = "http://www.google.com/nopage";
+    
+    Settings s = Ajax.createSettings();
+    s.setTimeout(400);
+    s.setSuccess(new Function(){
+      public void f() {
+        fail();
+      }
+    });
+    s.setError(new Function(){
+      public void f() {
+        finishTest();
+      }
+    });
+    s.setDataType("jsonp");
+    s.setUrl(nonJsonpUrl);
+    
+    Ajax.ajax(s);
+  }
+    
 }