1.概述
新的WTP2.0带了一个叫做WebPageEditor的编辑器,打开一开,不得了,是带图型的编辑器耶~~
既然有了这个功能,那它肯定有扩展机制,能够让我们把自己的Taglib标签通过该编辑器的图形功能显示出来。
注意:此文认为阅读者都已经具备了最基本的Eclipse Plugin开发能力。示例项目下载
2.如何扩展
WebPageEditor的如何工作的倪?其实它的工作原理很简单。
首先它支持了对最基本的HTML元素的现实功能,然后如果需要显示我们自己定义的Tag的话,则要将这个自定义的Tag转换成普通的HTML模型。
下面我们开始做一个例子。
首先我们建一个简单的TLD文件,我们命名为:mytest.tld.我们在这个文件中定义一个mybutton标签,它具有三个属性,text,width,height。
我们这么规定该标签在页面上的显示:基本现实为一个按钮,按钮上的文字是根据text值来确定的,该按钮的大小则是由width和height值来确定的:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<taglib>
<tlib-version>1.0</tlib-version>
<jsp-version>1.0</jsp-version>
<short-name>m</short-name>
<uri>http://mytagconvert.com</uri>
<description>test</description>
<tag>
<name>mybutton</name>
<tag-class>null</tag-class>
<tei-class>null</tei-class>
<body-content>empty</body-content>
<description>test</description>
<attribute>
<name>text</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>width</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
<attribute>
<name>height</name>
<required>false</required>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>
然后我们新建一个动态web项目,然后新建一个JSP文件,用WebPageEditor打开它,你会发现,画板中仅仅只有HTML的工具栏:
肯定有人会问:工具栏就只有HTML和jsp,怎么创建我所需要的拖拽我自定义的标签啊!
别急,这里我说一下。WebPageEditor的工具栏跟所编辑的页面所在项目中,
能够读到的TLD文件是有关系的(准确说应该是这个项目的classpath能够读到的TLD)。就是说,如果你在该项目下放有一些TLD文件,那当你打开WebPageEditor的时候,它会自己读到这些TLD文件(必须保证这些文件能够被读出来),然后根据TLD文件中对tag的定义,再在画板上显示出所能绘制的tag标签工具Entry。所以,我们这个例子也需要将刚才建好的那个test.tld文件放置到这个项目中去。然后我们重新用WebPageEditor打开新建好的JSP文件,你会发现,工具栏中出现了我们刚才所定义好的那个tld:
你可以试着把工具栏中的TestButton托到编辑器中,不过它显示出现的是一个空白的玩意儿,上面还有该标签的名称。
ok,准备工作算是做好了,现在我们开始真正讨论如何让自定义标签可以显示,而且还能进行编辑。
首先让我们看一个扩展点:
org.eclipse.jst.pagedesigner.pageDesignerExtension
这个扩展点就是我们需要扩展的。下面几个元素比较重要:
tagConverterFactory
elementEditFactory
attributeCellEditorFactory
我们目前只讨论tagConverterFactory,其他的扩展点会在以后进行讲解。
tagConverterFactory有一个属性值:class。这个class是需要我们给出一个实现了org.eclipse.jst.pagedesigner.converter.IConverterFactory接口的类。
这个接口有两个方法需要我们实现:
getSupportedURI
这个方法什么意思呢?打开TLD文件,大家可以看到,TLD文件中有一个URI的属性值,这个属性值我们可以看成是XML文件中Schema的名字空间,用来唯一确定该TLD文件的一个标识。WebPageEditor需要我们给出这么一个URI,其目的很明显,就是能够和它将读出的TLD进行匹配。
createConverter
这个方法有点让人很茫然,首先看它的参数:
Element element,int mode
第一个参数element是指,在我们拖拽进入一个标签后,该标签对应的element模型;mode是指现实模式,前面忘记说了,
WebPageEditor是多页编辑器,一页是编辑页面的,一页是预览页面的。这里的mode就是指在编辑页面模式还是预览页面模式。我们现在可以不考虑这个参数,在下面的所有文字中,该mode参数一律被视为编辑页面模式。
该方法返回的是一个ITagConverter接口。
可以说,ITagConverter接口诠释了WebPageEditor的如何对标签进行解析并形成一个图形的过程。根据上面我们给出的一个简单的流程图可以看出,ITagConverter其实就是专门转换taglib中定义的tag到标准HTML DOM的这么一个接口类。
话说多了是水,先看看怎么实现把。
先罗嗦一下步骤:
1.新建一个插件项目,加入依赖项:
org.eclipse.jst.pagedesigner,
org.eclipse.wst.sse.core,
org.eclipse.wst.xml.core
2.新建一个为mybutton标签进行转换的Converter类
3.新建一个映射标签名和Converter的ConverterFactory类
4.建立一个在插件项目中实现刚才提到的
org.eclipse.jst.pagedesigner.pageDesignerExtension 扩展点
新建项目我不就不说了。从新建Converter说起。
3.MyButtonTagConverter
一般情况下,我不建议大家直接实现ITagConverter,很累人的,而且其实里面还有很多需要考虑的东西。所以我们应该从一个抽象类开始继承:
AbstractTagConverter。
这个类实现了大部分ITagConverter的功能,并且还提供了好些方法可供使用,它只将转换DOM的这个工作利用一个抽象函数 doConvertRefresh暴露出来——
doConvertRefresh函数的返回值就是我们最终转换成的DOM。
另外两个抽象函数是isMultiLevel和isWidget,这两个以后介绍。
我们继承这个类后只要将doConvertRefresh函数实现就可以了。
刚才我们新建了一个TLD文件,里面描述了一个mybutton标签,现在我们来实现这个标签的转换。
新建一个类,名为MyButtonTagConverter,然后我们实现这个类的doConvertRefresh方法:
public class MyButtonTagConverter extends AbstractTagConverter{
@Override
protected Element doConvertRefresh() {
// 创建一个HTML 的button element
Element button = createElement(IHTMLConstants.TAG_BUTTON);
// 获得属性值
String text = getHostElement().getAttribute("text");
if(text == null) text = "";
// 将text值给button,作为button的content,以便显示
button.appendChild(createText(text));
// 将host element的属性全部复制给新建的button element中:
JSFConverterUtil.copyAllAttributes(getHostElement(), button, null);
return button;
}
}
我说一下这几个方法:
createElement
这个方法是AbstractTagConverter提供的,它是专门用于创建一个DOM元素的方法,传入的值则是生成该DOM得元素名,这里我用到了一个维护常量的类IHTMLConstants,它是JST提供的,很有用。如果你有兴趣可以看看AbstractTagConverter如何实现这个方法的,很简单,但是很麻烦。
getHostElement
这个方法是AbstractTagConverter提供的。返回的是一个被称为host element的DOM对象,什么是host element?它就是我们在页面上写的那个<mybutton/>的dom对象。
createText
这个方法是AbstractTagConverter提供的。创建一个content节点
JSFConverterUtil.copyAllAttributes
一个工具类提供的复制属性的方法。很实用。之所以要进行复制所有的属性,是因为,我们单独创建按出来的HTML DOM只是一个光秃秃的东西,不具备任何属性,那么host element的属性值有一部分是可以赋给生成的HTML DOM的,比如说,代码中给出了这么一段:读出host element的text属性值,然后给button dom的 属性,这样它就可以显示出文字来了,而其他一些属性名相同的属性,在host element和生成的html dom中具有相同的功效,我们是需要复制过来的。
我们可以这么想:
我们所写的<mybutton text="button"/> 被转换成了<button>button</button>HTML dom。
4 MyTagConverterFactory
这个类很简单:
public class MyConverterFactory implements IConverterFactory {
/* (non-Javadoc)
* @see org.eclipse.jst.pagedesigner.converter.IConverterFactory#createConverter(org.w3c.dom.Element, int)
*/
public ITagConverter createConverter(Element element, int mode) {
String name = element.getLocalName().trim();
if(name.equalsIgnoreCase("mybutton")){
return new MyButtonTagConverter(element);
}
return new DefaultUnknownTagConverter(element,mode);
}
/* (non-Javadoc)
* @see org.eclipse.jst.pagedesigner.converter.IConverterFactory#getSupportedURI()
*/
public String getSupportedURI() {
return "http://mytagconvert.com";
}
}
这里需要强调的是三点:
1.
getSupportedURI方法返回的URI必须和TLD里的一致。
2.返回的Converter的构造函数的参数必须给出,因为这个参数就是我们要的Hostelement,而createConverter传进的element正好就是这个host lement。
3.不要让createConverter返回null,给出一个默认的Converter
5 写好扩展点
我们新建一个
org.eclipse.jst.pagedesigner.pageDesignerExtension,然后写好tagConverterFactory元素,将它的class设成我们新建好的
MyTagConverterFactory:
<extension
point="org.eclipse.jst.pagedesigner.pageDesignerExtension">
<tagConverterFactory
class="tagconverters.MyConverterFactory">
</tagConverterFactory>
</extension>
6.运行
让我们运行这个插件。
在运行后,建立一个动态的web项目,然后把我们的tld文件复制到项目的WebContent下。再新建一个jsp文件,用WebPageEditor打来,然后我们再将右侧画板上的mybutton拖入编辑器:
怎么样,不错吧。
7.未完待续
其实这只是一个开始,记得一开始为什么我会将mybutton设置上width和height,但后面就没说了,这些都要留到后面。
后续文章我还会讲一些其他的东西,比如如何扩展IElementEdit、属性的页、Palette的显示等等。
谢谢大家,再见。