]> source.dussan.org Git - gwtquery.git/commitdiff
- Added submit method to gquery, and handle submit events in the events plugins ...
authorManolo Carrasco <manolo@apache.org>
Sat, 17 Jul 2010 17:21:11 +0000 (17:21 +0000)
committerManolo Carrasco <manolo@apache.org>
Sat, 17 Jul 2010 17:21:11 +0000 (17:21 +0000)
- Use the owner document to create new dom elements in order to write in iframes.
- Many changes in gquery in order to handle correctly iframe manipulation.
- Updated lazy interfaz for GQuery.
- Added tests for iframe manipulation and submit events.

gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java
gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java
gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/EventsListener.java
gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTest.java
gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryEventsTest.java

index cab0ac3e0c201cb539273317b82454da00e5fb9b..ed146b12c8a9119ff231f22f2ee9a3466e20e752 100644 (file)
@@ -18,6 +18,8 @@ package com.google.gwt.query.client;
 import static com.google.gwt.query.client.plugins.Effects.Effects;\r
 import static com.google.gwt.query.client.plugins.Events.Events;\r
 \r
+import java.util.HashMap;\r
+\r
 import com.google.gwt.core.client.GWT;\r
 import com.google.gwt.core.client.JavaScriptObject;\r
 import com.google.gwt.core.client.JsArray;\r
@@ -40,6 +42,7 @@ import com.google.gwt.query.client.css.Percentage;
 import com.google.gwt.query.client.css.TakesLength;\r
 import com.google.gwt.query.client.css.TakesPercentage;\r
 import com.google.gwt.query.client.impl.DocumentStyleImpl;\r
+import com.google.gwt.query.client.plugins.EventsListener;\r
 import com.google.gwt.user.client.Event;\r
 import com.google.gwt.user.client.Window;\r
 \r
@@ -161,7 +164,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
       FUNC_BEFORE = 3;\r
 \r
   private static final String OLD_DATA_PREFIX = "old-";\r
-\r
+  \r
   private static JsMap<Class<? extends GQuery>, Plugin<? extends GQuery>>\r
       plugins;;\r
 \r
@@ -241,8 +244,8 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
       return $();\r
     }\r
     if (selectorOrHtml.trim().charAt(0) == '<') {\r
-      Document doc = ctx instanceof Document ? (Document)ctx : document;\r
-      return $(clean(selectorOrHtml, doc));\r
+      Document doc = ctx instanceof Document ? ctx.<Document>cast() : ctx.getOwnerDocument();\r
+      return $(cleanHtmlString(selectorOrHtml, doc));\r
     }\r
     return new GQuery(select(selectorOrHtml, ctx));\r
   }\r
@@ -308,7 +311,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   }\r
 \r
   @SuppressWarnings("unchecked")\r
