use of com.gargoylesoftware.htmlunit.javascript.host.Window in project htmlunit by HtmlUnit.
the class ScriptElementSupport method executeScriptIfNeeded.
/**
* <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
*
* Executes this script node if necessary and/or possible.
* @param element the element
* @param ignoreAttachedToPage don't do the isAttachedToPage check
* @param ignorePageIsAncestor don't do the element.getPage().isAncestorOf(element) check
*/
public static void executeScriptIfNeeded(final DomElement element, final boolean ignoreAttachedToPage, final boolean ignorePageIsAncestor) {
if (!isExecutionNeeded(element, ignoreAttachedToPage, ignorePageIsAncestor)) {
return;
}
final ScriptElement scriptElement = (ScriptElement) element;
final String src = scriptElement.getSrcAttribute();
if (src.equals(SLASH_SLASH_COLON)) {
executeEvent(element, Event.TYPE_ERROR);
return;
}
final HtmlPage page = (HtmlPage) element.getPage();
if (src != ATTRIBUTE_NOT_DEFINED) {
if (!src.startsWith(JavaScriptURLConnection.JAVASCRIPT_PREFIX)) {
// <script src="[url]"></script>
if (LOG.isDebugEnabled()) {
LOG.debug("Loading external JavaScript: " + src);
}
try {
scriptElement.setExecuted(true);
Charset charset = EncodingSniffer.toCharset(scriptElement.getCharsetAttribute());
if (charset == null) {
charset = page.getCharset();
}
final JavaScriptLoadResult result;
final Window win = page.getEnclosingWindow().getScriptableObject();
final Document doc = win.getDocument();
try {
doc.setCurrentScript(element.getScriptableObject());
result = page.loadExternalJavaScriptFile(src, charset);
} finally {
doc.setCurrentScript(null);
}
if (result == JavaScriptLoadResult.SUCCESS) {
executeEvent(element, Event.TYPE_LOAD);
} else if (result == JavaScriptLoadResult.DOWNLOAD_ERROR) {
executeEvent(element, Event.TYPE_ERROR);
} else if (result == JavaScriptLoadResult.NO_CONTENT) {
final BrowserVersion browserVersion = page.getWebClient().getBrowserVersion();
if (browserVersion.hasFeature(JS_SCRIPT_HANDLE_204_AS_ERROR)) {
executeEvent(element, Event.TYPE_ERROR);
} else {
executeEvent(element, Event.TYPE_LOAD);
}
}
} catch (final FailingHttpStatusCodeException e) {
executeEvent(element, Event.TYPE_ERROR);
throw e;
}
}
} else if (element.getFirstChild() != null) {
// <script>[code]</script>
final Window win = page.getEnclosingWindow().getScriptableObject();
final Document doc = win.getDocument();
try {
doc.setCurrentScript(element.getScriptableObject());
executeInlineScriptIfNeeded(element);
} finally {
doc.setCurrentScript(null);
}
if (element.hasFeature(EVENT_ONLOAD_INTERNAL_JAVASCRIPT)) {
executeEvent(element, Event.TYPE_LOAD);
}
}
}
use of com.gargoylesoftware.htmlunit.javascript.host.Window in project htmlunit by HtmlUnit.
the class ScriptElementSupport method executeInlineScriptIfNeeded.
/**
* Executes this script node as inline script if necessary and/or possible.
*/
private static void executeInlineScriptIfNeeded(final DomElement element) {
if (!isExecutionNeeded(element, false, false)) {
return;
}
final ScriptElement scriptElement = (ScriptElement) element;
final String src = scriptElement.getSrcAttribute();
if (src != ATTRIBUTE_NOT_DEFINED) {
return;
}
final String forr = element.getAttributeDirect("for");
String event = element.getAttributeDirect("event");
// The event name can be like "onload" or "onload()".
if (event.endsWith("()")) {
event = event.substring(0, event.length() - 2);
}
final String scriptCode = getScriptCode(element);
if (event != ATTRIBUTE_NOT_DEFINED && forr != ATTRIBUTE_NOT_DEFINED && element.hasFeature(JS_SCRIPT_SUPPORTS_FOR_AND_EVENT_WINDOW) && "window".equals(forr)) {
final Window window = element.getPage().getEnclosingWindow().getScriptableObject();
final BaseFunction function = new EventHandler(element, event, scriptCode);
window.getEventListenersContainer().addEventListener(StringUtils.substring(event, 2), function, false);
return;
}
if (forr == ATTRIBUTE_NOT_DEFINED || "onload".equals(event)) {
final String url = element.getPage().getUrl().toExternalForm();
final int line1 = element.getStartLineNumber();
final int line2 = element.getEndLineNumber();
final int col1 = element.getStartColumnNumber();
final int col2 = element.getEndColumnNumber();
final String desc = "script in " + url + " from (" + line1 + ", " + col1 + ") to (" + line2 + ", " + col2 + ")";
scriptElement.setExecuted(true);
((HtmlPage) element.getPage()).executeJavaScript(scriptCode, desc, line1);
}
}
use of com.gargoylesoftware.htmlunit.javascript.host.Window in project htmlunit by HtmlUnit.
the class ScriptElementSupport method onAllChildrenAddedToPage.
/**
* Lifecycle method invoked after a node and all its children have been added to a page, during
* parsing of the HTML. Intended to be overridden by nodes which need to perform custom logic
* after they and all their child nodes have been processed by the HTML parser. This method is
* not recursive, and the default implementation is empty, so there is no need to call
* <tt>super.onAllChildrenAddedToPage()</tt> if you implement this method.
* @param element the element
* @param postponed whether to use {@link com.gargoylesoftware.htmlunit.javascript.PostponedAction} or no
*/
public static void onAllChildrenAddedToPage(final DomElement element, final boolean postponed) {
if (element.getOwnerDocument() instanceof XmlPage) {
return;
}
if (LOG.isDebugEnabled()) {
LOG.debug("Script node added: " + element.asXml());
}
if (!element.getPage().getWebClient().isJavaScriptEngineEnabled()) {
if (LOG.isDebugEnabled()) {
LOG.debug("Script found but not executed because javascript engine is disabled");
}
return;
}
final ScriptElement script = (ScriptElement) element;
final String srcAttrib = script.getSrcAttribute();
if (ATTRIBUTE_NOT_DEFINED != srcAttrib && script.isDeferred()) {
return;
}
final WebWindow webWindow = element.getPage().getEnclosingWindow();
if (webWindow != null) {
final StringBuilder description = new StringBuilder().append("Execution of ").append(srcAttrib == ATTRIBUTE_NOT_DEFINED ? "inline " : "external ").append(element.getClass().getSimpleName());
if (srcAttrib != ATTRIBUTE_NOT_DEFINED) {
description.append(" (").append(srcAttrib).append(')');
}
final PostponedAction action = new PostponedAction(element.getPage(), description.toString()) {
@Override
public void execute() {
// see HTMLDocument.setExecutingDynamicExternalPosponed(boolean)
HTMLDocument jsDoc = null;
final Window window = webWindow.getScriptableObject();
if (window != null) {
jsDoc = (HTMLDocument) window.getDocument();
jsDoc.setExecutingDynamicExternalPosponed(element.getStartLineNumber() == -1 && ATTRIBUTE_NOT_DEFINED != srcAttrib);
}
try {
executeScriptIfNeeded(element, false, false);
} finally {
if (jsDoc != null) {
jsDoc.setExecutingDynamicExternalPosponed(false);
}
}
}
};
final AbstractJavaScriptEngine<?> engine = element.getPage().getWebClient().getJavaScriptEngine();
if (engine != null && element.hasAttribute("async") && !engine.isScriptRunning()) {
final HtmlPage owningPage = element.getHtmlPageOrNull();
owningPage.addAfterLoadAction(action);
} else if (engine != null && (element.hasAttribute("async") || postponed && StringUtils.isBlank(element.getTextContent()))) {
engine.addPostponedAction(action);
} else {
try {
action.execute();
} catch (final RuntimeException e) {
throw e;
} catch (final Exception e) {
throw new RuntimeException(e);
}
}
}
}
use of com.gargoylesoftware.htmlunit.javascript.host.Window in project htmlunit by HtmlUnit.
the class EventTarget method fireEvent.
/**
* Fires the event on the node with capturing and bubbling phase.
* @param event the event
* @return the result
*/
public ScriptResult fireEvent(final Event event) {
final Window window = getWindow();
event.startFire();
final Event previousEvent = window.getCurrentEvent();
window.setCurrentEvent(event);
try {
// These can be null if we aren't tied to a DOM node
final DomNode ourNode = getDomNodeOrNull();
final DomNode ourParentNode = (ourNode != null) ? ourNode.getParentNode() : null;
// Determine the propagation path which is fixed here and not affected by
// DOM tree modification from intermediate listeners (tested in Chrome)
final List<EventTarget> propagationPath = new ArrayList<>();
// We're added to the propagation path first
propagationPath.add(this);
// and MessagePort, etc. will not have any parents)
for (DomNode parent = ourParentNode; parent != null; parent = parent.getParentNode()) {
propagationPath.add(parent.getScriptableObject());
}
// (see Note in https://www.w3.org/TR/DOM-Level-3-Events/#event-type-load)
if (!Event.TYPE_LOAD.equals(event.getType())) {
// Add Window if the the propagation path reached Document
if (propagationPath.get(propagationPath.size() - 1) instanceof Document) {
propagationPath.add(window);
}
}
// capturing phase
event.setEventPhase(Event.CAPTURING_PHASE);
for (int i = propagationPath.size() - 1; i >= 1; i--) {
final EventTarget jsNode = propagationPath.get(i);
final EventListenersContainer elc = jsNode.eventListenersContainer_;
if (elc != null) {
elc.executeCapturingListeners(event, new Object[] { event });
if (event.isPropagationStopped()) {
return new ScriptResult(null);
}
}
}
// at target phase
event.setEventPhase(Event.AT_TARGET);
if (!propagationPath.isEmpty()) {
// Note: This element is not always the same as event.getTarget():
// e.g. the 'load' event targets Document but "at target" is on Window.
final EventTarget jsNode = propagationPath.get(0);
final EventListenersContainer elc = jsNode.eventListenersContainer_;
if (elc != null) {
elc.executeAtTargetListeners(event, new Object[] { event });
if (event.isPropagationStopped()) {
return new ScriptResult(null);
}
}
}
// bubbling phase
if (event.isBubbles()) {
// This belongs here inside the block because events that don't bubble never set
// eventPhase = 3 (tested in Chrome)
event.setEventPhase(Event.BUBBLING_PHASE);
for (int i = 1, size = propagationPath.size(); i < size; i++) {
final EventTarget jsNode = propagationPath.get(i);
final EventListenersContainer elc = jsNode.eventListenersContainer_;
if (elc != null) {
elc.executeBubblingListeners(event, new Object[] { event });
if (event.isPropagationStopped()) {
return new ScriptResult(null);
}
}
}
}
HtmlLabel label = null;
if (event.processLabelAfterBubbling()) {
for (DomNode parent = ourParentNode; parent != null; parent = parent.getParentNode()) {
if (parent instanceof HtmlLabel) {
label = (HtmlLabel) parent;
break;
}
}
}
if (label != null) {
final HtmlElement element = label.getLabeledElement();
if (element != null && element != getDomNodeOrNull()) {
try {
element.click(event.isShiftKey(), event.isCtrlKey(), event.isAltKey(), false, true, true, true);
} catch (final IOException e) {
// ignore for now
}
}
}
} finally {
event.endFire();
// reset event
window.setCurrentEvent(previousEvent);
}
return new ScriptResult(null);
}
use of com.gargoylesoftware.htmlunit.javascript.host.Window in project htmlunit by HtmlUnit.
the class EventTarget method executeEventLocally.
/**
* Executes the event on this object only (needed for instance for onload on (i)frame tags).
* @param event the event
* @see #fireEvent(Event)
*/
public void executeEventLocally(final Event event) {
final EventListenersContainer eventListenersContainer = getEventListenersContainer();
final Window window = getWindow();
final Object[] args = { event };
final Event previousEvent = window.getCurrentEvent();
window.setCurrentEvent(event);
try {
event.setEventPhase(Event.AT_TARGET);
eventListenersContainer.executeAtTargetListeners(event, args);
} finally {
// reset event
window.setCurrentEvent(previousEvent);
}
}
Aggregations