package org.cobra_grendel.html.domimpl;
import java.util.HashMap;
import java.util.Map;
import org.cobra_grendel.html.UserAgentContext;
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;
/**
* Implements common functionality of most elements.
*/
public class HTMLAbstractUIElement extends HTMLElementImpl
{
/**
*
*/
private static final long serialVersionUID = 1L;
private Map functionByAttribute = null;
private Function onfocus, onblur, onclick, ondblclick, onmousedown, onmouseup, onmouseover, onmousemove, onmouseout, onkeypress, onkeydown, onkeyup;
public HTMLAbstractUIElement(final String name, final int transactionId)
{
super(name, transactionId);
}
@Override
protected void assignAttributeField(final String normalName, final String value)
{
super.assignAttributeField(normalName, value);
if (normalName.startsWith("on"))
{
synchronized (this)
{
Map fba = functionByAttribute;
if (fba != null)
{
fba.remove(normalName);
}
}
}
}
public void blur()
{
UINode node = getUINode();
if (node != null)
{
node.blur();
}
}
public void focus()
{
UINode node = getUINode();
if (node != null)
{
node.focus();
}
}
protected Function getEventFunction(final Function varValue, final String attributeName)
{
if (varValue != null)
{
return varValue;
}
String normalAttributeName = normalizeAttributeName(attributeName);
synchronized (this)
{
Map fba = functionByAttribute;
Function f = fba == null ? null : (Function) fba.get(normalAttributeName);
if (f != null)
{
return f;
}
UserAgentContext uac = getUserAgentContext();
if (uac == null)
{
throw new IllegalStateException("No user agent context.");
}
if (uac.isScriptingEnabled())
{
String attributeValue = getAttribute(attributeName);
if (attributeValue == null || attributeValue.length() == 0)
{
f = null;
}
else
{
String functionCode = "function " + normalAttributeName + "_" + System.identityHashCode(this) + "() { " + attributeValue + " }";
Document doc = document;
if (doc == null)
{
throw new IllegalStateException("Element does not belong to a document.");
}
Context ctx = Executor.createContext(getDocumentURL(), uac);
try
{
Scriptable scope = (Scriptable) doc.getUserData(Executor.SCOPE_KEY);
if (scope == null)
{
throw new IllegalStateException("Scriptable (scope) instance was expected to be keyed as UserData to document using " + Executor.SCOPE_KEY);
}
Scriptable thisScope = (Scriptable) JavaScript.getInstance().getJavascriptObject(this, scope);
try
{
// TODO: Get right line number for script. //TODO:
// Optimize this in case it's called multiple times?
// Is that done?
f = ctx.compileFunction(thisScope, functionCode, getTagName() + "[" + getId() + "]." + attributeName, 1, null);
}
catch (EcmaError ecmaError)
{
this.warn("Javascript error at " + ecmaError.getSourceName() + ":" + ecmaError.getLineNumber() + ": " + ecmaError.getMessage());
f = null;
}
catch (Throwable err)
{
this.warn("Unable to evaluate Javascript code", err);
f = null;
}
}
finally
{
Context.exit();
}
}
if (fba == null)
{
fba = new HashMap(1);
functionByAttribute = fba;
}
fba.put(normalAttributeName, f);
}
return f;
}
}
public Function getOnblur()
{
return getEventFunction(onblur, "onblur");
}
public Function getOnclick()
{
return getEventFunction(onclick, "onclick");
}
public Function getOndblclick()
{
return getEventFunction(ondblclick, "ondblclick");
}
public Function getOnfocus()
{
return getEventFunction(onfocus, "onfocus");
}
public Function getOnkeydown()
{
return getEventFunction(onkeydown, "onkeydown");
}
public Function getOnkeypress()
{
return getEventFunction(onkeypress, "onkeypress");
}
public Function getOnkeyup()
{
return getEventFunction(onkeyup, "onkeyup");
}
public Function getOnmousedown()
{
return getEventFunction(onmousedown, "onmousedown");
}
public Function getOnmousemove()
{
return getEventFunction(onmousemove, "onmousemove");
}
public Function getOnmouseout()
{
return getEventFunction(onmouseout, "onmouseout");
}
public Function getOnmouseover()
{
return getEventFunction(onmouseover, "onmouseover");
}
public Function getOnmouseup()
{
return getEventFunction(onmouseup, "onmouseup");
}
public void setOnblur(final Function onblur)
{
this.onblur = onblur;
}
public void setOnclick(final Function onclick)
{
this.onclick = onclick;
}
public void setOndblclick(final Function ondblclick)
{
this.ondblclick = ondblclick;
}
public void setOnfocus(final Function onfocus)
{
this.onfocus = onfocus;
}
public void setOnkeydown(final Function onkeydown)
{
this.onkeydown = onkeydown;
}
public void setOnkeypress(final Function onkeypress)
{
this.onkeypress = onkeypress;
}
public void setOnkeyup(final Function onkeyup)
{
this.onkeyup = onkeyup;
}
public void setOnmousedown(final Function onmousedown)
{
this.onmousedown = onmousedown;
}
public void setOnmousemove(final Function onmousemove)
{
this.onmousemove = onmousemove;
}
public void setOnmouseout(final Function onmouseout)
{
this.onmouseout = onmouseout;
}
public void setOnmouseover(final Function onmouseover)
{
this.onmouseover = onmouseover;
}
public void setOnmouseup(final Function onmouseup)
{
this.onmouseup = onmouseup;
}
}