From 9db75b2103c3e2258f0c8a5c9fc6e426ba3fc1a6 Mon Sep 17 00:00:00 2001 From: Manolo Carrasco Date: Thu, 28 Jul 2011 09:44:01 +0000 Subject: implement :hidden and :visible pseudo selectors, fixes issue86 --- .../java/com/google/gwt/query/client/GQuery.java | 44 +++++++--------------- .../gwt/query/client/impl/SelectorEngine.java | 40 ++++++++++++++++++-- .../client/impl/SelectorEngineCssToXPath.java | 5 ++- .../com/google/gwt/query/client/js/JsUtils.java | 16 ++++++++ .../client/plugins/effects/ClipAnimation.java | 2 +- .../plugins/effects/PropertiesAnimation.java | 2 +- .../gwt/query/client/GQuerySelectorsTest.java | 39 +++++++++++++------ 7 files changed, 99 insertions(+), 49 deletions(-) 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 625521c7..cdc8cbee 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 @@ -40,9 +40,7 @@ import com.google.gwt.query.client.css.HasCssValue; import com.google.gwt.query.client.css.TakesCssValue; import com.google.gwt.query.client.css.TakesCssValue.CssSetter; import com.google.gwt.query.client.impl.DocumentStyleImpl; -import com.google.gwt.query.client.impl.HasSelector; import com.google.gwt.query.client.impl.SelectorEngine; -import com.google.gwt.query.client.impl.SelectorEngineCssToXPath; import com.google.gwt.query.client.js.JsCache; import com.google.gwt.query.client.js.JsMap; import com.google.gwt.query.client.js.JsNamedArray; @@ -443,14 +441,6 @@ public class GQuery implements Lazy { } } - private static JsNodeArray copyNodeList(NodeList nodes) { - JsNodeArray res = JsNodeArray.create(); - for (int i = 0, l = nodes.getLength(); i < l; i++) { - res.addNode(nodes.getItem(i), i); - } - return res; - } - private static native void emptyDocument(Document d) /*-{ d.open(); d.write(""); @@ -490,14 +480,11 @@ public class GQuery implements Lazy { if (engine == null) { engine = new SelectorEngine(); } - - NodeList n = engine.select(selector, context == null ? document : context); - JsNodeArray res = copyNodeList(n); + NodeList n = engine.select(selector, context == null ? document : context); currentSelector = selector; currentContext = context != null ? context : document; - - return setArray(res); + return setArray(n); } private static native Element window() /*-{ @@ -545,14 +532,13 @@ public class GQuery implements Lazy { * It also update the selector appending the new one. */ public GQuery add(GQuery previousObject) { - return pushStack(unique(merge(nodeList, previousObject.nodeList)), "add", + return pushStack(unique(JsUtils.copyNodeList(previousObject.nodeList, nodeList)), "add", getSelector() + "," + previousObject.getSelector()); } /** * Add elements to the set of matched elements if they are not included yet. */ - public GQuery add(String selector) { return add($(selector)); } @@ -1876,7 +1862,7 @@ public class GQuery implements Lazy { } return pushStack(unique(array), "filter", filters[0]); } - + /** * Searches for all elements that match the specified css expression. This * method is a good way to find additional descendant elements with which to @@ -3532,7 +3518,7 @@ public class GQuery implements Lazy { */ public GQuery toggle() { for (Element e : elements) { - if ($(e).visible()) { + if (styleImpl.isVisible(e)) { $(e).hide(); } else { $(e).show(); @@ -3688,7 +3674,7 @@ public class GQuery implements Lazy { * Remove all duplicate elements from an array of elements. Note that this * only works on arrays of DOM elements, not strings or numbers. */ - public JsNodeArray unique(JsNodeArray result) { + public JsNodeArray unique(NodeList result) { return JsUtils.unique(result.> cast()).cast(); } @@ -3832,12 +3818,18 @@ public class GQuery implements Lazy { return new String[0]; } + /** - * Return true if the first element is visible. + * Return true if the first element is visible.isVisible */ - public boolean visible() { + public boolean isVisible() { return isEmpty() ? false : styleImpl.isVisible(get(0)); } + + @Deprecated + public boolean visible() { + return isVisible(); + } /** * Return the first non null attached widget from the matched elements or null @@ -4216,14 +4208,6 @@ public class GQuery implements Lazy { return sib; }-*/; - private JsNodeArray merge(NodeList first, NodeList second) { - JsNodeArray res = copyNodeList(first); - for (int i = 0, l = second.getLength(); i < l; i++) { - res.addNode(second.getItem(i)); - } - return res; - } - private void removeData(Element item, String name) { if (dataCache == null) { windowData = JavaScriptObject.createObject().cast(); 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 8451be10..65d735df 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 @@ -16,16 +16,20 @@ package com.google.gwt.query.client.impl; import com.google.gwt.core.client.GWT; +import com.google.gwt.core.client.JsArray; 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.js.JsNodeArray; +import com.google.gwt.query.client.js.JsUtils; /** * Core Selector engine functions, and native JS utility functions. */ public class SelectorEngine implements HasSelector { + + private static DocumentStyleImpl styleImpl; public static native NodeList getElementsByClassName(String clazz, Node ctx) /*-{ @@ -86,17 +90,47 @@ public class SelectorEngine implements HasSelector { public SelectorEngine() { impl = (SelectorEngineImpl) GWT.create(SelectorEngineImpl.class); - System.out.println("Create SelectorEngineImpl " + impl.getClass().getName()); + System.out.println("Created SelectorEngineImpl: " + impl.getClass().getName()); + styleImpl = GWT.create(DocumentStyleImpl.class); + System.out.println("Created DocumentStyleImpl: " + styleImpl.getClass().getName()); } public Node getRoot() { return root; } + public NodeList filterByVisibility (NodeList nodes, boolean visible) { + 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))) { + res.addNode(e, j++); + } + } + return res; + } + public NodeList select(String selector, Node ctx) { - return impl.select(selector, ctx); + if (selector.matches(".*:(visible|hidden)\\s*(,|$).*")) { + // :visible and :hidden pseudo selectors are computed by gquery + JsNodeArray res = JsNodeArray.create(); + for (String s : selector.trim().split("\\s*,\\s*")) { + NodeList nodes; + 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); + } else { + nodes = select(s, ctx); + } + JsUtils.copyNodeList(res, nodes); + } + return JsUtils.unique(res.> cast()).cast(); + } else { + return impl.select(selector, ctx); + } } - + public void setRoot(Node root) { assert root != null; this.root = root; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineCssToXPath.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineCssToXPath.java index 4ed673f6..5feec66f 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineCssToXPath.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/SelectorEngineCssToXPath.java @@ -34,7 +34,7 @@ import com.google.gwt.query.client.js.JsUtils; */ public class SelectorEngineCssToXPath extends SelectorEngineImpl { - JsNamedArray cache; + static JsNamedArray cache; /** * Interface for callbacks in replaceAll operations. @@ -225,7 +225,8 @@ public class SelectorEngineCssToXPath extends SelectorEngineImpl { return JsUtils.unique(elm.> cast()).cast(); } catch (Exception e) { System.err.println("ERROR: xpathEvaluate invalid xpath expression:" - + xsel + " css-selector:" + sel + "\n\n" + e.getMessage()); + + xsel + " css-selector:" + sel + "\n"); + e.printStackTrace(); return elm; } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java index b504d6e4..686550ec 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsUtils.java @@ -18,6 +18,7 @@ package com.google.gwt.query.client.js; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.client.JsArray; import com.google.gwt.dom.client.Element; +import com.google.gwt.dom.client.NodeList; import com.google.gwt.query.client.GQuery; import com.google.gwt.user.client.DOM; @@ -110,5 +111,20 @@ public class JsUtils { } return ret; } + + /** + * Merge the newNodes list into the oldNodes one. + * If oldNodes is null, a new list will be created and returned, + * newNodes list is never modified. + */ + public static NodeList copyNodeList(NodeList oldNodes, NodeList newNodes) { + if (oldNodes == null) { + oldNodes = JsNodeArray.create(); + } + for (int i = 0, l = newNodes.getLength(), j = oldNodes.getLength(); i < l; i++) { + oldNodes.cast().addNode(newNodes.getItem(i), j++); + } + return oldNodes; + } } diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ClipAnimation.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ClipAnimation.java index be06f997..3af40938 100755 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ClipAnimation.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/ClipAnimation.java @@ -62,7 +62,7 @@ public class ClipAnimation extends GQAnimation { public ClipAnimation(Element elem, Action a, Corner c, Direction d, final Function... funcs) { if (a == Action.TOGGLE) { - a = GQuery.$(elem).visible() ? Action.HIDE : Action.SHOW; + a = GQuery.$(elem).isVisible() ? Action.HIDE : Action.SHOW; } this.action = a; this.corner = c; diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java index 2552b03b..72559a70 100755 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/PropertiesAnimation.java @@ -240,7 +240,7 @@ public class PropertiesAnimation extends GQAnimation { public void onStart() { boolean resize = false; boolean move = false; - boolean hidden = !g.visible(); + boolean hidden = !g.isVisible(); Fx fx; // g.show(); for (String key : prps.keys()) { diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTest.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTest.java index 306869d7..57a4f7fd 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTest.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/GQuerySelectorsTest.java @@ -42,16 +42,18 @@ import com.google.gwt.user.client.ui.RootPanel; public class GQuerySelectorsTest extends GWTTestCase { protected interface AllSelectors extends Selectors { - // @Selector("h1[id]:contains(Selectors)") - // NodeList h1IdContainsSelectors(); - // @Selector("*:first") - // NodeList allFirst(); - // @Selector("div[class!=madeup]") + @Selector("h1[id]:contains(Selectors)") + NodeList h1IdContainsSelectors(); + @Selector("tr:first") + NodeList trFirst(); + @Selector("tr:last") + NodeList trLast(); + // @Selector("div[class!='madeup']") // NodeList divWithClassNotContainsMadeup(); // @Selector("div, p a") // NodeList divCommaPA(); - // @Selector("p:contains(selectors)") - // NodeList pContainsSelectors(); + @Selector("p:contains(selectors)") + NodeList pContainsSelectors(); @Selector("a[href][lang][class]") NodeList aHrefLangClass(); @Selector("*:checked") @@ -173,22 +175,32 @@ public class GQuerySelectorsTest extends GWTTestCase { e.setInnerHTML(""); } } + + public void testVisibleHidden() { + $(e).html("
A Text

"); + assertEquals(9, $("* ", e).size()); + assertEquals(1, $("*:hidden ", e).size()); + assertEquals(8, $("*:visible ", e).size()); + assertEquals(2, $("*:hidden , span", e).size()); + assertEquals(8, $("*:visible , span", e).size()); + } public void testCompiledSelectors() { final AllSelectors sel = GWT.create(AllSelectors.class); $(e).html(getTestContent()); // TODO: fix these selectors - // sel.h1IdContainsSelectors().getLength() - // sel.allFirst().getLength() // sel.divWithClassNotContainsMadeup().getLength() // sel.divCommaPA().getLength() - // sel.pContainsSelectors().getLength() + // assertArrayContains(sel.title().getLength(), 1); - assertEquals(1, sel.body().getLength()); assertArrayContains(sel.bodyDiv().getLength(), 53, 55); sel.setRoot(e); + assertArrayContains(sel.trFirst().getLength(), 5); + assertArrayContains(sel.trLast().getLength(), 5); + assertArrayContains(sel.pContainsSelectors().getLength(), 54); + assertArrayContains(sel.h1IdContainsSelectors().getLength(), 1); assertArrayContains(sel.aHrefLangClass().getLength(), 0, 1); assertArrayContains(sel.allChecked().getLength(), 1); assertArrayContains(sel.divExample().getLength(), 43); @@ -392,7 +404,10 @@ public class GQuerySelectorsTest extends GWTTestCase { assertArrayContains(selEng.select("body", document).getLength(), 1); assertArrayContains(selEng.select("body div", document).getLength(), 53, 55); - + + assertArrayContains(selEng.select("tr:first", e).getLength(), 0, 1, 5); + assertArrayContains(selEng.select("tr:last", e).getLength(), 0, 1, 5); + assertArrayContains(selEng.select("p:contains(selectors)", e).getLength(), 54); assertArrayContains(selEng.select("h1[id]:contains(Selectors)", e).getLength(), 1); assertArrayContains(selEng.select("div[class!=madeup]", e).getLength(), 52, 53); assertArrayContains(selEng.select("div, p a", e).getLength(), 136, 137, 138); -- cgit v1.2.3