/*
* GNU LESSER GENERAL PUBLIC LICENSE Copyright (C) 2006 The Lobo Project
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Contact info: xamjadmin@users.sourceforge.net
*/
package com.grendelscan.commons.html;
import org.cobra_grendel.html.domimpl.HTMLDocumentImpl;
import org.cobra_grendel.html.domimpl.HTMLElementImpl;
import org.cobra_grendel.html.domimpl.HTMLHtmlElementImpl;
import org.cobra_grendel.html.js.Executor;
import org.cobra_grendel.js.JavaScript;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.EcmaError;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
/**
* Cobbled together from various parts of Cobra and the sample DOM writer in Xerces by Andy Clark.
*
* @author David Byrne
*
*/
public class EventHandlerExecutor
{
private static void executeAttributeValue(final HTMLElementImpl element, final String attributeName)
{
String attributeValue = element.getAttributes().getNamedItem(attributeName).getNodeValue();
if (attributeValue != null && !attributeValue.equals(""))
{
String functionCode = "function " + attributeName + "_" + System.identityHashCode(element) + "() { " + attributeValue + " }";
HTMLDocumentImpl document = (HTMLDocumentImpl) element.getOwnerDocument();
if (document != null)
{
Scriptable scope = (Scriptable) document.getUserData(Executor.SCOPE_KEY);
Scriptable thisScope = (Scriptable) JavaScript.getInstance().getJavascriptObject(element, scope);
Context ctx = Executor.createContext(document.getDocumentURL(), document.getUserAgentContext());
try
{
Function eventFunction = ctx.compileFunction(thisScope, functionCode, element.getTagName() + "[" + element.getId() + "]." + attributeName, 1, null);
Executor.executeFunction(document, eventFunction, null);
}
catch (EcmaError ecmaError)
{
element.warn("Javascript error at " + ecmaError.getSourceName() + ":" + ecmaError.getLineNumber() + ": " + ecmaError.getMessage());
}
catch (Throwable err)
{
element.warn("Unable to evaluate Javascript code", err);
}
finally
{
Context.exit();
}
}
}
}
/**
* A major limitation is that all events are execute against the same DOM. This is due to the difficulty of DOM cloning. This won't be a problem for most pages, but if a page modifies the page in
* a way that prevents other events from running properly, the desired results won't be obtained.
*
* @param node
* @param terminationCondition
*/
public static void executeEvents(final Node node, final EventExecutorTerminator terminationCondition)
{
internalExecuteEvents(node, terminationCondition);
}
/**
* Returns true if the test is terminated
*
* @param node
* @param terminationCondition
* @return
*/
private static boolean internalExecuteEvents(final Node node, final EventExecutorTerminator terminationCondition)
{
boolean terminate = false;
// is there anything to do?
if (node == null)
{
return terminate;
}
short type = node.getNodeType();
switch (type)
{
case Node.DOCUMENT_NODE:
{
Document document = (Document) node;
Element e = document.getDocumentElement();
if (!(e instanceof HTMLHtmlElementImpl))
{
// This is in case there is no HTML tag. Some of the DOM can still be salvaged.
Node child = document.getFirstChild();
while (child != null)
{
terminate = internalExecuteEvents(child, terminationCondition);
if (terminate)
{
break;
}
child = child.getNextSibling();
}
}
else
{
terminate = internalExecuteEvents(e, terminationCondition);
}
break;
}
case Node.ELEMENT_NODE:
{
NamedNodeMap attrs = node.getAttributes();
for (int index = 0; index < attrs.getLength(); index++)
{
Node attr = attrs.item(index);
if (attr.getNodeName().toLowerCase().startsWith("on"))
{
executeAttributeValue((HTMLElementImpl) node, attr.getNodeName());
terminate = terminationCondition.stopExecution(node);
if (terminate)
{
break;
}
}
}
if (terminate)
{
break;
}
Node child = node.getFirstChild();
while (child != null)
{
terminate = internalExecuteEvents(child, terminationCondition);
if (terminate)
{
break;
}
child = child.getNextSibling();
}
break;
}
case Node.ENTITY_REFERENCE_NODE:
{
Node child = node.getFirstChild();
while (child != null)
{
terminate = internalExecuteEvents(child, terminationCondition);
if (terminate)
{
break;
}
child = child.getNextSibling();
}
break;
}
}
return terminate;
}
}