From: <rb...@us...> - 2018-06-29 19:51:30
|
Revision: 15418 http://sourceforge.net/p/htmlunit/code/15418 Author: rbri Date: 2018-06-29 19:51:23 +0000 (Fri, 29 Jun 2018) Log Message: ----------- Correct handling of additional parameters provided in functions setTimeout/setInterval. Issue 1966 Modified Paths: -------------- trunk/htmlunit/src/changes/changes.xml trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/background/BackgroundJavaScriptFactory.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/background/JavaScriptFunctionJob.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java Modified: trunk/htmlunit/src/changes/changes.xml =================================================================== --- trunk/htmlunit/src/changes/changes.xml 2018-06-29 17:33:58 UTC (rev 15417) +++ trunk/htmlunit/src/changes/changes.xml 2018-06-29 19:51:23 UTC (rev 15418) @@ -14,6 +14,9 @@ <action type="remove" dev="rbri"> FF45 support removed. </action> + <action type="fix" dev="rbri" issue="1966" due-to="Atsushi Nakagawa"> + Correct handling of additional parameters provided in functions setTimeout/setInterval. + </action> <action type="fix" dev="rbri" issue="1964"> NPE in HtmlTextArea.removeFocus(). </action> Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/background/BackgroundJavaScriptFactory.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/background/BackgroundJavaScriptFactory.java 2018-06-29 17:33:58 UTC (rev 15417) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/background/BackgroundJavaScriptFactory.java 2018-06-29 19:51:23 UTC (rev 15418) @@ -28,6 +28,7 @@ * JavaScript engine. * * @author Ronald Brill + * @author Atsushi Nakagawa */ public class BackgroundJavaScriptFactory { @@ -73,13 +74,14 @@ * @param label the label for the job * @param window the window to which the job belongs * @param function the JavaScript code to execute + * @param args the arguments to pass into the function call * * @return JavaScriptJob the created job */ public JavaScriptFunctionJob createJavaScriptJob(final int initialDelay, final Integer period, final String label, - final WebWindow window, final Function function) { - return new JavaScriptFunctionJob(initialDelay, period, label, window, function); + final WebWindow window, final Function function, final Object[] args) { + return new JavaScriptFunctionJob(initialDelay, period, label, window, function, args); } /** Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/background/JavaScriptFunctionJob.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/background/JavaScriptFunctionJob.java 2018-06-29 17:33:58 UTC (rev 15417) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/background/JavaScriptFunctionJob.java 2018-06-29 19:51:23 UTC (rev 15418) @@ -24,11 +24,14 @@ /** * A {@link JavaScriptJob} created from a {@link Function} object. * @author Brad Clarke + * @author Ronald Brill + * @author Atsushi Nakagawa */ class JavaScriptFunctionJob extends JavaScriptExecutionJob { /** The JavaScript code to execute. */ private final Function function_; + private final Object[] args_; /** * Creates a new JavaScript execution job, where the JavaScript code to execute is a function. @@ -37,11 +40,13 @@ * @param label the label for the job * @param window the window to which the job belongs * @param function the JavaScript code to execute + * @param args the arguments to pass into the function call */ JavaScriptFunctionJob(final int initialDelay, final Integer period, final String label, - final WebWindow window, final Function function) { + final WebWindow window, final Function function, final Object[] args) { super(initialDelay, period, label, window); function_ = function; + args_ = args; } /** {@inheritDoc} */ @@ -49,7 +54,7 @@ protected void runJavaScript(final HtmlPage page) { final DomElement doc = page.getDocumentElement(); final Scriptable scriptable = page.getEnclosingWindow().getScriptableObject(); - page.executeJavaScriptFunction(function_, scriptable, new Object[0], doc); + page.executeJavaScriptFunction(function_, scriptable, args_, doc); } } Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java 2018-06-29 17:33:58 UTC (rev 15417) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/Window.java 2018-06-29 19:51:23 UTC (rev 15418) @@ -24,8 +24,8 @@ import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.CHROME; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.EDGE; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF; +import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF52; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF60; -import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.FF52; import static com.gargoylesoftware.htmlunit.javascript.configuration.SupportedBrowser.IE; import java.io.IOException; @@ -155,6 +155,7 @@ * @author Frank Danek * @author Carsten Steul * @author Colin Alworth + * @author Atsushi Nakagawa * @see <a href="http://msdn.microsoft.com/en-us/library/ms535873.aspx">MSDN documentation</a> */ @JsxClass @@ -483,32 +484,77 @@ * 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 code specifies the function pointer or string that indicates the code to be executed - * when the specified interval has elapsed - * @param timeout specifies the number of milliseconds - * @param language specifies language + * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout"> + * MDN web docs</a> + * + * @param context the JavaScript context + * @param thisObj the scriptable + * @param args the arguments passed into the method + * @param function the function * @return the id of the created timer */ @JsxFunction - public int setTimeout(final Object code, int timeout, final Object language) { + public static Object setTimeout(final Context context, final Scriptable thisObj, + final Object[] args, final Function function) { + if (args.length < 1) { + throw ScriptRuntime.typeError("Function not provided"); + } + + final int timeout = ScriptRuntime.toInt32((args.length > 1) ? args[1] : Undefined.instance); + final Object[] params = (args.length > 2) + ? Arrays.copyOfRange(args, 2, args.length) + : ScriptRuntime.emptyArgs; + return ((Window) thisObj).setTimeoutIntervalImpl(args[0], timeout, true, params); + } + + /** + * Sets a chunk of JavaScript to be invoked each time a specified number of milliseconds has elapsed. + * + * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval"> + * MDN web docs</a> + * @param context the JavaScript context + * @param thisObj the scriptable + * @param args the arguments passed into the method + * @param function the function + * @return the id of the created interval + */ + @JsxFunction + public static Object setInterval(final Context context, final Scriptable thisObj, + final Object[] args, final Function function) { + if (args.length < 1) { + throw ScriptRuntime.typeError("Function not provided"); + } + + final int timeout = ScriptRuntime.toInt32((args.length > 1) ? args[1] : Undefined.instance); + final Object[] params = (args.length > 2) + ? Arrays.copyOfRange(args, 2, args.length) + : ScriptRuntime.emptyArgs; + return ((Window) thisObj).setTimeoutIntervalImpl(args[0], timeout, false, params); + } + + private int setTimeoutIntervalImpl(final Object code, int timeout, final boolean isTimeout, final Object[] params) { if (timeout < MIN_TIMER_DELAY) { timeout = MIN_TIMER_DELAY; } - if (code == null) { - throw Context.reportRuntimeError("Function not provided."); - } - final int id; final WebWindow webWindow = getWebWindow(); final Page page = (Page) getDomNodeOrNull(); + Integer period = null; + if (!isTimeout) { + period = Integer.valueOf(timeout); + } + if (code instanceof String) { final String s = (String) code; - final String description = "window.setTimeout(" + s + ", " + timeout + ")"; + final String description = "window.set" + + (isTimeout ? "Timeout" : "Interval") + + "(" + s + ", " + timeout + ")"; final JavaScriptJob job = BackgroundJavaScriptFactory.theFactory(). - createJavaScriptJob(timeout, null, description, webWindow, s); - id = webWindow.getJobManager().addJob(job, page); + createJavaScriptJob(timeout, period, description, webWindow, s); + return webWindow.getJobManager().addJob(job, page); } - else if (code instanceof Function) { + + if (code instanceof Function) { final Function f = (Function) code; final String functionName; if (f instanceof FunctionObject) { @@ -518,15 +564,15 @@ functionName = String.valueOf(f); // can this happen? } - final String description = "window.setTimeout(" + functionName + ", " + timeout + ")"; + final String description = "window.set" + + (isTimeout ? "Timeout" : "Interval") + + "(" + functionName + ", " + timeout + ")"; final JavaScriptJob job = BackgroundJavaScriptFactory.theFactory(). - createJavaScriptJob(timeout, null, description, webWindow, f); - id = webWindow.getJobManager().addJob(job, page); + createJavaScriptJob(timeout, period, description, webWindow, f, params); + return webWindow.getJobManager().addJob(job, page); } - else { - throw Context.reportRuntimeError("Unknown type for function."); - } - return id; + + throw Context.reportRuntimeError("Unknown type for function."); } /** @@ -543,6 +589,21 @@ } /** + * Cancels the interval previously started using the {@link #setInterval(Object, int, Object)} method. + * Current implementation does nothing. + * @param intervalID specifies the interval to cancel as returned by the + * {@link #setInterval(Object, int, Object)} method + * @see <a href="http://msdn.microsoft.com/en-us/library/ms536353.aspx">MSDN documentation</a> + */ + @JsxFunction + public void clearInterval(final int intervalID) { + if (LOG.isDebugEnabled()) { + LOG.debug("clearInterval(" + intervalID + ")"); + } + getWebWindow().getJobManager().removeJob(intervalID); + } + + /** * Returns the JavaScript property {@code navigator}. * @return the navigator */ @@ -1487,61 +1548,6 @@ } /** - * Sets a chunk of JavaScript to be invoked each time a specified number of milliseconds has elapsed. - * - * @see <a href="http://msdn.microsoft.com/en-us/library/ms536749.aspx">MSDN documentation</a> - * @param code specifies the function pointer or string that indicates the code to be executed - * when the specified interval has elapsed - * @param timeout specifies the number of milliseconds - * @param language specifies language - * @return the id of the created interval - */ - @JsxFunction - public int setInterval(final Object code, int timeout, final Object language) { - if (timeout < MIN_TIMER_DELAY) { - timeout = MIN_TIMER_DELAY; - } - final int id; - final WebWindow w = getWebWindow(); - final Page page = (Page) getDomNodeOrNull(); - final String description = "window.setInterval(" + timeout + ")"; - if (code == null) { - throw Context.reportRuntimeError("Function not provided."); - } - else if (code instanceof String) { - final String s = (String) code; - final JavaScriptJob job = BackgroundJavaScriptFactory.theFactory(). - createJavaScriptJob(timeout, Integer.valueOf(timeout), description, w, s); - id = w.getJobManager().addJob(job, page); - } - else if (code instanceof Function) { - final Function f = (Function) code; - final JavaScriptJob job = BackgroundJavaScriptFactory.theFactory(). - createJavaScriptJob(timeout, Integer.valueOf(timeout), description, w, f); - id = w.getJobManager().addJob(job, page); - } - else { - throw Context.reportRuntimeError("Unknown type for function."); - } - return id; - } - - /** - * Cancels the interval previously started using the {@link #setInterval(Object, int, Object)} method. - * Current implementation does nothing. - * @param intervalID specifies the interval to cancel as returned by the - * {@link #setInterval(Object, int, Object)} method - * @see <a href="http://msdn.microsoft.com/en-us/library/ms536353.aspx">MSDN documentation</a> - */ - @JsxFunction - public void clearInterval(final int intervalID) { - if (LOG.isDebugEnabled()) { - LOG.debug("clearInterval(" + intervalID + ")"); - } - getWebWindow().getJobManager().removeJob(intervalID); - } - - /** * Returns the {@code innerWidth}. * @return the {@code innerWidth} * @see <a href="http://www.mozilla.org/docs/dom/domref/dom_window_ref28.html">Mozilla doc</a> |