- 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.
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
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
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
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
}\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
}\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
private String currentSelector;\r
\r
private GQuery previousObject;\r
- \r
+\r
public GQuery() {\r
elements = JavaScriptObject.createArray().cast();\r
}\r
}\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
*/\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
}\r
\r
public GQuery submit() {\r
- return as(Events).triggerHtmlEvent("submit");\r
+ return as(Events).trigger(EventsListener.ONSUBMIT);\r
}\r
\r
/**\r
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
}\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
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;
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;
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);
/**
* 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.
*/
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.
*/
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.
*/
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.
* 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;
}
* 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) {
}
}
+ // 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);
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);
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
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);
}
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;
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>";
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() {
$("button").click();
assertEquals(1,done);
}
-
+
public void testModifyMethods() {
String pTxt = "<p>I would like to say: </p>";
String bTxt = "<b>Hello</b>";
assertEquals(1, g2.size());
assertEquals(expected, g2.toString());
}
-
+
public void testOpacity() {
$(e)
.html(
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>";
$(e).html(content);
assertHtmlEquals(expected, $("p", e).contains("test"));
}
-
+
public void testShowHide() {
$(e)
.html(
$("*", e).wrap("<b></b>");
assertHtmlEquals(expected, $(e).html());
}
-
+
}
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;
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("");
$("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() {
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) {
gq.val(gq.val() + Character.toString((char) evnt.getKeyCode()));
return false;
}
- };
+ };
$("input", e).keypress(keyEventAction);
$("input", e).keydown(keyEventAction);
$("input", e).keyup(keyEventAction);
$("input", e).keyup('c');
assertEquals("abc", $("input", e).val());
}
-
+
/**
* TODO: DblClick doesn't work with HtmlUnit, investigate and report.
*/
}
});
$("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() {
});
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);
+ }
}