Just my first attempt at adding some initial support for
getElementsByClassName. This is by no means tested or
Newer browsers support getElementsByClassName. This is my attempt at a patch.
Caveats:
There's a "bug" in that quirks mode doesn't behave properly (I don't
know how to detect it in the deferred binding) for IE & Firefox2 &
earlier. According to the HTML5 spec, it's supposed to be case
insensitive in quirks mode. However, this "bug" behaves the exact
same way as all the javascript wrappers do (since I based the XPath &
RegExp code paths roughly around the implementations floating out
there).
I'm also not sure if I added the support correctly for Firefox.
getElementsByClassName only came in with FF3 & requires the xpath
workaround for FF2 & earlier (I believe I read xpath was introduced
with FF 1.5). I placed the xpath code in DOMImplMozillaOld for now
(not sure whether or not gecko1_8 represents FF2).
There's also no mention of the versions of Safari & Opera that are
supported by GWT, so they're defaulting to using the native version
(which will not work if they don't provide it).
Safari in particular got it with version 3.1. if earlier versions are
supported, it's not too much work. Simply grab the expression built
in the FF xpath & pass it to document._getElementsByXPath(query,
parent) for Safari versions that have xpath (not sure which those
are). Not sure how to distinguish Safari pre3.1 & post3.1 in deferred
binding.
Opera got it with 9.5. Not sure when xPath support got into Opera
(should be a straightfoward copy of the mozilla code). Not sure how
to distinguish the two in the deferred binding.
Feedback would be appreciated.
Should this go as an enhancement request in the issue tracker?
--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---
diff --git a/user/src/com/google/gwt/dom/client/DOMImpl.java b/user/src/com/google/gwt/dom/client/DOMImpl.java
index 1d7e39b..581764b 100644
--- a/user/src/com/google/gwt/dom/client/DOMImpl.java
+++ b/user/src/com/google/gwt/dom/client/DOMImpl.java
@@ -176,6 +176,8 @@ abstract class DOMImpl {
return 0;
}-*/;
+ public abstract NodeList<Element> getElementsByClassName(Element parent, String className);
+
public native Element getFirstChildElement(Element elem) /*-{
var child = elem.firstChild;
while (child && child.nodeType != 1)
diff --git a/user/src/com/google/gwt/dom/client/DOMImplIE6.java b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
index 04c205a..8c24a6c 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplIE6.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplIE6.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dom.client;
+import com.google.gwt.core.client.JsArray;
+
/**
* Internet Explorer 6 implementation of
* {...@link com.google.gwt.user.client.impl.DOMImpl}.
@@ -184,6 +186,31 @@ class DOMImplIE6 extends DOMImpl {
}
@Override
+ public NodeList<Element> getElementsByClassName(Element parent, String className) {
+ // TODO: detect quirks mode so that the regexps do a case insensitive match as per the
+ // spec. when quirks mode detected, pass "i" as the flags parameter
+ return getElementsByClassName(parent, className.split(" "), "").cast();
+ }
+
+ private native JsArray<Element> getElementsByClassName(Element parent, String [] classes, String flags) /*-{
+ var i, j, e, c, elements = parent.all || parent.getElementsByTagName("*");
+ var regexps = [], result = [];
+ for (i = classes.length - 1; i >= 0; i--) {
+ c = classes[i].replace(/^\s+|\s+$/g, "");
+ if (c.length)
+ regexps.push(new RegExp(new Array("(?:^|\\s)", c, "(?:\\s|$)").join(""), flags);
+ }
+ if (regexps.length) {
+ for (i = 0, c = elements.length; i < c; i++) {
+ e = elements[i];
+ for (j = regexps.length - 1; j >= 0 && regexps[j].test(e); j--) {}
+ j == -1 && result.push(e);
+ }
+ }
+ return result;
+ }-*/;
+
+ @Override
public native String getInnerText(Element elem) /*-{
return elem.innerText;
}-*/;
diff --git a/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java b/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
index ecf52fb..5fd7312 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplMozillaOld.java
@@ -15,6 +15,8 @@
*/
package com.google.gwt.dom.client;
+import com.google.gwt.core.client.JsArray;
+
/**
* DOM implementation differences for older version of Mozilla (mostly the
* hosted mode browser on linux). The main difference is due to changes in
@@ -114,4 +116,23 @@ package com.google.gwt.dom.client;
return top + viewport.scrollTop;
}-*/;
+
+ @Override
+ public NodeList<Element> getElementsByClassName(Element parent, String className) {
+ // the cast should be safe since both it & JsArray access the underlying object the same way
+ // and NodeList is immutable (constraints added, not removed)
+ return getElementsByClassName(parent, className.split(" ")).cast();
+ }
+
+ private native JsArray<Element> getElementsByClassName(Element parent, String [] classes) /*-{
+ var result, i, xpathResult, classExpr = ".//*";
+ for (i = classes.length - 1; i >= 0; i--) {
+ classExpr += "[contains(concat(' ', @class, ' '), ' " + classes[i] + " ')]";
+ }
+ xpathResult = document.evaluate(classExpr, parent, null, 0, null);
+ while ((i = xpathResult.iterateNext())) {
+ result.push(i);
+ }
+ return result;
+ }-*/;
}
diff --git a/user/src/com/google/gwt/dom/client/DOMImplStandard.java b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
index 90d2e89..be29fe1 100644
--- a/user/src/com/google/gwt/dom/client/DOMImplStandard.java
+++ b/user/src/com/google/gwt/dom/client/DOMImplStandard.java
@@ -114,6 +114,11 @@ abstract class DOMImplStandard extends DOMImpl {
}-*/;
@Override
+ public native NodeList<Element> getElementsByClassName(Element parent, String className) /*-{
+ return parent.getElementsByClassName(className);
+ }-*/;
+
+ @Override
public native boolean isOrHasChild(Element parent, Element child) /*-{
return parent.contains(child);
}-*/;
diff --git a/user/src/com/google/gwt/dom/client/Document.java b/user/src/com/google/gwt/dom/client/Document.java
index 209b1b9..23d6daf 100644
--- a/user/src/com/google/gwt/dom/client/Document.java
+++ b/user/src/com/google/gwt/dom/client/Document.java
@@ -1125,6 +1125,18 @@ public class Document extends Node {
}-*/;
/**
+ * Returns a {...@link NodeList} of all the {...@link Element Elements} with a given
+ * class name in the order in which they are encountered in a preorder traversal
+ * of the document tree.
+ *
+ * @param className the space-separated name of the classes to match on
+ * @return a list containing all the matched elements.
+ */
+ public final NodeList<Element> getElementsByClassName(String className) {
+ return DOMImpl.impl.getElementsByClassName(this.<Element>cast(), className);
+ }
+
+ /**
* Returns the {...@link Element} whose id is given by elementId. If no such
* element exists, returns null. Behavior is not defined if more than one
* element has this id.
diff --git a/user/src/com/google/gwt/dom/client/Element.java b/user/src/com/google/gwt/dom/client/Element.java
index a0bf9f2..d64b83e 100644
--- a/user/src/com/google/gwt/dom/client/Element.java
+++ b/user/src/com/google/gwt/dom/client/Element.java
@@ -149,6 +149,18 @@ public class Element extends Node {
}-*/;
/**
+ * Returns a {...@link NodeList} of all the {...@link Element Elements} with a given
+ * class name in the order in which they are encountered in a preorder traversal
+ * of this elements children.
+ *
+ * @param className the space-separated names of the classes to match on
+ * @return a list containing all the matched elements.
+ */
+ public final NodeList<Element> getElementsByClassName(String className) {
+ return DOMImpl.impl.getElementsByClassName(this, className);
+ }
+
+ /**
* Returns a NodeList of all descendant Elements with a given tag name, in the
* order in which they are encountered in a preorder traversal of this Element
* tree.