diff options
author | Manuel Carrasco Moñino <manolo@apache.org> | 2014-12-06 13:36:10 +0100 |
---|---|---|
committer | Manuel Carrasco Moñino <manolo@apache.org> | 2014-12-06 13:36:10 +0100 |
commit | 9fb01505bf41afa0063ac4d85b51f02ac6365b8f (patch) | |
tree | 99b25ea7b5460694fceb1cb8969bdb8b9f10882d /gwtquery-core | |
parent | 64dd253a2b1643c475b46b0284e5b37abec30684 (diff) | |
parent | 93ec3586adcbc1dcced6f7ac2ecb732975f1af6d (diff) | |
download | gwtquery-9fb01505bf41afa0063ac4d85b51f02ac6365b8f.tar.gz gwtquery-9fb01505bf41afa0063ac4d85b51f02ac6365b8f.zip |
Merge pull request #311 from manolo/master
Faster implementation of filter.
Diffstat (limited to 'gwtquery-core')
7 files changed, 153 insertions, 59 deletions
diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml index 8ba4fc33..3ba5c445 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml +++ b/gwtquery-core/src/main/java/com/google/gwt/query/Query.gwt.xml @@ -16,10 +16,10 @@ <module> <inherits name='com.google.gwt.user.User'/> - + <source path="client"/> <super-source path="super"/> - + <!-- Browser flags --> <generate-with class="com.google.gwt.query.rebind.BrowserGenerator"> <when-type-assignable class="com.google.gwt.query.client.Browser"/> @@ -124,6 +124,11 @@ </any> </replace-with> + <!-- GQuery uses GWT.create to create the selector engine so as it can be overriden by users --> + <replace-with class="com.google.gwt.query.client.impl.SelectorEngine"> + <when-type-assignable class="com.google.gwt.query.client.impl.SelectorEngine"/> + </replace-with> + <!-- UI implementations --> <replace-with class="com.google.gwt.query.client.plugins.UiPlugin.GQueryUiImpl"> <when-type-is class="com.google.gwt.query.client.plugins.UiPlugin.GQueryUiImpl" /> diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java index 32a30e1f..b82a2a3c 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/GQuery.java @@ -13,12 +13,7 @@ */ package com.google.gwt.query.client; -import static com.google.gwt.query.client.plugins.QueuePlugin.*; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import static com.google.gwt.query.client.plugins.QueuePlugin.Queue; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.JavaScriptObject; @@ -26,9 +21,19 @@ import com.google.gwt.core.client.JsArray; import com.google.gwt.core.client.JsArrayMixed; import com.google.gwt.core.client.JsArrayString; import com.google.gwt.core.client.ScriptInjector; -import com.google.gwt.dom.client.*; +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.InputElement; +import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.NodeList; +import com.google.gwt.dom.client.OptionElement; +import com.google.gwt.dom.client.SelectElement; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.HasCssName; +import com.google.gwt.dom.client.TextAreaElement; import com.google.gwt.query.client.css.CSS; import com.google.gwt.query.client.css.HasCssValue; import com.google.gwt.query.client.css.TakesCssValue; @@ -60,6 +65,11 @@ import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.Widget; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + /** * GwtQuery is a GWT clone of the popular jQuery library. */ @@ -764,11 +774,10 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> { return new Deferred(); } - private static SelectorEngine getSelectorEngine() { + public static SelectorEngine getSelectorEngine() { if (engine == null) { - engine = new SelectorEngine(); + engine = GWT.create(SelectorEngine.class); } - return engine; } @@ -830,7 +839,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> { */ public GQuery add(GQuery elementsToAdd) { return pushStack(JsUtils.copyNodeList(nodeList, elementsToAdd.nodeList, true) - .<JsNodeArray> cast(), "add", getSelector() + "," + elementsToAdd.getSelector()); + .<JsNodeArray> cast(), "add", join(",", getSelector(), elementsToAdd.getSelector())); } /** @@ -2255,53 +2264,46 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> { * false, then the element is removed - anything else and the element is kept. */ public GQuery filter(Predicate filterFn) { - JsNodeArray result = JsNodeArray.create(); - int i = 0; - for (Element e : elements) { - if (filterFn.f(e, i++)) { - result.addNode(e); - } - } + JsNodeArray result = getSelectorEngine().filter(nodeList, filterFn).cast(); return pushStack(result, "filter", currentSelector); } /** * Removes all elements from the set of matched elements that do not pass the specified css * expression. This method is used to narrow down the results of a search. + * By default it works for either detached and attached elements unless + * {@link SelectorEngine#filterDetached} is set to false. */ - // TODO performance bad... public GQuery filter(String... filters) { - if (filters.length == 0 || filters[0] == null) { - return this; - } - - JsNodeArray array = JsNodeArray.create(); - - for (String f : filters) { - for (Element e : elements) { - boolean ghostParent = false; - if (e == window || e.getNodeName() == null) { - continue; - } - if (e.getParentNode() == null) { - DOM.createDiv().appendChild(e); - ghostParent = true; - } + String selector = join(", ", filters); + JsNodeArray result = getSelectorEngine().filter(nodeList, selector).cast(); + return pushStack(result, "filter", selector); + } - for (Element c : $(f, e.getParentNode()).elements) { - if (c == e) { - array.addNode(c); - break; - } - } + /** + * Removes all elements from the set of matched elements that do not pass the specified css + * expression. This method is used to narrow down the results of a search. + * Setting filterDetached parameter to true, means that we should consider detached elements + * as well which implies some performance penalty. + */ + public GQuery filter(boolean filterDetached, String... filters) { + String selector = join(", ", filters); + JsNodeArray result = getSelectorEngine().filter(nodeList, selector, filterDetached).cast(); + return pushStack(result, "filter", selector); + } - if (ghostParent) { - e.removeFromParent(); - } - } + /** + * Removes all elements from the set of matched elements that do not pass the specified css + * expression. This method is used to narrow down the results of a search. + * Setting considerDetached parameter to true, means that we should consider detached elements + * as well which implies some performance penalties. + */ + public GQuery filter(boolean filterDetached, String selector) { + if (selector.isEmpty()) { + return this; } - - return pushStack(unique(array), "filter", filters[0]); + JsNodeArray result = getSelectorEngine().filter(nodeList, selector, filterDetached).cast(); + return pushStack(result, "filter", selector); } /** @@ -4674,10 +4676,7 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> { * $(...).val(new String[]{"value"}); */ public GQuery val(String... values) { - String value = values.length > 0 ? values[0] : ""; - for (int i = 1; i < values.length; i++) { - value += "," + values[i]; - } + String value = join(",", values); for (Element e : elements) { String name = e.getNodeName(); if ("select".equalsIgnoreCase(name)) { @@ -4977,4 +4976,12 @@ public class GQuery implements Lazy<GQuery, LazyGQuery> { public GQuery wrapInner(String html) { return wrapInner($(html)); } + + private String join(String chr, String... values) { + String value = ""; + for (int i = 0; i < values.length; i++) { + value += i > 0 ? chr + values[i] : values[i]; + } + return value; + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java index af506174..33b12731 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/LazyGQuery.java @@ -1015,10 +1015,27 @@ public interface LazyGQuery<T> extends LazyBase<T>{ /** * Removes all elements from the set of matched elements that do not pass the specified css * expression. This method is used to narrow down the results of a search. + * {@link #filterDetached} is set to false. */ LazyGQuery<T> filter(String... filters); /** + * Removes all elements from the set of matched elements that do not pass the specified css + * expression. This method is used to narrow down the results of a search. + * Setting considerDetached parameter to true, means that we should consider detached elements + * as well which implies some performance penalties. + */ + LazyGQuery<T> filter(boolean filterDetached, String... filters); + + /** + * Removes all elements from the set of matched elements that do not pass the specified css + * expression. This method is used to narrow down the results of a search. + * Setting considerDetached parameter to true, means that we should consider detached elements + * as well which implies some performance penalties. + */ + LazyGQuery<T> filter(boolean filterDetached, String selector); + + /** * Searches for all elements that match the specified css expression. This method is a good way to * find additional descendant elements with which to process. * diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngine.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngine.java index 0d565d0e..6b6d5921 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngine.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngine.java @@ -15,11 +15,17 @@ */ package com.google.gwt.query.client.impl; +import static com.google.gwt.query.client.GQuery.*; + +import java.util.ArrayList; +import java.util.List; + import com.google.gwt.core.client.GWT; 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.GQuery; import com.google.gwt.query.client.Predicate; import com.google.gwt.query.client.js.JsMap; import com.google.gwt.query.client.js.JsNodeArray; @@ -97,6 +103,13 @@ public class SelectorEngine implements HasSelector { public final SelectorEngineImpl impl; + /** + * Set it to false if all your elements are attached to the DOM and you want to + * increase filter performance using {@link GQuery#getSelectorEngine()} + * method. + */ + public boolean filterDetached = true; + protected Node root = Document.get(); public static final boolean hasQuerySelector = hasQuerySelectorAll(); @@ -155,6 +168,55 @@ public class SelectorEngine implements HasSelector { return res; } + public NodeList<Element> filter(NodeList<Element> nodes, String selector) { + return filter(nodes, selector, filterDetached); + } + + public NodeList<Element> filter(NodeList<Element> nodes, String selector, boolean filterDetached) { + JsNodeArray res = JsNodeArray.create(); + if (selector.isEmpty()){ + return res; + } + Element ghostParent = null; + ArrayList<Node> parents = new ArrayList<Node>(); + List<Node> elmList = new ArrayList<Node>(); + for (int i = 0, l = nodes.getLength(); i < l; i++) { + Node e = nodes.getItem(i); + if (e == window || e == document || e.getNodeName() == null || "html".equalsIgnoreCase(e.getNodeName())) { + continue; + } + elmList.add(e); + if (filterDetached) { + Element p = e.getParentElement(); + if (p == null) { + if (ghostParent == null) { + ghostParent = Document.get().createDivElement(); + parents.add(ghostParent); + } + p = ghostParent; + p.appendChild(e); + } else if (!parents.contains(p)) { + parents.add(p); + } + } else if (parents.isEmpty()) { + parents.add(document); + } + } + for (Node e : parents) { + NodeList<Element> n = select(selector, e); + for (int i = 0, l = n.getLength(); i < l; i++) { + Element el = n.getItem(i); + if (elmList.remove(el)) { + res.addNode(el); + } + } + } + if (ghostParent != null) { + ghostParent.setInnerHTML(null); + } + return res; + } + // pseudo selectors which are computed by gquery in runtime RegExp gQueryPseudo = RegExp.compile("(.*):((visible|hidden|selected|input|header)|((button|checkbox|file|hidden|image|password|radio|reset|submit|text)\\s*(,|$)))(.*)", "i"); // pseudo selectors which work in engine @@ -223,12 +285,10 @@ public class SelectorEngine implements HasSelector { */ public static native boolean hasQuerySelectorAll() /*-{ return $doc.location.href.indexOf("_force_no_native") < 0 && - $doc.querySelectorAll && - /native/.test(String($doc.querySelectorAll)) ? true : false; + typeof $doc.querySelectorAll == 'function'; }-*/; public static native boolean hasXpathEvaluate() /*-{ - return $doc.evaluate ? true : false; + return !!$doc.evaluate; }-*/; - } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java index cf62be4f..f0af09b8 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEffects.java @@ -363,6 +363,13 @@ public interface LazyEffects<T> extends LazyBase<T>{ LazyEffects<T> slideRight(int millisecs, Function... f); /** + * Toggle the visibility of all matched elements by adjusting their height and firing an optional + * callback after completion. Only the height is adjusted for this animation, causing all matched + * elements to be hidden or shown in a "sliding" manner + */ + LazyEffects<T> slideToggle(Function... f); + + /** * Toggle the visibility of all matched elements by adjusting their height and * firing an optional callback after completion. Only the height is adjusted * for this animation, causing all matched elements to be hidden or shown in a diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java index dec30be8..081e1702 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java @@ -16,7 +16,6 @@ import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.FormElement; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Node; -import com.google.gwt.event.dom.client.HasNativeEvent; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQuery; import com.google.gwt.query.client.js.JsUtils; diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java index f4a4d963..763655da 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQueryCoreTestGwt.java @@ -877,7 +877,6 @@ public class GQueryCoreTestGwt extends GWTTestCase { public void testShowHide() { $(e).html( "<p id='id1' style='display: inline'>Content 1</p><p id='id2'>Content 2</p><p id='id3'>Content 3</p>"); - final GQuery sectA = $("#id1"); final GQuery sectB = $("#id2"); final GQuery sectC = $("#id3"); |