-  protected static GQuery clean(String elem, Document doc) {\r
+  protected static GQuery cleanHtmlString(String elem, Document doc) {\r
     String tags = elem.trim().toLowerCase();\r
     String preWrap = "", postWrap = "";\r
     int wrapPos = 0;\r
@@ -395,7 +398,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   }\r
 \r
   private static GQuery innerHtml(String html) {\r
-    return $(clean(html, document));\r
+    return $(cleanHtmlString(html, document));\r
   }\r
 \r
   private static native String[] jsArrayToString0(JsArrayString array) /*-{\r
@@ -424,7 +427,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   private String currentSelector;\r
 \r
   private GQuery previousObject;\r
-  \r
+\r
   public GQuery() {\r
     elements = JavaScriptObject.createArray().cast();\r
   }\r
@@ -446,8 +449,8 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   }\r
 \r
   /**\r
-   * Adds the specified classes to each matched element. Add elements to the set\r
-   * of matched elements if they are not included yet.\r
+   * Add elements to the set of matched elements if they are not included yet.\r
+   * It also update the selector appending the new one. \r
    */\r
   public GQuery add(GQuery previousObject) {\r
     return pushStack(unique(merge(elements, previousObject.elements)), "add",\r
@@ -1177,6 +1180,9 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
    */\r
   public GQuery html(String html) {\r
     for (Element e : elements()) {\r
+      if (e.getNodeType() == Node.DOCUMENT_NODE) {\r
+        e = e.<Document>cast().getBody();\r
+      }\r
       e.setInnerHTML(html);\r
     }\r
     return this;\r
@@ -1968,7 +1974,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   }\r
 \r
   public GQuery submit() {\r
-    return as(Events).triggerHtmlEvent("submit");\r
+    return as(Events).trigger(EventsListener.ONSUBMIT);\r
   }\r
 \r
   /**\r
@@ -2432,13 +2438,29 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
       return bind(eventbits, data, funcs);\r
     }\r
   }\r
+  \r
+  private GQuery domManip(String htmlString, int func) {\r
+    GQuery ret = $();\r
+    HashMap<Document, GQuery> cache = new HashMap<Document, GQuery>();\r
+    for (Element e: elements()) {\r
+      Document d = e.getNodeType() == Node.DOCUMENT_NODE ? e.<Document>cast() : e.getOwnerDocument();\r
+      GQuery g = cache.get(d);\r
+      if (g == null) {\r
+        g = cleanHtmlString(htmlString, d);\r
+        cache.put(d, g);\r
+      }\r
+      ret.add(domManip(g, func));\r
+    }\r
+    return ret;\r
+  }\r
 \r
   private GQuery domManip(GQuery g, int func) {\r
     JSArray newNodes = JSArray.create();\r
     for (int i = 0; i < elements().length; i++) {\r
       Element e = elements()[i];\r
-      if (document.equals(e)) {\r
-        e = body;\r
+      e.getOwnerDocument();\r
+      if (e.getNodeType() == Node.DOCUMENT_NODE) { \r
+        e = e.<Document>cast().getBody();\r
       }\r
       for (int j = 0; j < g.size(); j++) {\r
         Node n = g.get(j);\r
@@ -2468,13 +2490,15 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> {
   }\r
 \r
   private GQuery domManip(String html, Document doc, int func) {\r
-    return domManip(clean(html, doc), func);\r
+    return domManip(html, func);\r
   }\r
 \r
   private native Document getContentDocument(Node n) /*-{\r
-    return n.contentDocument || n.contentWindow.document;\r
+    var d =  n.contentDocument || n.contentWindow.document;\r
+    if (!d.body) d.write("<body/>");\r
+    return d;\r
   }-*/;\r
-\r
+  \r
   private native Element getPreviousSiblingElement(Element elem)  /*-{\r
     var sib = elem.previousSibling;\r
     while (sib && sib.nodeType != 1)\r
index 8800c8f372d3ddda795276a5d4a41c0f21da6252..8eaf32891a1afe5c5fa7f7c0acce01f0e1e8b086 100644 (file)
@@ -16,6 +16,7 @@
 package com.google.gwt.query.client;
 import static com.google.gwt.query.client.plugins.Effects.Effects;
 import static com.google.gwt.query.client.plugins.Events.Events;
+import java.util.HashMap;
 import com.google.gwt.core.client.GWT;
 import com.google.gwt.core.client.JavaScriptObject;
 import com.google.gwt.core.client.JsArray;
@@ -38,6 +39,7 @@ import com.google.gwt.query.client.css.Percentage;
 import com.google.gwt.query.client.css.TakesLength;
 import com.google.gwt.query.client.css.TakesPercentage;
 import com.google.gwt.query.client.impl.DocumentStyleImpl;
+import com.google.gwt.query.client.plugins.EventsListener;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.Window;
 import com.google.gwt.query.client.LazyBase;
@@ -45,8 +47,7 @@ import com.google.gwt.query.client.LazyBase;
 public interface LazyGQuery<T> extends LazyBase<T>{
 
   /**
-   * Adds the specified classes to each matched element. Add elements to the set
-   * of matched elements if they are not included yet.
+   * Add elements to the set of matched elements if they are not included yet.
    */
   LazyGQuery<T> add(GQuery previousObject);
 
@@ -326,7 +327,7 @@ public interface LazyGQuery<T> extends LazyBase<T>{
   /**
    * Stores the value in the named spot with desired return type.
    */
-  Object data(String name, Object value);
+  LazyGQuery<T> data(String name, Object value);
 
   /**
    * Bind a set of functions to the dblclick event of each matched element.
@@ -591,6 +592,11 @@ public interface LazyGQuery<T> extends LazyBase<T>{
    */
   LazyGQuery<T> keyup(int key);
 
+  /**
+   * Returns the computed left position of the first element matched.
+   */
+  int left();
+
   /**
    * Returns the number of elements currently matched. The size function will
    * return the same value.
@@ -1000,6 +1006,11 @@ public interface LazyGQuery<T> extends LazyBase<T>{
    */
   LazyGQuery<T> toggleClass(String clz, boolean addOrRemove);
 
+  /**
+   * Returns the computed left position of the first element matched.
+   */
+  int top();
+
   /**
    * Produces a string representation of the matched elements.
    */
index 67b8a083bbe716c65a849724357fa72265568ec1..ec1c1d41987f251a3e17c87270e6785a6cf20a8b 100644 (file)
@@ -133,8 +133,11 @@ public class Events extends GQuery {
       dispatchEvent(document.createErrorEvent());
     if ((eventbits | Event.ONMOUSEWHEEL) == Event.ONMOUSEWHEEL)
       dispatchEvent(document.createMouseEvent("mousewheel", true, true, 0, 0, 0, 0, 0, false, false, false, false, NativeEvent.BUTTON_LEFT, null));
+    if (eventbits == EventsListener.ONSUBMIT)
+      triggerHtmlEvent("submit");
     return this;
   }
+  
 
   /**
    * Trigger a html event in all matched elements.
@@ -143,7 +146,7 @@ public class Events extends GQuery {
    *    An string representing the html event desired 
    */
   public Events triggerHtmlEvent(String htmlEvent) {
-    dispatchEvent(document.createHtmlEvent(htmlEvent, false, false));
+    dispatchEvent(document.createHtmlEvent(htmlEvent, true, true));
     return this;
   }
   
index 94beabb17a8197679e97020ac37770fbfb314d11..9155b41a799209b90032eb31dde3f8a75b6e712d 100644 (file)
@@ -33,16 +33,13 @@ import com.google.gwt.user.client.EventListener;
  * The class takes care of calling the appropriate functions for each browser
  * event and it also calls sinkEvents method.
  */
-class EventsListener implements EventListener {
+public class EventsListener implements EventListener {
 
   private static class BindFunction {
 
     Object data;
-
     Function function;
-
     int times = -1;
-
     int type;
 
     BindFunction(int t, Function f, Object d) {
@@ -69,6 +66,9 @@ class EventsListener implements EventListener {
     }
   }
 
+  // Gwt Events class has not this event defined
+  public static int ONSUBMIT = 0x08000;
+
   public static EventsListener getInstance(Element e) {
     EventsListener ret = getGQueryEventLinstener(e);
     return ret != null ? ret : new EventsListener(e);
@@ -81,22 +81,38 @@ class EventsListener implements EventListener {
   private static native EventListener getOriginalEventListener(Element elem) /*-{
     return elem.__listener;
   }-*/;
-
-  private static native void setFocusable(Element elem) /*-{
-    elem.tabIndex = 0;
-  }-*/;
-
+  
   private static native void setGQueryEventListener(Element elem,
       EventsListener gqevent) /*-{
     elem.__gqueryevent = gqevent;
   }-*/;
 
+  // Gwt does't handle submit events in DOM.sinkEvents
+  private static native void sinkSubmitEvent(Element elem) /*-{
+    if (elem.__gquerysubmit) return;
+    elem.__gquerysubmit = true;
+    
+    var handle = function(event) {
+      elem.__gqueryevent.@com.google.gwt.query.client.plugins.EventsListener::dispatchEvent(Lcom/google/gwt/user/client/Event;)(event);
+    };
+    
+    if (elem.addEventListener)
+      elem.addEventListener("submit", handle, true);
+    else
+      elem.attachEvent("onsubmit", handle);
+  }-*/;
+
+  double lastEvnt=0;
+  int lastType=0;
+  
+
   private Element element;
 
-  private JsObjectArray<EventsListener.BindFunction> elementEvents = JsObjectArray
+  private JsObjectArray<BindFunction> elementEvents = JsObjectArray
       .createArray().cast();
-  private EventListener originalEventListener;
 
+  private EventListener originalEventListener;
+  
   private EventsListener(Element element) {
     this.element = element;
     originalEventListener = getOriginalEventListener(element);
@@ -114,21 +130,35 @@ class EventsListener implements EventListener {
       int times) {
     if (function == null) {
       unbind(eventbits);
+      return;
+    }
+    
+    if (eventbits == ONSUBMIT) {
+      sinkSubmitEvent(element);
     } else {
+      if ((eventbits | Event.FOCUSEVENTS) == Event.FOCUSEVENTS) {
+        element.setAttribute("tabIndex", "0");
+      }
       DOM.sinkEvents((com.google.gwt.user.client.Element) element, eventbits
           | DOM.getEventsSunk((com.google.gwt.user.client.Element) element));
-
-      if ((eventbits | Event.FOCUSEVENTS) == Event.FOCUSEVENTS) {
-        setFocusable(element);
+      
+    }
+    elementEvents.add(new BindFunction(eventbits, function, data, times));
+  }
+  
+  public void dispatchEvent(Event event) {
+    int etype = "submit".equalsIgnoreCase(event.getType()) ? ONSUBMIT
+        : DOM.eventGetType(event);
+    for (int i = 0; i < elementEvents.length(); i++) {
+      BindFunction listener = elementEvents.get(i);
+      if (listener.hasEventType(etype)) {
+        if (!listener.fire(event)) {
+          event.stopPropagation();
+          event.preventDefault();
+        }
       }
-
-      elementEvents.add(new EventsListener.BindFunction(eventbits, function,
-          data, times));
     }
   }
-
-  double lastEvnt=0;
-  int lastType=0;
   
   public void onBrowserEvent(Event event) {
     // Workaround for Issue_20
@@ -140,27 +170,19 @@ class EventsListener implements EventListener {
     lastEvnt = Duration.currentTimeMillis();
     lastType = event.getTypeInt();
 
+    // Execute the original Gwt listener
     if (originalEventListener != null) {
       originalEventListener.onBrowserEvent(event);
     }
-
-    int etype = DOM.eventGetType(event);
-    for (int i = 0; i < elementEvents.length(); i++) {
-      EventsListener.BindFunction listener = elementEvents.get(i);
-      if (listener.hasEventType(etype)) {
-        if (!listener.fire(event)) {
-          event.stopPropagation();
-          event.preventDefault();
-        }
-      }
-    }
+    
+    dispatchEvent(event);
   }
-
+  
   public void unbind(int eventbits) {
-    JsObjectArray<EventsListener.BindFunction> newList = JsObjectArray
+    JsObjectArray<BindFunction> newList = JsObjectArray
         .createArray().cast();
     for (int i = 0; i < elementEvents.length(); i++) {
-      EventsListener.BindFunction listener = elementEvents.get(i);
+      BindFunction listener = elementEvents.get(i);
       if (!listener.hasEventType(eventbits)) {
         newList.add(listener);
       }
index 78dc7e0e5c1a316f7aa8df42a3d013d45422be49..8ebc67def9bbfbf612815caa242a15db8f58c5d6 100644 (file)
@@ -19,6 +19,7 @@ import static com.google.gwt.query.client.GQuery.$;
 import static com.google.gwt.query.client.GQuery.$$;
 import static com.google.gwt.query.client.GQuery.document;
 
+import com.google.gwt.dom.client.Document;
 import com.google.gwt.dom.client.Element;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.query.client.impl.SelectorEngineImpl;
@@ -190,6 +191,19 @@ public class GQueryCoreTest extends GWTTestCase {
     assertHtmlEquals("<p>0</p><p>1</p><p>2</p>", $("p", e));
   }
 
+  public void testIFrameManipulation() {
+    $(e).html("<iframe name='miframe' id='miframe' src=\"javascript:''\">");
+    Document d = $("#miframe").contents().get(0).cast();
+    assertNotNull(d);
+    assertNotNull(d.getBody());
+    assertEquals(1, $("#miframe").contents().size());
+    assertEquals(1, $("#miframe").contents().find("body").size());
+    assertEquals(0, $("#miframe").contents().find("body > h1").size());
+    $("#miframe").contents().find("body").append("<h1>Test</h1>");
+    assertEquals(1, $("#miframe").contents().find("body > h1").size());
+    assertEquals(1, $(d).find("h1").size());
+  }
+
   public void testInnerMethods() {
     String txt = "<p>I would like to say: </p>";
 
@@ -276,7 +290,7 @@ public class GQueryCoreTest extends GWTTestCase {
     gq.val("v1");
     assertEquals("v1", gq.val());
   }
-
+  
   public void testIssue23() {
     $(e).html("<table><tr><td><input type='radio' name='n' value='v1'>1</input><input type='radio' name='n' value='v2' checked='checked'>2</input></td><td><button>Click</button></tr><td></table>");
     $("button").click(new Function() {
@@ -293,7 +307,7 @@ public class GQueryCoreTest extends GWTTestCase {
     $("button").click();
     assertEquals(1,done);
   }
-  
+
   public void testModifyMethods() {
     String pTxt = "<p>I would like to say: </p>";
     String bTxt = "<b>Hello</b>";
@@ -421,7 +435,7 @@ public class GQueryCoreTest extends GWTTestCase {
     assertEquals(1, g2.size());
     assertEquals(expected, g2.toString());    
   }
-
+  
   public void testOpacity() {
     $(e)
     .html(
@@ -446,7 +460,7 @@ public class GQueryCoreTest extends GWTTestCase {
     assertEquals(1, p.keys().length);
     assertNotNull(p.get("border"));
   }
-  
+
   public void testRelativeMethods() {
     String content = "<p><span>Hello</span>, how are you?</p>";
     String expected = "<span>Hello</span>";
@@ -589,7 +603,7 @@ public class GQueryCoreTest extends GWTTestCase {
     $(e).html(content);
     assertHtmlEquals(expected, $("p", e).contains("test"));
   }
-
+  
   public void testShowHide() {
     $(e)
     .html(
@@ -725,5 +739,5 @@ public class GQueryCoreTest extends GWTTestCase {
     $("*", e).wrap("<b></b>");
     assertHtmlEquals(expected, $(e).html());
   }
-  
+
 }
index d65b8125d6a55c3c512907c2b0da4cd196cd99df..6fa9e47729199ec45353e6b68f89d2925a9aec1a 100644 (file)
@@ -26,7 +26,9 @@ import com.google.gwt.junit.Platform;
 import com.google.gwt.junit.client.GWTTestCase;
 import com.google.gwt.query.client.css.CSS;
 import com.google.gwt.query.client.plugins.Events;
+import com.google.gwt.query.client.plugins.EventsListener;
 import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Timer;
 import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.RootPanel;
@@ -43,14 +45,14 @@ public class GQueryEventsTest extends GWTTestCase {
   public String getModuleName() {
     return "com.google.gwt.query.Query";
   }
-  
+
   public void gwtSetUp() {
     if (e == null) {
       testPanel = new HTML();
       RootPanel.get().add(testPanel);
       e = testPanel.getElement();
       e.setId("evnt-tst");
-      
+
       CSS.init();
     } else {
       e.setInnerHTML("");
@@ -79,7 +81,7 @@ public class GQueryEventsTest extends GWTTestCase {
     $("p", e).unbind(Event.ONCLICK);
     $("p", e).click();
     assertEquals("white", $("p", e).css("color"));
-    
+
     // toggle
     $("p", e).unbind(Event.ONCLICK);
     $("p", e).toggle(new Function() {
@@ -134,7 +136,7 @@ public class GQueryEventsTest extends GWTTestCase {
     assertEquals("black", $("p", e).css("border-top-color"));
     assertEquals("dotted", $("p", e).css("border-top-style"));
     assertEquals("1px", $("p", e).css("border-top-width"));
-    
+
     // blur
     $("p", e).blur(new Function() {
       public void f(Element elem) {
@@ -152,7 +154,7 @@ public class GQueryEventsTest extends GWTTestCase {
         gq.val(gq.val() + Character.toString((char) evnt.getKeyCode()));
         return false;
       }
-    }; 
+    };
     $("input", e).keypress(keyEventAction);
     $("input", e).keydown(keyEventAction);
     $("input", e).keyup(keyEventAction);
@@ -162,7 +164,7 @@ public class GQueryEventsTest extends GWTTestCase {
     $("input", e).keyup('c');
     assertEquals("abc", $("input", e).val());
   }
-  
+
   /**
    * TODO: DblClick doesn't work with HtmlUnit, investigate and report.
    */
@@ -176,22 +178,22 @@ public class GQueryEventsTest extends GWTTestCase {
       }
     });
     $("p", e).dblclick();
-    assertEquals("yellow", $("p", e).css("color"));    
+    assertEquals("yellow", $("p", e).css("color"));
   }
 
   public void testLazyMethods() {
     $(e).css("color", "white");
     assertEquals("white", $(e).css("color"));
-    
+
     $(e).one(Event.ONCLICK, null, lazy().css("color", "red").done());
     $(e).click();
     assertEquals("red", $(e).css("color"));
-    
+
     $(e).click(lazy().css(CSS.COLOR, CSS.BLACK).done());
     $(e).click();
-    assertEquals("black", $(e).css("color"));    
+    assertEquals("black", $(e).css("color"));
   }
-  
+
   public void testWidgetEvents() {
     final Button b = new Button("click-me");
     b.addClickHandler(new ClickHandler() {
@@ -201,10 +203,46 @@ public class GQueryEventsTest extends GWTTestCase {
     });
     RootPanel.get().add(b);
     $("button").click(lazy().css("color", "red").done());
-    
+
     $("button").click();
-    assertEquals("red", $("button").css("color"));    
-    assertEquals("black", $("button").css("background-color"));    
+    assertEquals("red", $("button").css("color"));
+    assertEquals("black", $("button").css("background-color"));
     RootPanel.get().remove(b);
   }
+
+  int testSubmitEventCont = 0;
+
+  public void testSubmitEvent() {
+    // Add a form and an iframe to the dom. The form target is the iframe
+    $(e).html("<form action='whatever' target='miframe'><input type='text' value='Hello'><input type='submit' value='Go'></form><iframe name='miframe' id='miframe' src=\"javascript:''\">");
+    testSubmitEventCont = 0;
+
+    // Add an onsubmit function to the form returning false to cancel the action
+    $("form").bind(EventsListener.ONSUBMIT, null, new Function() {
+      public boolean f(Event e) {
+        testSubmitEventCont++;
+        return false;
+      }
+    });
+
+    // Check that the onsubmit function is called and the iframe has not changed
+    $("form").submit();
+    assertEquals(1, testSubmitEventCont);
+    assertFalse($("#miframe").contents().find("body").text().contains("ERROR"));
+
+    // Remove the binding
+    $("form").unbind(EventsListener.ONSUBMIT);
+
+    // Check that on submit function is not called and the form has been
+    // submitted
+    $("form").submit();
+    assertEquals(1, testSubmitEventCont);
+    new Timer() {
+      public void run() {
+        // Check that the server returns an error since the action does not
+        // exist
+        assertTrue($("#miframe").contents().find("body").text().contains("ERROR"));
+      }
+    }.schedule(500);
+  }
 }