From: Manuel Carrasco MoƱino Date: Thu, 19 Dec 2013 12:58:55 +0000 (+0100) Subject: Use a hash to customize filters. Include more filters present in jquery. Fixes issues... X-Git-Tag: gwtquery-project-1.4.3~52 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=83e2739c656a992653e11fcec85409881332c801;p=gwtquery.git Use a hash to customize filters. Include more filters present in jquery. Fixes issues #230 #184 #220 --- 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 3ffff970..beedb287 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 @@ -20,6 +20,8 @@ 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.Predicate; +import com.google.gwt.query.client.js.JsMap; import com.google.gwt.query.client.js.JsNodeArray; import com.google.gwt.query.client.js.JsUtils; import com.google.gwt.regexp.shared.MatchResult; @@ -99,6 +101,37 @@ public class SelectorEngine implements HasSelector { public static final boolean hasQuerySelector = hasQuerySelectorAll(); + public static JsMap filters; + + static { + filters = JsMap.create(); + filters.put("visible", new Predicate(){ + public boolean f(Element e, int index) { + return (e.getOffsetWidth() + e.getOffsetHeight()) > 0 && styleImpl.isVisible(e); + } + }); + filters.put("hidden", new Predicate() { + public boolean f(Element e, int index) { + return !filters.get("visible").f(e, index); + } + }); + filters.put("selected", new Predicate() { + public boolean f(Element e, int index) { + return e.getPropertyBoolean("selected"); + } + }); + filters.put("input", new Predicate(){ + public boolean f(Element e, int index) { + return e.getNodeName().toLowerCase().matches("input|select|textarea|button"); + } + }); + filters.put("header", new Predicate(){ + public boolean f(Element e, int index) { + return e.getNodeName().toLowerCase().matches("h\\d"); + } + }); + } + public SelectorEngine() { impl = (SelectorEngineImpl) GWT.create(SelectorEngineImpl.class); GWT.log("GQuery - Created SelectorEngineImpl: " + impl.getClass().getName()); @@ -110,33 +143,51 @@ public class SelectorEngine implements HasSelector { return root; } - public NodeList filterByVisibility (NodeList nodes, boolean visible) { + public NodeList filter(NodeList nodes, Predicate p) { JsNodeArray res = JsNodeArray.create(); for (int i = 0, l = nodes.getLength(), j = 0; i < l; i++) { Element e = nodes.getItem(i); - if (visible == ((e.getOffsetWidth() + e.getOffsetHeight()) > 0 && styleImpl.isVisible(e))) { + if (p.f(e, i)) { res.addNode(e, j++); } } return res; } - // pseudo selectors which are computed by gquery - RegExp p = RegExp.compile("(.*):((visible|hidden)|((button|checkbox|file|hidden|image|password|radio|reset|submit|text)\\s*(,|$)))(.*)", "i"); + // 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 + RegExp nativePseudo = RegExp.compile("(.*):([\\w]+):(disabled|checked|enabled|empty|focus)\\s*([:,].*|$)", "i"); public NodeList select(String selector, Node ctx) { - if (p.test(selector)) { + + if (nativePseudo.test(selector)) { + // move gQuery filters at the end to improve performance, and deal with issue #220 + MatchResult r; + while ((r = nativePseudo.exec(selector)) != null) { + selector = r.getGroup(1) + ":" + r.getGroup(3); + if (!r.getGroup(3).equals(r.getGroup(2))) { + selector += ":" + r.getGroup(2); + } + selector += r.getGroup(4); + } + } + + if (gQueryPseudo.test(selector)) { JsNodeArray res = JsNodeArray.create(); for (String s : selector.trim().split("\\s*,\\s*")) { NodeList nodes; - MatchResult a = p.exec(s); + MatchResult a = gQueryPseudo.exec(s); if (a != null) { - if (s.endsWith(":visible")) { - nodes = filterByVisibility(select(s.substring(0, s.length() - 8), ctx), true); - } else if (s.endsWith(":hidden")) { - nodes = filterByVisibility(select(s.substring(0, s.length() - 7), ctx), false); + String select = a.getGroup(1).isEmpty() ? "*" : a.getGroup(1); + String pseudo = a.getGroup(2); + Predicate pred = filters.get(pseudo.toLowerCase()); + if (pred != null) { + nodes = filter(select(select, ctx), pred); + } else if (nativePseudo.test(pseudo)) { + nodes = select(select, ctx); } else { - nodes = select((a.getGroup(1) != null ? a.getGroup(1) : "") + "[type=" + a.getGroup(2) + "]", ctx); + nodes = select(select + "[type=" + pseudo + "]", ctx); } } else { nodes = select(s, ctx); diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTestGwt.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTestGwt.java index 08897f56..36083eee 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTestGwt.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTestGwt.java @@ -215,6 +215,34 @@ public class GQuerySelectorsTestGwt extends GWTTestCase { assertEquals(1, $("input:checkbox ", e).size()); assertEquals(1, $(":radio ", e).size()); assertEquals(2, $("*:radio, *:checkbox", e).size()); + assertEquals(2, $(":input", e).size()); + assertEquals(0, $(":checked", e).size()); + + // issue #220 + $(":checkbox", e).prop("checked", true); + assertEquals(1, $(":checked", e).size()); + assertEquals(1, $(":checkbox", e).size()); + assertEquals(1, $(":checkbox:checked", e).size()); + + // issue #184 + $(e).html("

"); + assertEquals(1, $("p:hidden ", e).size()); + assertTrue($("p").is(":hidden")); + + // issue #206 + $(e).html("

"); + assertEquals(0, $("*:selected ", e).size()); + $("option", e).eq(2).prop("selected", true); + assertEquals(1, $(":selected", e).size()); + $("option", e).eq(1).prop("selected", true); + assertEquals(2, $("option:selected", e).size()); + + // Extra selectors + assertEquals(1, $(":header", e).size()); + + // disabling this because querySelectorAll of htmlunit does not support :empty + // it works in chrome and FF + // assertEquals(1, $(":empty", e).size()); } public void testCompiledSelectors() {