Finally, I have an automated test that exercises DynaFaces and jMaki. If you don't know what those two things are, check out <http://developers.sun.com/web/swdp/>.
Anyhow, it was a real pain to keep these two things working together as jMaki rapidly evolved. Now at least we can have an automated test to catch regressions. SECTION: Changes A dist/mcp-test/src/main/java/jsf_jmaki/JsfjMaki.java A dist/mcp-test/src/test/java/jsf_jmaki/JsfjMakiTest.java - The automated test and the netbeans empty main class. M dom/classes/org/mozilla/dom/util/DOMTreeDumper.java - Introduce preorder traversal callback facility M webclient/classes_spec/org/mozilla/mcp/MCP.java - add methods + public List<Element> getAnchors(String id) { + public List<Element> getAnchors() { + public List<Element> getChildElementsWithTagName(Element root, + final String tagName) { + public List<Element> getChildElementsWithTagName(String id, + final String tagName) { + public void clickElement(String id) { + public void blockingClickElement(Element element) { SECTION: Diffs Index: dom/classes/org/mozilla/dom/util/DOMTreeDumper.java =================================================================== RCS file: /cvsroot/mozilla/java/dom/classes/org/mozilla/dom/util/ DOMTreeDumper.java,v retrieving revision 1.2 diff -u -r1.2 DOMTreeDumper.java --- dom/classes/org/mozilla/dom/util/DOMTreeDumper.java 6 Mar 2007 22:03:42 -0000 1.2 +++ dom/classes/org/mozilla/dom/util/DOMTreeDumper.java 21 Apr 2007 03:16:51 -0000 @@ -24,6 +24,7 @@ import java.io.PrintStream; import java.io.FileOutputStream; import java.io.IOException; +import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -233,34 +234,60 @@ dbg("finished dumping..."); return baos.toString(); } - - private Element findElementWithName(Element start, String name) { - Element result = null; + public void preorderTreeWalk(Node start, + TreeTraversalCallBack callback, Object closure) { + try { + doPreorderTreeWalk(start, callback, closure); + } catch (AbortTraversalException ex) { + return; + } + } + + + private void doPreorderTreeWalk(Node start, + TreeTraversalCallBack callback, Object closure) + throws AbortTraversalException { + callback.takeActionOnNode(start, closure); + NodeList children = start.getChildNodes(); Node child = null; - String elementName = start.getAttribute("name"); - if (null != elementName && elementName.equals(name)) { - return start; + int length = 0; + boolean hasChildren = ((children != null) && + ((length = children.getLength()) > 0)); + if (!hasChildren) { + return; } - else { - NodeList children = start.getChildNodes(); - int length = 0; - boolean hasChildren = ((children != null) && - ((length = children.getLength()) > 0)); - if (!hasChildren) { - return result; - } - for (int i=0; i < length; i++) { - child = children.item(i); - result = null; - if (child instanceof Element) { - result = findElementWithName((Element) child, name); - } - if (null != result) { - break; + for (int i=0; i < length; i++) { + child = children.item(i); + doPreorderTreeWalk(child, callback, closure); + } + } + + private Element findElementWithName(Element start, final String name) { + TreeTraversalCallBack callback = new TreeTraversalCallBack() { + + public void takeActionOnNode(Node node, Object closure) + throws AbortTraversalException { + Element element = null; + if (node instanceof Element) { + element = (Element) node; + String elementName = element.getAttribute("name"); + if (null != elementName && elementName.equals(name)) { + this.setResult(node); + throw new AbortTraversalException("Found result"); + } } } - } + + }; + + Element result = null; + + this.preorderTreeWalk(start, callback, name); + Object obj = callback.getResult(); + if (obj instanceof Element) { + result = (Element)obj; + } return result; } @@ -280,4 +307,29 @@ System.out.println(name + ": " + str); } } + + public static abstract class TreeTraversalCallBack { + public abstract void takeActionOnNode(Node node, Object closure) +throws AbortTraversalException; + + private Object result; + + public Object getResult() { + return result; + } + + public void setResult(Object result) { + this.result = result; + } + } + + public static class AbortTraversalException extends RuntimeException { + private Object closure; + public AbortTraversalException(Object closure) { + this.closure = closure; + } + public Object getClosure() { + return closure; + } + } } Index: webclient/classes_spec/org/mozilla/mcp/MCP.java =================================================================== RCS file: /cvsroot/mozilla/java/webclient/classes_spec/org/mozilla/mcp/ MCP.java,v retrieving revision 1.8 diff -u -r1.8 MCP.java --- webclient/classes_spec/org/mozilla/mcp/MCP.java 14 Mar 2007 21:02:13 -0000 1.8 +++ webclient/classes_spec/org/mozilla/mcp/MCP.java 21 Apr 2007 03:16:51 -0000 @@ -33,11 +33,15 @@ import java.awt.event.KeyListener; import java.awt.event.MouseListener; import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.logging.Level; import java.util.logging.Logger; import org.mozilla.dom.util.DOMTreeDumper; +import org.mozilla.dom.util.DOMTreeDumper.AbortTraversalException; +import org.mozilla.dom.util.DOMTreeDumper.TreeTraversalCallBack; import org.mozilla.webclient.BrowserControl; import org.mozilla.webclient.BrowserControlCanvas; import org.mozilla.webclient.BrowserControlFactory; @@ -49,6 +53,7 @@ import org.mozilla.webclient.WebclientEvent; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.Node; /** * <p>The main class for the Mozilla Control Program. Please see <a @@ -110,6 +115,9 @@ } private void openLatch() { + if (null == latch) { + return; + } if (null != latch || 1 != latch.getCount()) { latch.countDown(); latch = null; @@ -405,6 +413,79 @@ return result; } + + /** + + * <p>Given an argument <code>id</code>, return a List of DOM + * <code>Element</code> instances that are HTML anchors that are + * direct or indirect children of the element with that <code>id</ code>. + */ + public List<Element> getAnchors(String id) { + List<Element> result = getChildElementsWithTagName(id, "a"); + return result; + } + + /** + + * <p>Return a List of DOM + * <code>Element</code> instances that are HTML anchors that are + * present in the document. + * If no such elements exist, + * <code>null</code> is returned.</p> + */ + public List<Element> getAnchors() { + Element root = getCurrentPage().getDOM().getDocumentElement(); + List<Element> result = getChildElementsWithTagName(root, "a"); + return result; + } + + /** + + * <p>Return a List of DOM <code>Element</code> instances whose + * tagName attribute is equal to the argument <code>tagName</ code>. + * If no such elements exist, + * <code>null</code> is returned.</p> + */ + + public List<Element> getChildElementsWithTagName(Element root, + final String tagName) { + List<Element> results = new ArrayList<Element>(); + if (null != root) { + TreeTraversalCallBack callback = new TreeTraversalCallBack() { + public void takeActionOnNode(Node node, Object closure) + throws AbortTraversalException { + List<Element> list = (List<Element>) closure; + Element element = null; + if (node instanceof Element) { + element = (Element) node; + String nodeTagName = element.getTagName(); + if (null != nodeTagName && nodeTagName.equalsIgnoreCase(tagName)){ + list.add(element); + } + } + } + }; + getDOMTreeDumper().preorderTreeWalk(root, callback, results); + } + + return results; + } + /** + + * <p>Return a List of DOM <code>Element</code> instances whose + * tagName attribute is equal to the argument <code>tagName</ code>. + * If no such elements exist, + * <code>null</code> is returned.</p> + */ + + public List<Element> getChildElementsWithTagName(String id, + final String tagName) { + List<Element> results = null; + Element root = findElement(id); + results = getChildElementsWithTagName(root, tagName); + + return results; + } /** @@ -432,9 +513,9 @@ */ - public void clickElement(String id) { - Element element = findElement(id); + public void clickElement(Element element) { String clientX = null, clientY = null; + String id = element.getAttribute("id"); if (null != element) { clientX = element.getAttribute("clientX"); clientY = element.getAttribute("clientY"); @@ -444,7 +525,6 @@ x = Integer.valueOf(clientX).intValue(); y = Integer.valueOf(clientY).intValue(); Robot robot = getRobot(); - createLatch(); robot.mouseMove(x, y); robot.mousePress(InputEvent.BUTTON1_MASK); robot.mouseRelease(InputEvent.BUTTON1_MASK); @@ -466,16 +546,34 @@ * <p>Find the DOM element within the current page matching the * argument <code>id</code> using [EMAIL PROTECTED] #findElement}. Use + * <code>java.awt.Robot</code> to click the element. Return + * immediately after clicking the element.</p> + + */ + + public void clickElement(String id) { + Element element = findElement(id); + if (null != element) { + clickElement(element); + } + } + + + /** + + * <p>Find the DOM element within the current page matching the + * argument <code>id</code> using [EMAIL PROTECTED] #findElement}. Use * <code>java.awt.Robot</code> to click the element. Block until the * document load triggered by the click has completed.</p> */ - public void blockingClickElement(String idOrName) { + public void blockingClickElement(Element element) { synchronized (this) { try { - clickElement(idOrName); + createLatch(); + clickElement(element); lockLatch(); } catch (InterruptedException ie) { @@ -488,6 +586,23 @@ /** + * <p>Find the DOM element within the current page matching the + * argument <code>id</code> using [EMAIL PROTECTED] #findElement}. Use + * <code>java.awt.Robot</code> to click the element. Block until the + * document load triggered by the click has completed.</p> + + */ + + + public void blockingClickElement(String idOrName) { + Element element = findElement(idOrName); + if (null != element) { + blockingClickElement(element); + } + } + + /** + * <p>Load the url, blocking until the load has completed.</p> */ _______________________________________________ dev-embedding mailing list dev-embedding@lists.mozilla.org https://lists.mozilla.org/listinfo/dev-embedding