ATF中,Evaluator对象提供了从Java代码来控制内嵌Mozilla执行js脚本的功能,本文对其工作原理作一个简单的介绍。
1、概要介绍
在Eclipse中,基于JavaXPCOM的MozillaInterfaces开发包中,为使用者提供了一项功能:从Java代码中监听浏览器中的事件及在Java代码中触发浏览器的事件,这些事件包括浏览器中document的所有元素的预定义事件和自定义事件。ATF的Evaluator对象正是利用这个原理来工作的。简单来说,第一步,先利用MozillaInterfaces提供的功能,把要执行的脚本加入浏览器的当前页面中;然后触发一个页面上的事件,来执行第一步加入的代码。下面具体说明一下。
2、具体步骤
2.1 第一步,创建一个Evaluator对象的实例,并和浏览器的当前的document对象关联起来,为在浏览器当前的document中执行脚本做准备。这一步是通过调用Evaluator的init方法实现的:
public void init(nsIDOMDocument document);
在这个方法里面,主要完成了以下的事情:
2.1.1 首先,增加了Java代码对页面的3种自定义事件的监听,代码如下:
nsIDOMEventTarget docTarget=(nsIDOMEventTarget)document.
queryInterface(nsIDOMEventTarget.NS_IDOMEVENTTARGET_IID);
docTarget.addEventListener(EVAL_READY, this.listener, true);
docTarget.addEventListener(EVAL_DONE, this.listener, true);
docTarget.addEventListener(EVAL_ERROR, this.listener, true);
这样做的目的是:
监听EVAL_READY类型的自定义事件,当页面那边准备好之后,就会向Java代码这边发送这个事件,Java代码这边监听到之后,就开始调用js的操作;
监听EVAL_DONE类型的自定义事件,当页面那边完成Java代码这边指定要执行的js脚本之后,发送一个EVAL_DONE类型的事件,Java代码这边监听到之后,进行读取返回值的操作;
监听EVAL_ERROR类型的自定义事件是为了出错处理,不详细介绍了。
2.1.2 接下来,向浏览器的当前的document对象中增加一段脚本,这段脚本在附件中。之所以要向浏览器的当前的document对象中加入这一段脚本,是为了完成以下几件事情:
首先,这段脚本向document.body对象中增加了两个html元素,称为eval_in,eval_out。从名字可以猜测出来,eval_in用来保存即将被执行的脚本,eval_out用来保存执行脚本的返回值,返回到Java代码那边的值。当创建了这两个元素之后,页面就会触发类型为EVAL_READY的自定义事件,通知Java代码端页面这边已经做好准备,可以开始执行js脚本了。这个通知是如何发送的,请参考下面这一段代码:
ATF.Eval.connect = function()
{
var event = document.createEvent( "Event" );
event.initEvent( "ATF_EVAL_READY", false, false );
this.eval_in.dispatchEvent( event );
}
其次,这段脚本中还含有执行Java代码端传递过来的js脚本的方法。首先,页面里注册了对类型为ATF_EVAL_SET的自定义事件 的监听,当Java代码那边通过MozillaInterfaces接口,将被执行的js脚本作为字符串赋给eval_in的value属性之后,就会触发一个类型为ATF_EVAL_SET的事件,而页面这边就会监听到这个事件。注册监听的代码如下:
document.addEventListener( "ATF_EVAL_SET", function( event )
{ ATF.Eval.eval.call( ATF.Eval, event );}
, true );
从这段代码中可以看出,当页面监听到Java端触发的类型为ATF_EVAL_SET的自定义事件之后,会执行一个名为ATF.Eval.eval的脚本方法,这个方法的作用就是读取eval_in.value的值,然后将其作为脚本执行。
最后,被加入到浏览器当前document对象的这段脚本提供了处理返回结果和出错信息的方法,这里就不再详细介绍了。
2.2 创建了Evaluator对象,并初始化之后,接下来就可以在Java中执行js脚本了,调用如下这个方法:
public IJSValue evaluate(String expression);
其代码如下:
this.evalRet = null;
//将被执行的js赋给页面上的eval_in.value
this.evalIn.setValue(expression);
//触发事件,通知页面执行脚本
nsIDOMDocumentEvent docEvent = (nsIDOMDocumentEvent) this.document.
queryInterface(nsIDOMDocumentEvent.NS_IDOMDOCUMENTEVENT_IID);
nsIDOMEvent event = docEvent.createEvent("Event");
event.initEvent(EVAL_SET, false, false);
nsIDOMEventTarget target = (nsIDOMEventTarget) node.
queryInterface(nsIDOMEventTarget.NS_IDOMEVENTTARGET_IID);
target.dispatchEvent(event);
//返回结果
return this.evalRet;