use of com.gargoylesoftware.htmlunit.javascript.host.Window in project htmlunit by HtmlUnit.
the class HtmlPage method executeEventHandlersIfNeeded.
/**
* Looks for and executes any appropriate event handlers. Looks for body and frame tags.
* @param eventType either {@link Event#TYPE_LOAD}, {@link Event#TYPE_UNLOAD}, or {@link Event#TYPE_BEFORE_UNLOAD}
* @return {@code true} if user accepted <tt>onbeforeunload</tt> (not relevant to other events)
*/
private boolean executeEventHandlersIfNeeded(final String eventType) {
// If JavaScript isn't enabled, there's nothing for us to do.
if (!getWebClient().isJavaScriptEnabled()) {
return true;
}
// Execute the specified event on the document element.
final WebWindow window = getEnclosingWindow();
if (window.getScriptableObject() instanceof Window) {
final Event event;
if (eventType.equals(Event.TYPE_BEFORE_UNLOAD)) {
event = new BeforeUnloadEvent(this, eventType);
} else {
event = new Event(this, eventType);
}
// here so it could be used with HtmlPage.
if (LOG.isDebugEnabled()) {
LOG.debug("Firing " + event);
}
final EventTarget jsNode;
if (Event.TYPE_DOM_DOCUMENT_LOADED.equals(eventType)) {
jsNode = this.getScriptableObject();
} else {
// The load/beforeunload/unload events target Document but paths Window only (tested in Chrome/FF)
jsNode = window.getScriptableObject();
}
final HtmlUnitContextFactory cf = ((JavaScriptEngine) getWebClient().getJavaScriptEngine()).getContextFactory();
cf.callSecured(cx -> jsNode.fireEvent(event), this);
if (!isOnbeforeunloadAccepted(this, event)) {
return false;
}
}
// If this page was loaded in a frame, execute the version of the event specified on the frame tag.
if (window instanceof FrameWindow) {
final FrameWindow fw = (FrameWindow) window;
final BaseFrameElement frame = fw.getFrameElement();
// if part of a document fragment, then the load event is not triggered
if (Event.TYPE_LOAD.equals(eventType) && frame.getParentNode() instanceof DomDocumentFragment) {
return true;
}
if (frame.hasEventHandlers("on" + eventType)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Executing on" + eventType + " handler for " + frame);
}
if (window.getScriptableObject() instanceof Window) {
final Event event;
if (Event.TYPE_BEFORE_UNLOAD.equals(eventType)) {
event = new BeforeUnloadEvent(frame, eventType);
} else {
// ff does not trigger the onload event in this case
if (PageDenied.BY_CONTENT_SECURIRY_POLICY == fw.getPageDenied() && hasFeature(JS_EVENT_LOAD_SUPPRESSED_BY_CONTENT_SECURIRY_POLICY)) {
return true;
}
event = new Event(frame, eventType);
}
// This fires the "load" event for the <frame> element which, like all non-window
// load events, propagates up to Document but not Window. The "load" event for
// <frameset> on the other hand, like that of <body>, is handled above where it is
// fired against Document and directed to Window.
frame.fireEvent(event);
if (!isOnbeforeunloadAccepted((HtmlPage) frame.getPage(), event)) {
return false;
}
}
}
}
return true;
}
use of com.gargoylesoftware.htmlunit.javascript.host.Window in project htmlunit by HtmlUnit.
the class HTMLDocument method setActiveElement.
/**
* Sets the specified element as the document's active element.
* @see HTMLElement#setActive()
* @param element the new active element for this document
*/
public void setActiveElement(final HTMLElement element) {
// TODO update page focus element also
activeElement_ = element;
if (element != null) {
// if this is part of an iFrame, make the iFrame tag the
// active element of his doc
final WebWindow window = element.getDomNodeOrDie().getPage().getEnclosingWindow();
if (window instanceof FrameWindow) {
final BaseFrameElement frame = ((FrameWindow) window).getFrameElement();
if (frame instanceof HtmlInlineFrame) {
final Window winWithFrame = frame.getPage().getEnclosingWindow().getScriptableObject();
((HTMLDocument) winWithFrame.getDocument()).setActiveElement(frame.getScriptableObject());
}
}
}
}
use of com.gargoylesoftware.htmlunit.javascript.host.Window in project htmlunit by HtmlUnit.
the class History method goToUrlAtCurrentIndex.
/**
* Loads the URL at the current index into the window to which this navigation history belongs.
* @throws IOException if an IO error occurs
*/
private void goToUrlAtCurrentIndex() throws IOException {
final Boolean old = ignoreNewPages_.get();
ignoreNewPages_.set(Boolean.TRUE);
try {
final HistoryEntry entry = entries_.get(index_);
final Page page = entry.getPage();
if (page == null) {
window_.getWebClient().getPage(window_, entry.getWebRequest(), false);
} else {
window_.setEnclosedPage(page);
page.getWebResponse().getWebRequest().setUrl(entry.getUrl());
}
final Window jsWindow = window_.getScriptableObject();
if (jsWindow != null && jsWindow.hasEventHandlers("onpopstate")) {
final Event event = new PopStateEvent(jsWindow, Event.TYPE_POPSTATE, entry.getState());
jsWindow.executeEventLocally(event);
}
} finally {
ignoreNewPages_.set(old);
}
}
use of com.gargoylesoftware.htmlunit.javascript.host.Window in project htmlunit by HtmlUnit.
the class JavaScriptEngine method handleJavaScriptException.
/**
* Handles an exception that occurred during execution of JavaScript code.
* @param scriptException the exception
* @param triggerOnError if true, this triggers the onerror handler
*/
protected void handleJavaScriptException(final ScriptException scriptException, final boolean triggerOnError) {
// shutdown was already called
final WebClient webClient = getWebClient();
if (webClient == null) {
if (LOG.isInfoEnabled()) {
LOG.info("handleJavaScriptException('" + scriptException.getMessage() + "') called after the shutdown of the Javascript engine - exception ignored.");
}
return;
}
// Trigger window.onerror, if it has been set.
final HtmlPage page = scriptException.getPage();
if (triggerOnError && page != null) {
final WebWindow window = page.getEnclosingWindow();
if (window != null) {
final Window w = window.getScriptableObject();
if (w != null) {
try {
w.triggerOnError(scriptException);
} catch (final Exception e) {
handleJavaScriptException(new ScriptException(page, e, null), false);
}
}
}
}
webClient.getJavaScriptErrorListener().scriptException(page, scriptException);
// Throw a Java exception if the user wants us to.
if (webClient.getOptions().isThrowExceptionOnScriptError()) {
throw scriptException;
}
}
use of com.gargoylesoftware.htmlunit.javascript.host.Window in project htmlunit by HtmlUnit.
the class JavaScriptEngine method init.
/**
* Initializes all the JS stuff for the window.
* @param webWindow the web window
* @param context the current context
* @throws Exception if something goes wrong
*/
private void init(final WebWindow webWindow, final Page page, final Context context) throws Exception {
final WebClient webClient = webWindow.getWebClient();
final BrowserVersion browserVersion = webClient.getBrowserVersion();
final Window window = new Window();
window.setClassName("Window");
context.initSafeStandardObjects(window);
final ClassConfiguration windowConfig = jsConfig_.getClassConfiguration("Window");
if (windowConfig.getJsConstructor() != null) {
final FunctionObject functionObject = new RecursiveFunctionObject("Window", windowConfig.getJsConstructor(), window);
ScriptableObject.defineProperty(window, "constructor", functionObject, ScriptableObject.DONTENUM | ScriptableObject.PERMANENT | ScriptableObject.READONLY);
} else {
defineConstructor(window, window, new Window());
}
// remove some objects, that Rhino defines in top scope but that we don't want
deleteProperties(window, "Continuation", "Iterator", "StopIteration", "BigInt");
if (!browserVersion.hasFeature(JS_PROMISE)) {
deleteProperties(window, "Promise");
}
if (!browserVersion.hasFeature(JS_SYMBOL)) {
deleteProperties(window, "Symbol");
}
final ScriptableObject errorObject = (ScriptableObject) ScriptableObject.getProperty(window, "Error");
if (browserVersion.hasFeature(JS_ERROR_STACK_TRACE_LIMIT)) {
errorObject.defineProperty("stackTraceLimit", 10, ScriptableObject.EMPTY);
} else {
ScriptableObject.deleteProperty(errorObject, "stackTraceLimit");
}
if (!browserVersion.hasFeature(JS_ERROR_CAPTURE_STACK_TRACE)) {
ScriptableObject.deleteProperty(errorObject, "captureStackTrace");
}
if (browserVersion.hasFeature(JS_URL_SEARCH_PARMS_ITERATOR_SIMPLE_NAME)) {
URLSearchParams.NativeParamsIterator.init(window, "Iterator");
} else {
URLSearchParams.NativeParamsIterator.init(window, "URLSearchParams Iterator");
}
if (browserVersion.hasFeature(JS_FORM_DATA_ITERATOR_SIMPLE_NAME)) {
FormData.FormDataIterator.init(window, "Iterator");
} else {
FormData.FormDataIterator.init(window, "FormData Iterator");
}
final Intl intl = new Intl();
intl.setParentScope(window);
window.defineProperty(intl.getClassName(), intl, ScriptableObject.DONTENUM);
if (browserVersion.hasFeature(JS_INTL_NAMED_OBJECT)) {
intl.setClassName("Object");
}
intl.defineProperties(browserVersion);
if (browserVersion.hasFeature(JS_REFLECT)) {
final Reflect reflect = new Reflect();
reflect.setParentScope(window);
window.defineProperty(reflect.getClassName(), reflect, ScriptableObject.DONTENUM);
}
final Map<Class<? extends Scriptable>, Scriptable> prototypes = new HashMap<>();
final Map<String, Scriptable> prototypesPerJSName = new HashMap<>();
final String windowClassName = Window.class.getName();
for (final ClassConfiguration config : jsConfig_.getAll()) {
final boolean isWindow = windowClassName.equals(config.getHostClass().getName());
if (isWindow) {
configureConstantsPropertiesAndFunctions(config, window);
final HtmlUnitScriptable prototype = configureClass(config, window, browserVersion);
prototypesPerJSName.put(config.getClassName(), prototype);
} else {
final HtmlUnitScriptable prototype = configureClass(config, window, browserVersion);
if (config.isJsObject()) {
// Place object with prototype property in Window scope
final HtmlUnitScriptable obj = config.getHostClass().newInstance();
prototype.defineProperty("__proto__", prototype, ScriptableObject.DONTENUM);
// but not setPrototype!
obj.defineProperty("prototype", prototype, ScriptableObject.DONTENUM);
obj.setParentScope(window);
obj.setClassName(config.getClassName());
ScriptableObject.defineProperty(window, obj.getClassName(), obj, ScriptableObject.DONTENUM);
// this obj won't have prototype, constants need to be configured on it again
configureConstants(config, obj);
}
prototypes.put(config.getHostClass(), prototype);
prototypesPerJSName.put(config.getClassName(), prototype);
}
}
for (final ClassConfiguration config : jsConfig_.getAll()) {
final Executable jsConstructor = config.getJsConstructor();
final String jsClassName = config.getClassName();
Scriptable prototype = prototypesPerJSName.get(jsClassName);
final String hostClassSimpleName = config.getHostClassSimpleName();
if ("Image".equals(hostClassSimpleName)) {
prototype = prototypesPerJSName.get("HTMLImageElement");
}
if ("Option".equals(hostClassSimpleName)) {
prototype = prototypesPerJSName.get("HTMLOptionElement");
}
switch(hostClassSimpleName) {
case "WebKitMutationObserver":
prototype = prototypesPerJSName.get("MutationObserver");
break;
case "webkitURL":
prototype = prototypesPerJSName.get("URL");
break;
default:
}
if (prototype != null && config.isJsObject()) {
if (jsConstructor == null) {
final ScriptableObject constructor;
if ("Window".equals(jsClassName)) {
constructor = (ScriptableObject) ScriptableObject.getProperty(window, "constructor");
} else {
constructor = config.getHostClass().newInstance();
((HtmlUnitScriptable) constructor).setClassName(config.getClassName());
}
defineConstructor(window, prototype, constructor);
configureConstantsStaticPropertiesAndStaticFunctions(config, constructor);
} else {
final BaseFunction function;
if ("Window".equals(jsClassName)) {
function = (BaseFunction) ScriptableObject.getProperty(window, "constructor");
} else {
function = new RecursiveFunctionObject(jsClassName, jsConstructor, window);
}
if ("WebKitMutationObserver".equals(hostClassSimpleName) || "webkitURL".equals(hostClassSimpleName) || "Image".equals(hostClassSimpleName) || "Option".equals(hostClassSimpleName)) {
final Object prototypeProperty = ScriptableObject.getProperty(window, prototype.getClassName());
if (function instanceof FunctionObject) {
try {
((FunctionObject) function).addAsConstructor(window, prototype);
} catch (final Exception e) {
// TODO see issue #1897
if (LOG.isWarnEnabled()) {
final String newline = System.lineSeparator();
LOG.warn("Error during JavaScriptEngine.init(WebWindow, Context)" + newline + e.getMessage() + newline + "prototype: " + prototype.getClassName());
}
}
}
ScriptableObject.defineProperty(window, hostClassSimpleName, function, ScriptableObject.DONTENUM);
// so we restore its value
if (!hostClassSimpleName.equals(prototype.getClassName())) {
if (prototypeProperty == UniqueTag.NOT_FOUND) {
ScriptableObject.deleteProperty(window, prototype.getClassName());
} else {
ScriptableObject.defineProperty(window, prototype.getClassName(), prototypeProperty, ScriptableObject.DONTENUM);
}
}
} else {
if (function instanceof FunctionObject) {
try {
((FunctionObject) function).addAsConstructor(window, prototype);
} catch (final Exception e) {
// TODO see issue #1897
if (LOG.isWarnEnabled()) {
final String newline = System.lineSeparator();
LOG.warn("Error during JavaScriptEngine.init(WebWindow, Context)" + newline + e.getMessage() + newline + "prototype: " + prototype.getClassName());
}
}
}
}
configureConstantsStaticPropertiesAndStaticFunctions(config, function);
}
}
}
window.setPrototype(prototypesPerJSName.get(Window.class.getSimpleName()));
// once all prototypes have been build, it's possible to configure the chains
final Scriptable objectPrototype = ScriptableObject.getObjectPrototype(window);
for (final Map.Entry<String, Scriptable> entry : prototypesPerJSName.entrySet()) {
final String name = entry.getKey();
final ClassConfiguration config = jsConfig_.getClassConfiguration(name);
final Scriptable prototype = entry.getValue();
if (!StringUtils.isEmpty(config.getExtendedClassName())) {
final Scriptable parentPrototype = prototypesPerJSName.get(config.getExtendedClassName());
prototype.setPrototype(parentPrototype);
} else {
prototype.setPrototype(objectPrototype);
}
}
// if we need more in the future, we have to enhance our JSX annotations
if (browserVersion.hasFeature(JS_WINDOW_ACTIVEXOBJECT_HIDDEN)) {
final Scriptable prototype = prototypesPerJSName.get("ActiveXObject");
if (null != prototype) {
final Method jsConstructor = ActiveXObject.class.getDeclaredMethod("jsConstructor", Context.class, Object[].class, Function.class, boolean.class);
final FunctionObject functionObject = new HiddenFunctionObject("ActiveXObject", jsConstructor, window);
try {
functionObject.addAsConstructor(window, prototype);
} catch (final Exception e) {
// TODO see issue #1897
if (LOG.isWarnEnabled()) {
final String newline = System.lineSeparator();
LOG.warn("Error during JavaScriptEngine.init(WebWindow, Context)" + newline + e.getMessage() + newline + "prototype: " + prototype.getClassName());
}
}
}
}
configureRhino(webClient, browserVersion, window);
window.setPrototypes(prototypes, prototypesPerJSName);
window.initialize(webWindow, page);
applyPolyfills(webClient, browserVersion, context, window);
}
Aggregations