|
[HtmlUnit] CVS Commit: src/xdocs: Implemented window.setTimeout(function, : msg#00057java.htmlunit.devel
Log Message: ----------- Implemented window.setTimeout(function, int) and window.setInterval(function, int) Modified Files: -------------- htmlunit/src/java/com/gargoylesoftware/htmlunit/html: HtmlPage.java (http://cvs.sourceforge.net/viewcvs.py/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java) htmlunit/src/xdocs: changes.xml (http://cvs.sourceforge.net/viewcvs.py/htmlunit/htmlunit/src/xdocs/changes.xml) htmlunit/src/java/com/gargoylesoftware/htmlunit/javascript/host: JavaScriptBackgroundJob.java (http://cvs.sourceforge.net/viewcvs.py/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/javascript/host/JavaScriptBackgroundJob.java) Window.java (http://cvs.sourceforge.net/viewcvs.py/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java) htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host: WindowTest.java (http://cvs.sourceforge.net/viewcvs.py/htmlunit/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/WindowTest.java) Revision Data ------------- Index: JavaScriptBackgroundJob.java =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/javascript/host/JavaScriptBackgroundJob.java,v retrieving revision 1.2 retrieving revision 1.3 diff -Lsrc/java/com/gargoylesoftware/htmlunit/javascript/host/JavaScriptBackgroundJob.java -Lsrc/java/com/gargoylesoftware/htmlunit/javascript/host/JavaScriptBackgroundJob.java -u -d -r1.2 -r1.3 --- src/java/com/gargoylesoftware/htmlunit/javascript/host/JavaScriptBackgroundJob.java +++ src/java/com/gargoylesoftware/htmlunit/javascript/host/JavaScriptBackgroundJob.java @@ -39,6 +39,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.mozilla.javascript.Function; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebWindow; @@ -59,6 +60,7 @@ private final int timeout_; private final String script_; private final boolean loopForever_; + private final Function function_; JavaScriptBackgroundJob(final Window window, final int timeout, final String script, final boolean loopForever) { @@ -66,13 +68,27 @@ timeout_ = timeout; loopForever_ = loopForever; script_ = script; + function_ = null; + } + JavaScriptBackgroundJob(final Window window, final int timeout, final Function function, + final boolean loopForever) { + window_ = window; + timeout_ = timeout; + loopForever_ = loopForever; + script_ = null; + function_ = function; } public void run() { final Page page = window_.getWebWindow().getEnclosedPage(); try { do { Thread.sleep(timeout_); - getLog().debug("Executing JavaScriptBackgroundJob: " + script_); + if (function_ == null) { + getLog().debug("Executing JavaScriptBackgroundJob: " + script_); + } + else { + getLog().debug("Executing JavaScriptBackgroundJob: (function reference) "); + } final WebWindow webWindow = window_.getWebWindow(); // test that the window is always opened and the page the same @@ -86,11 +102,20 @@ } final HtmlPage htmlPage = (HtmlPage) window_.getWebWindow().getEnclosedPage(); - htmlPage.executeJavaScriptIfPossible( - script_, - "JavaScriptBackgroundJob", - true, - htmlPage.getDocumentElement()); + if (function_ == null) { + htmlPage.executeJavaScriptIfPossible( + script_, + "JavaScriptBackgroundJob", + true, + htmlPage.getDocumentElement()); + } + else { + htmlPage.executeJavaScriptFunctionIfPossible( + function_, + window_, + new Object[0], + htmlPage.getDocumentElement()); + } } while (loopForever_); } Index: Window.java =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java,v retrieving revision 1.85 retrieving revision 1.86 diff -Lsrc/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java -Lsrc/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java -u -d -r1.85 -r1.86 --- src/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java +++ src/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java @@ -234,22 +234,57 @@ return null; } } - + + /** + * Makes the job object for setTimeout and setInterval + * + * @param codeToExec either a Function or a String of the javascript code + * @param timeout time to wait + * @param thisWindow the window to associate the thread with + * @param loopForever if the thread should keep looping (setTimeout vs setInterval) + * @return + */ + private static JavaScriptBackgroundJob createJavaScriptBackgroundJob(final Object codeToExec, + final int timeout, final Window thisWindow, final boolean loopForever) { + if (codeToExec == null) { + throw Context.reportRuntimeError("Function not provided"); + } + else if (codeToExec instanceof String) { + final String scriptString = (String) codeToExec; + return new JavaScriptBackgroundJob(thisWindow, timeout, scriptString, loopForever); + } + else if (codeToExec instanceof Function) { + final Function scriptFunction = (Function) codeToExec; + return new JavaScriptBackgroundJob(thisWindow, timeout, scriptFunction, loopForever); + } + else { + throw Context.reportRuntimeError("Unknown type for function"); + } + } /** * Set a chunk of javascript to be invoked at some specified time later. * The invocation occurs only if the window is opened after the delay * and does not contain an other page than the one that originated the setTimeout. - * - * @param script the code to execute - * @param timeout the delay in milliseconds to wait before executing the code + * + * JavaScript param 1: The code to execute, either a String or a Function. + * JavaScript param 2: the delay in milliseconds to wait before executing the code. + * + * @param context The javascript Context + * @param scriptable The object that the function was called on. + * @param args The arguments passed to the function. + * @param function The function object that was invoked. * @return the id of the created timer */ - public int jsxFunction_setTimeout(final String script, final int timeout) { - final Runnable setTimeoutThread = new JavaScriptBackgroundJob(this, timeout, script, false); - final int id = getWebWindow().getThreadManager().startThread(setTimeoutThread); + public static int jsxFunction_setTimeout(final Context context, final Scriptable scriptable, + final Object[] args, final Function function) { + final Window thisWindow = (Window) scriptable; + final Object codeToExec = getObjectArg(0, args, null); + final int timeout = getIntArg(1, args, 0); + final Runnable job = createJavaScriptBackgroundJob(codeToExec, timeout, thisWindow, false); + final int id = thisWindow.getWebWindow().getThreadManager().startThread(job); return id; - } + } /** * Cancels a time-out previously set with the <tt>setTimeout</tt> method. @@ -710,16 +745,27 @@ /** * Set a chunk of javascript to be invoked each time a specified number of milliseconds has elapsed * Current implementation does nothing. - - * @param script the code to execute - * @param timeout the delay in milliseconds to wait before executing the code - * @return the id of the created interval + * + * JavaScript param 1: The code to execute, either a String or a Function. + * JavaScript param 2: the delay in milliseconds to wait before executing the code. + * * @see <a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/setinterval.asp"> * MSDN documentation</a> + * + * @param context The javascript Context + * @param scriptable The object that the function was called on. + * @param args The arguments passed to the function. + * @param function The function object that was invoked. + * @return the id of the created interval */ - public int jsxFunction_setInterval(final String script, final int timeout) { - final Runnable setTimeoutThread = new JavaScriptBackgroundJob(this, timeout, script, true); - final int id = getWebWindow().getThreadManager().startThread(setTimeoutThread); + public static int jsxFunction_setInterval(final Context context, final Scriptable scriptable, + final Object[] args, final Function function) { + final Window thisWindow = (Window) scriptable; + final Object codeToExec = getObjectArg(0, args, null); + final int timeout = getIntArg(1, args, 0); + + final Runnable job = createJavaScriptBackgroundJob(codeToExec, timeout, thisWindow, true); + final int id = thisWindow.getWebWindow().getThreadManager().startThread(job); return id; } Index: changes.xml =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/xdocs/changes.xml,v retrieving revision 1.494 retrieving revision 1.495 diff -Lsrc/xdocs/changes.xml -Lsrc/xdocs/changes.xml -u -d -r1.494 -r1.495 --- src/xdocs/changes.xml +++ src/xdocs/changes.xml @@ -8,6 +8,9 @@ <body> <release version="next"> <action type="update" dev="yourgod"> + Implemented window.setTimeout(function, int) and window.setInterval(function, int) + </action> + <action type="update" dev="yourgod"> HtmlOption.asText() now respects the label attribute as browsers do. </action> <action type="update" dev="mguillem" id="1437068"> Index: HtmlPage.java =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java,v retrieving revision 1.135 retrieving revision 1.136 diff -Lsrc/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java -Lsrc/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java -u -d -r1.135 -r1.136 --- src/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java +++ src/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java @@ -705,6 +705,8 @@ } /** + * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br/> + * * Execute a Function in the given context. * * @param function The javascript Function to call. @@ -716,7 +718,7 @@ * @return A ScriptResult which will contain both the current page (which may be different than * the previous page and a javascript result object. */ - ScriptResult executeJavaScriptFunctionIfPossible( + public ScriptResult executeJavaScriptFunctionIfPossible( final Function function, final Scriptable thisObject, final Object[] args, @@ -748,7 +750,8 @@ } /** - * Internal use only. + * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br/> + * * @param srcAttribute The source attribute from the script tag. * @param charset The charset attribute from the script tag. */ @@ -773,7 +776,9 @@ } /** - * Internal use only. Return true if a script with the specified type and language attributes + * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br/> + * + * Return true if a script with the specified type and language attributes * is actually JavaScript. * According to <a href="http://www.w3.org/TR/REC-html40/types.html#h-6.7">W3C recommendation</a> * are content types case insensitive. @@ -1366,7 +1371,8 @@ } /** - * For internal used only + * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br/> + * * @param node the node that has just been added to the document. */ void notifyNodeAdded(final DomNode node) { @@ -1381,7 +1387,8 @@ } /** - * For internal used only + * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br/> + * * @param node the node that has just been removed from the tree */ void notifyNodeRemoved(final DomNode node) { Index: WindowTest.java =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/javascript/host/WindowTest.java,v retrieving revision 1.57 retrieving revision 1.58 diff -Lsrc/test/java/com/gargoylesoftware/htmlunit/javascript/host/WindowTest.java -Lsrc/test/java/com/gargoylesoftware/htmlunit/javascript/host/WindowTest.java -u -d -r1.57 -r1.58 --- src/test/java/com/gargoylesoftware/htmlunit/javascript/host/WindowTest.java +++ src/test/java/com/gargoylesoftware/htmlunit/javascript/host/WindowTest.java @@ -51,6 +51,7 @@ import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.PromptHandler; import com.gargoylesoftware.htmlunit.StatusHandler; +import com.gargoylesoftware.htmlunit.ThreadManager; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.WebTestCase; import com.gargoylesoftware.htmlunit.WebWindow; @@ -760,6 +761,21 @@ assertTrue("thread failed to stop in 1 second", page.getEnclosingWindow().getThreadManager().joinAll(1000)); assertEquals(Collections.singletonList("Yo!"), collectedAlerts); } + + /** + * @throws Exception If the test fails + */ + public void testSetTimeoutByReference() throws Exception { + final String content = "<html><body><script language='JavaScript'>" + + "function doTimeout() { alert('Yo!'); }" + + "window.setTimeout(doTimeout,1);" + + "</script></body></html>"; + + final List collectedAlerts = Collections.synchronizedList(new ArrayList()); + final HtmlPage page = loadPage(content, collectedAlerts); + assertTrue("thread failed to stop in 1 second", page.getEnclosingWindow().getThreadManager().joinAll(1000)); + assertEquals(Collections.singletonList("Yo!"), collectedAlerts); + } /** * Just tests that setting and clearing an interval doesn't throw @@ -778,6 +794,39 @@ final List collectedAlerts = Collections.synchronizedList(new ArrayList()); loadPage(content, collectedAlerts); } + + /** + * @throws Exception If the test fails + */ + public void testSetIntervalFunctionReference() throws Exception { + final String content = "<html>\n" + + "<head>\n" + + " <title>test</title>\n" + + " <script>\n" + + " var threadID;\n" + + " function test() {\n" + + " threadID = setInterval(doAlert, 100);\n" + + " }\n" + + " var iterationNumber=0;" + + " function doAlert() {\n" + + " alert('blah');\n" + + " if (++iterationNumber >= 3) {" + + " clearInterval(threadID);" + + " }" + + " }\n" + + " </script>\n" + + "</head>\n" + + "<body onload='test()'>\n" + + "</body>\n" + + "</html>"; + + final List collectedAlerts = Collections.synchronizedList(new ArrayList()); + final HtmlPage page = loadPage(content, collectedAlerts); + final ThreadManager threadManager = page.getEnclosingWindow().getThreadManager(); + threadManager.joinAll(1000); + assertEquals(0, threadManager.activeCount()); + assertEquals(Collections.nCopies(3, "blah"), collectedAlerts); + } /** * Test that a script started by a timer is stopped if the page that started it ------------------------------------------------------- This SF.Net email is sponsored by xPML, a groundbreaking scripting language that extends applications into web and mobile media. Attend the live webcast and join the prime developer group breaking into this new coding territory! http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642
|
|
| <Prev in Thread] | Current Thread | [Next in Thread> |
|---|---|---|
| Previous by Date: | [HtmlUnit] CVS Commit: WebConnectionImpl.java: made public so it can be extended, yourgod |
|---|---|
| Next by Date: | [HtmlUnit] [ htmlunit-Bugs-1433566 ] Htmlunit as a maven 2.0 dependecies fails, SourceForge.net |
| Previous by Thread: | [HtmlUnit] CVS Commit: WebConnectionImpl.java: made public so it can be extended, yourgod |
| Next by Thread: | [HtmlUnit] [ htmlunit-Bugs-1309064 ] JavaScript Undefined, SourceForge.net |
| Indexes: | [Date] [Thread] [Top] [All Lists] |
| News | FAQ | advertise |