From: Ray Cromwell Date: Wed, 29 Apr 2009 23:40:20 +0000 (+0000) Subject: More implementations and docs X-Git-Tag: release-1.3.2~791 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=94e9626e350487ade2617ebf0706897d77df1b17;p=gwtquery.git More implementations and docs --- diff --git a/gwtquery-core/src/main/java/gwtquery/client/Effects.java b/gwtquery-core/src/main/java/gwtquery/client/Effects.java index d7c42b9d..21fabb86 100644 --- a/gwtquery-core/src/main/java/gwtquery/client/Effects.java +++ b/gwtquery-core/src/main/java/gwtquery/client/Effects.java @@ -24,6 +24,75 @@ public class Effects extends GQuery { super(list); } + /** + * function( prop, speed, easing, callback ) { + var optall = jQuery.speed(speed, easing, callback); + + return this[ optall.queue === false ? "each" : "queue" ](function(){ + + var opt = jQuery.extend({}, optall), p, + hidden = this.nodeType == 1 && jQuery(this).is(":hidden"), + self = this; + + for ( p in prop ) { + if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden ) + return opt.complete.call(this); + + if ( ( p == "height" || p == "width" ) && this.style ) { + // Store display property + opt.display = jQuery.css(this, "display"); + + // Make sure that nothing sneaks out + opt.overflow = this.style.overflow; + } + } + + if ( opt.overflow != null ) + this.style.overflow = "hidden"; + + opt.curAnim = jQuery.extend({}, prop); + + jQuery.each( prop, function(name, val){ + var e = new jQuery.fx( self, opt, name ); + + if ( /toggle|show|hide/.test(val) ) + e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop ); + else { + var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/), + start = e.cur(true) || 0; + + if ( parts ) { + var end = parseFloat(parts[2]), + unit = parts[3] || "px"; + + // We need to compute starting value + if ( unit != "px" ) { + self.style[ name ] = (end || 1) + unit; + start = ((end || 1) / e.cur(true)) * start; + self.style[ name ] = start + unit; + } + + // If a +=/-= token was provided, we're doing a relative animation + if ( parts[1] ) + end = ((parts[1] == "-=" ? -1 : 1) * end) + start; + + e.custom( start, end, unit ); + } else + e.custom( start, val, "" ); + } + }); + + // For JS strict compliance + return true; + }); + }, + * @return + */ + public Effects animate(Properties props, String speed, String easing, + Function callback) { + return this; + } + public Effects fadeOut() { Animation a = new Animation() { diff --git a/gwtquery-core/src/main/java/gwtquery/client/GQuery.java b/gwtquery-core/src/main/java/gwtquery/client/GQuery.java index e5598598..3354bba8 100644 --- a/gwtquery-core/src/main/java/gwtquery/client/GQuery.java +++ b/gwtquery-core/src/main/java/gwtquery/client/GQuery.java @@ -2,9 +2,11 @@ package gwtquery.client; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JavaScriptObject; +import com.google.gwt.dom.client.BodyElement; import com.google.gwt.dom.client.ButtonElement; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.IFrameElement; import com.google.gwt.dom.client.InputElement; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Node; @@ -16,6 +18,7 @@ import com.google.gwt.dom.client.TextAreaElement; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.EventListener; +import com.google.gwt.user.client.Window; import java.util.HashMap; import java.util.Map; @@ -169,6 +172,8 @@ public class GQuery { }-*/; } + public static boolean fxOff = false; + private static Map, Plugin> plugins; private static Element windowData = null; @@ -177,6 +182,9 @@ public class GQuery { private static DocumentStyleImpl styleImpl; + private static final int FUNC_PREPEND = 0, FUNC_APPEND = 1, FUNC_AFTER = 2, + FUNC_BEFORE = 3; + /** * This function accepts a string containing a CSS selector which is then used * to match a set of elements, or it accepts raw HTML creating a GQuery @@ -338,6 +346,23 @@ public class GQuery { } } + private static String curCSS(Element elem, String name) { + Style s = elem.getStyle(); + ensureStyleImpl(); + name = styleImpl.getPropertyName(name); + + if (SelectorEngine.truth(s.getProperty(name))) { + return s.getProperty(name); + } + return styleImpl.getCurrentStyle(elem, name); + } + + private static void ensureStyleImpl() { + if (styleImpl != null) { + styleImpl = GWT.create(DocumentStyleImpl.class); + } + } + private static boolean hasClass(Element e, String clz) { return e.getClassName().matches("\\s" + clz + "\\s"); } @@ -378,6 +403,10 @@ public class GQuery { elements = JSArray.create(element); } + public GQuery add(String selector) { + return add($(selector)); + } + /** * Adds the specified classes to each matched element. */ @@ -390,6 +419,69 @@ public class GQuery { return this; } + /** + * Insert content after each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element after + * another if it's not in the page). + */ + public GQuery after(Node n) { + return domManip(JSArray.create(n), FUNC_AFTER); + } + + /** + * Insert content after each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element after + * another if it's not in the page). + */ + public GQuery after(String html) { + return domManip(html, FUNC_AFTER); + } + + /** + * Insert content after each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element after + * another if it's not in the page). + */ + public GQuery after(GQuery query) { + return domManip(query.elements, FUNC_AFTER); + } + + /** + * Add the previous selection to the current selection. Useful for traversing + * elements, and then adding something that was matched before the last + * traversal. + */ + public GQuery andSelf() { + return add(previousObject); + } + + /** + * Append content to the inside of every matched element. This operation is + * similar to doing an appendChild to all the specified elements, adding them + * into the document. + */ + public GQuery append(String html) { + return domManip(html, FUNC_APPEND); + } + + /** + * Append content to the inside of every matched element. This operation is + * similar to doing an appendChild to all the specified elements, adding them + * into the document. + */ + public GQuery append(Node n) { + return domManip(JSArray.create(n), FUNC_APPEND); + } + + /** + * Append content to the inside of every matched element. This operation is + * similar to doing an appendChild to all the specified elements, adding them + * into the document. + */ + public GQuery append(GQuery query) { + return domManip(query.elements, FUNC_APPEND); + } + /** * Convert to Plugin interface provided by Class literal. */ @@ -443,6 +535,33 @@ public class GQuery { return this; } + /** + * Insert content before each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element before + * another if it's not in the page). + */ + public GQuery before(Node n) { + return domManip(JSArray.create(n), FUNC_AFTER); + } + + /** + * Insert content before each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element before + * another if it's not in the page). + */ + public GQuery before(GQuery query) { + return domManip(query.elements, FUNC_AFTER); + } + + /** + * Insert content before each of the matched elements. The elements must + * already be inserted into the document (you can't insert an element before + * another if it's not in the page). + */ + public GQuery before(String html) { + return domManip(html, FUNC_AFTER); + } + /** * Binds a handler to one or more events (like click) for each matched * element. @@ -506,11 +625,43 @@ public class GQuery { return bind(Event.ONCLICK, null, f); } + /** + * Clone matched DOM Elements and select the clones. This is useful for moving + * copies of the elements to another location in the DOM. + */ + public GQuery clone() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + result.addNode(e.cloneNode(true)); + } + return new GQuery(result); + } + + /** + * Find all the child nodes inside the matched elements (including text + * nodes), or the content document, if the element is an iframe. + */ + public GQuery contents() { + JSArray result = JSArray.create(); + for (Element e : elements()) { + NodeList children = e.getChildNodes(); + for (int i = 0; i < children.getLength(); i++) { + Node n = children.getItem(i); + if (IFrameElement.is(n)) { + result.addNode(getContentDocument(n)); + } else { + result.addNode(n); + } + } + } + return new GQuery(unique(result)); + } + /** * Return a style property on the first matched element. */ public String css(String name) { - return elements.getItem(0).getStyle().getProperty(name); + return curCSS(get(0), name); } /** @@ -615,6 +766,21 @@ public class GQuery { return asArray(elements); } + /** + * Remove all child nodes from the set of matched elements. + */ + public GQuery empty() { + //TODO: add memory leak cleanup, remove event handlers, and + // data caches + for (Element e : elements()) { + while (e.getFirstChild() != null) { + e.removeChild(e.getFirstChild()); + } + } + + return this; + } + /** * Revert the most recent 'destructive' operation, changing the set of matched * elements to its previous state (right before the destructive operation). @@ -740,6 +906,69 @@ public class GQuery { return -1; } + /** + * Insert all of the matched elements after another, specified, set of + * elements. + */ + public GQuery insertAfter(String selector) { + return insertAfter($(selector)); + } + + /** + * Insert all of the matched elements after another, specified, set of + * elements. + */ + public GQuery insertAfter(Element elem) { + return insertAfter($(elem)); + } + + /** + * Insert all of the matched elements after another, specified, set of + * elements. + */ + public GQuery insertAfter(GQuery query) { + for (Element e : elements()) { + query.after(e); + } + return this; + } + + /** + * Insert all of the matched elements before another, specified, set of + * elements. + * + * The elements must already be inserted into the document (you can't insert + * an element after another if it's not in the page). + */ + public GQuery insertBefore(Element item) { + return insertBefore($(item)); + } + + /** + * Insert all of the matched elements before another, specified, set of + * elements. + * + * The elements must already be inserted into the document (you can't insert + * an element after another if it's not in the page). + */ + public GQuery insertBefore(GQuery query) { + for (Element e : elements()) { + query.before(e); + } + return this; + } + + /** + * Insert all of the matched elements before another, specified, set of + * elements. + * + * The elements must already be inserted into the document (you can't insert + * an element after another if it's not in the page). + */ + public GQuery insertBefore(String selector) { + return insertBefore($(selector)); + } + public GQuery keydown() { return trigger( Document.get().createKeyDownEvent(false, false, false, false, 0, 0), @@ -826,7 +1055,7 @@ public class GQuery { } /** - * Returns a jQuery collection with the positioned parent of the first matched + * Returns a GQuery collection with the positioned parent of the first matched * element. This is the first parent of the element that has position (as in * relative or absolute). This method only works with visible elements. */ @@ -869,6 +1098,58 @@ public class GQuery { return new GQuery(unique(result)); } + /** + * Gets the top and left position of an element relative to its offset parent. + * The returned object contains two Integer properties, top and left. For + * accurate calculations make sure to use pixel values for margins, borders + * and padding. This method only works with visible elements. + */ + public Offset position() { + + if (size() > 0) { + GQuery offsetParent = offsetParent(); + Offset offset = offset(); + Element e = offsetParent.get(0); + + Offset parentOffset = BodyElement.is(e) || "html".equals(e.getTagName()) + ? new Offset(0, 0) : offsetParent.offset(); + offset.top -= num(this, "marginTop"); + offset.left -= num(this, "marginLeft"); + parentOffset.top += num(offsetParent, "borderTopWidth"); + parentOffset.left += num(offsetParent, "borderLeftWidth"); + return new Offset(offset.top - parentOffset.top, + offset.left - parentOffset.left); + } + return null; + } + + /** + * Prepend content to the inside of every matched element. This operation is + * the best way to insert elements inside, at the beginning, of all matched + * elements. + */ + public GQuery prepend(String html) { + return domManip(html, FUNC_PREPEND); + } + + /** + * Prepend content to the inside of every matched element. This operation is + * the best way to insert elements inside, at the beginning, of all matched + * elements. + */ + public GQuery prepend(GQuery query) { + return domManip(query.elements, FUNC_PREPEND); + } + + /** + * Prepend content to the inside of every matched element. This operation is + * the best way to insert elements inside, at the beginning, of all matched + * elements. + */ + public GQuery prepend(Node n) { + return domManip(JSArray.create(n), FUNC_PREPEND); + } + /** * Get a set of elements containing the unique previous siblings of each of * the matched set of elements. Only the immediately previous sibling is @@ -940,6 +1221,20 @@ public class GQuery { return queue("__FX", data); } + /** + * Removes all matched elements from the DOM. + */ + public GQuery remove() { + for (Element e : elements()) { + //TODO: cleanup event bindings + removeData(e, null); + if (e.getParentNode() != null) { + e.getParentNode().removeChild(e); + } + } + return this; + } + /** * Remove the named attribute from every element in the matched set. */ @@ -972,15 +1267,134 @@ public class GQuery { return this; } + /** + * Replaces the elements matched by the specified selector with the matched + * elements. This function is the complement to replaceWith() which does the + * same task with the parameters reversed. + */ + public GQuery replaceAll(GQuery query) { + for (Element e : elements()) { + $(e).replaceWith(query); + } + return this; + } + + /** + * Replaces the elements matched by the specified selector with the matched + * elements. This function is the complement to replaceWith() which does the + * same task with the parameters reversed. + */ + public GQuery replaceAll(String html) { + return replaceAll($(html)); + } + + /** + * Replaces the elements matched by the specified selector with the matched + * elements. This function is the complement to replaceWith() which does the + * same task with the parameters reversed. + */ + public GQuery replaceAll(Element elem) { + return replaceAll($(elem)); + } + + /** + * Replaces all matched elements with the specified HTML or DOM elements. This + * returns the GQuery element that was just replaced, which has been removed + * from the DOM. + */ + public GQuery replaceWith(GQuery query) { + return after(query).remove(); + } + + /** + * Replaces all matched elements with the specified HTML or DOM elements. This + * returns the GQuery element that was just replaced, which has been removed + * from the DOM. + */ + public GQuery replaceWith(String html) { + return replaceWith($(html)); + } + + /** + * Replaces all matched elements with the specified HTML or DOM elements. This + * returns the GQuery element that was just replaced, which has been removed + * from the DOM. + */ + public GQuery replaceWith(Element elem) { + return replaceWith($(elem)); + } + public GQuery scroll(Function f) { return bind(Event.ONSCROLL, null, f); } + /** + * When a value is passed in, the scroll left offset is set to that value on + * all matched elements. This method works for both visible and hidden + * elements. + */ + public GQuery scrollLeft(int left) { + for (Element e : elements()) { + if (e == window() || e == (Node) Document.get()) { + Window.scrollTo(left, $(e).scrollTop()); + } else { + e.setPropertyInt("scrollLeft", left); + } + } + return this; + } + + /** + * Gets the scroll left offset of the first matched element. This method works + * for both visible and hidden elements. + */ + public int scrollLeft() { + Element e = get(0); + if (e == window()) { + return Window.getScrollLeft(); + } else if (e == (Node) Document.get()) { + return Document.get().getScrollLeft(); + } else { + return e.getScrollLeft(); + } + } + + /** + * When a value is passed in, the scroll top offset is set to that value on + * all matched elements. This method works for both visible and hidden + * elements. + */ + public GQuery scrollTop(int top) { + for (Element e : elements()) { + if (e == window() || e == (Node) Document.get()) { + Window.scrollTo($(e).scrollLeft(), top); + } else { + e.setPropertyInt("scrollTop", top); + } + } + return this; + } + + /** + * Gets the scroll top offset of the first matched element. This method works + * for both visible and hidden elements. + */ + public int scrollTop() { + Element e = get(0); + if (e == window()) { + return Window.getScrollTop(); + } else if (e == (Node) Document.get()) { + return Document.get().getScrollTop(); + } else { + return e.getScrollTop(); + } + } + public GQuery select() { return trigger(Document.get().createHtmlEvent("select", false, false), null); } - + public void setPreviousObject(GQuery previousObject) { this.previousObject = previousObject; } @@ -1168,6 +1582,149 @@ public class GQuery { return this; } + /** + * Wrap each matched element with the specified HTML content. This wrapping + * process is most useful for injecting additional structure into a document, + * without ruining the original semantic qualities of a document. This works + * by going through the first element provided (which is generated, on the + * fly, from the provided HTML) and finds the deepest descendant element + * within its structure -- it is that element that will enwrap everything + * else. + */ + public GQuery wrap(GQuery query) { + for (Element e : elements()) { + $(e).wrapAll(query); + } + return this; + } + + /** + * Wrap each matched element with the specified HTML content. This wrapping + * process is most useful for injecting additional structure into a document, + * without ruining the original semantic qualities of a document. This works + * by going through the first element provided (which is generated, on the + * fly, from the provided HTML) and finds the deepest descendant element + * within its structure -- it is that element that will enwrap everything + * else. + */ + public GQuery wrap(Element elem) { + return wrap($(elem)); + } + + /** + * Wrap each matched element with the specified HTML content. This wrapping + * process is most useful for injecting additional structure into a document, + * without ruining the original semantic qualities of a document. This works + * by going through the first element provided (which is generated, on the + * fly, from the provided HTML) and finds the deepest descendant element + * within its structure -- it is that element that will enwrap everything + * else. + */ + public GQuery wrap(String html) { + return wrap($(html)); + } + + /** + * Wrap all the elements in the matched set into a single wrapper element. + * This is different from .wrap() where each element in the matched set would + * get wrapped with an element. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. + * + * This works by going through the first element provided (which is generated, + * on the fly, from the provided HTML) and finds the deepest descendant + * element within its structure -- it is that element that will enwrap + * everything else. + */ + public GQuery wrapAll(String html) { + return wrapAll($(html)); + } + + /** + * Wrap all the elements in the matched set into a single wrapper element. + * This is different from .wrap() where each element in the matched set would + * get wrapped with an element. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. + * + * This works by going through the first element provided (which is generated, + * on the fly, from the provided HTML) and finds the deepest descendant + * element within its structure -- it is that element that will enwrap + * everything else. + */ + public GQuery wrapAll(Element elem) { + return wrapAll($(elem)); + } + + /** + * Wrap all the elements in the matched set into a single wrapper element. + * This is different from .wrap() where each element in the matched set would + * get wrapped with an element. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. + * + * This works by going through the first element provided (which is generated, + * on the fly, from the provided HTML) and finds the deepest descendant + * element within its structure -- it is that element that will enwrap + * everything else. + */ + public GQuery wrapAll(GQuery query) { + GQuery wrap = query.clone(); + if (elements.getItem(0).getParentNode() != null) { + wrap.insertBefore(elements.getItem(0)); + } + for (Element e : wrap.elements()) { + Node n = e; + while (n.getFirstChild() != null) { + n = n.getFirstChild(); + $((Element) n).append(this); + } + } + return this; + } + + /** + * Wrap the inner child contents of each matched element (including text + * nodes) with an HTML structure. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. This works by going through the + * first element provided (which is generated, on the fly, from the provided + * HTML) and finds the deepest ancestor element within its structure -- it is + * that element that will enwrap everything else. + */ + public GQuery wrapInner(GQuery query) { + for (Element e : elements()) { + $(e).contents().wrapAll(query); + } + return this; + } + + /** + * Wrap the inner child contents of each matched element (including text + * nodes) with an HTML structure. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. This works by going through the + * first element provided (which is generated, on the fly, from the provided + * HTML) and finds the deepest ancestor element within its structure -- it is + * that element that will enwrap everything else. + */ + public GQuery wrapInner(String html) { + return wrapInner($(html)); + } + + /** + * Wrap the inner child contents of each matched element (including text + * nodes) with an HTML structure. This wrapping process is most useful for + * injecting additional structure into a document, without ruining the + * original semantic qualities of a document. This works by going through the + * first element provided (which is generated, on the fly, from the provided + * HTML) and finds the deepest ancestor element within its structure -- it is + * that element that will enwrap everything else. + */ + public GQuery wrapInner(Element elem) { + return wrapInner($(elem)); + } + protected GQuery pushStack(JSArray elts, String name, String selector) { GQuery g = new GQuery(elts); g.setPreviousObject(this); @@ -1175,6 +1732,11 @@ public class GQuery { return g; } + private GQuery add(GQuery previousObject) { + return pushStack(unique(merge(elements, previousObject.elements)), "add", + getSelector() + "," + previousObject.getSelector()); + } + private void allNextSiblingElements(Element firstChildElement, JSArray result) { while (firstChildElement != null) { @@ -1191,15 +1753,44 @@ public class GQuery { } } - private String curCSS(Element elem, String name) { - Style s = elem.getStyle(); - ensureStyleImpl(); - name = styleImpl.getPropertyName(name); - - if (SelectorEngine.truth(s.getProperty(name))) { - return s.getProperty(name); - } - return styleImpl.getCurrentStyle(elem, name); + private JSArray clean(String elem) { + String tags = elem.trim().toLowerCase(); + String preWrap = "", postWrap = ""; + int wrapPos = 0; + if (tags.contains(""; + postWrap = ""; + } else if (!tags.contains(" Object data(Element item, String name, S value) { @@ -1234,12 +1825,37 @@ public class GQuery { } } - private void ensureStyleImpl() { - if (styleImpl != null) { - styleImpl = GWT.create(DocumentStyleImpl.class); + private GQuery domManip(String html, int func) { + return domManip(clean(html), func); + } + + private GQuery domManip(NodeList nodes, int func) { + for (Element e : elements()) { + for (int i = 0; i < nodes.getLength(); i++) { + Node n = nodes.getItem(i).cloneNode(true); + switch (func) { + case FUNC_PREPEND: + e.insertBefore(n, e.getFirstChild()); + break; + case FUNC_APPEND: + e.appendChild(n); + break; + case FUNC_AFTER: + e.getParentNode().insertBefore(n, e.getNextSibling()); + break; + case FUNC_BEFORE: + e.getParentNode().insertBefore(n, e); + break; + } + } } + return this; } + private native Document getContentDocument(Node n) /*-{ + return n.contentDocument || n.contentWindow.document; + }-*/; + private native Element getPreviousSiblingElement(Element elem) /*-{ var sib = elem.previousSibling; while (sib && sib.nodeType != 1) @@ -1251,6 +1867,30 @@ public class GQuery { this.elements = gQuery.elements; } + private JSArray merge(NodeList first, NodeList second) { + JSArray res = JSArray.create(); + for (int i = 0; i < first.getLength(); i++) { + res.addNode(first.getItem(i)); + } + for (int i = 0; i < second.getLength(); i++) { + res.addNode(second.getItem(i)); + } + return res; + } + + private int num(GQuery gQuery, String val) { + Element elem = gQuery.get(0); + try { + if (elem != null) { + String v = GQuery.curCSS(elem, val); + return Integer.parseInt(v); + } + } catch (NumberFormatException e) { + + } + return 0; + } + private Queue queue(Element elem, String type, Function data) { if (elem != null) { type = type + "queue";