1.概述
新的WTP2.0帶了一個(gè)叫做WebPageEditor的編輯器,打開一開,不得了,是帶圖型的編輯器耶~~
既然有了這個(gè)功能,那它肯定有擴(kuò)展機(jī)制,能夠讓我們把自己的Taglib標(biāo)簽通過該編輯器的圖形功能顯示出來。
注意:此文認(rèn)為閱讀者都已經(jīng)具備了最基本的Eclipse Plugin開發(fā)能力。示例項(xiàng)目下載
2.如何擴(kuò)展
WebPageEditor的如何工作的倪?其實(shí)它的工作原理很簡(jiǎn)單。
首先它支持了對(duì)最基本的HTML元素的現(xiàn)實(shí)功能,然后如果需要顯示我們自己定義的Tag的話,則要將這個(gè)自定義的Tag轉(zhuǎn)換成普通的HTML模型。
下面我們開始做一個(gè)例子。
首先我們建一個(gè)簡(jiǎn)單的TLD文件,我們命名為:mytest.tld.我們?cè)谶@個(gè)文件中定義一個(gè)mybutton標(biāo)簽,它具有三個(gè)屬性,text,width,height。
我們這么規(guī)定該標(biāo)簽在頁面上的顯示:基本現(xiàn)實(shí)為一個(gè)按鈕,按鈕上的文字是根據(jù)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>
然后我們新建一個(gè)動(dòng)態(tài)web項(xiàng)目,然后新建一個(gè)JSP文件,用WebPageEditor打開它,你會(huì)發(fā)現(xiàn),畫板中僅僅只有HTML的工具欄:
肯定有人會(huì)問:工具欄就只有HTML和jsp,怎么創(chuàng)建我所需要的拖拽我自定義的標(biāo)簽啊!
別急,這里我說一下。WebPageEditor的工具欄跟所編輯的頁面所在項(xiàng)目中,
能夠讀到的TLD文件是有關(guān)系的(準(zhǔn)確說應(yīng)該是這個(gè)項(xiàng)目的classpath能夠讀到的TLD)。就是說,如果你在該項(xiàng)目下放有一些TLD文件,那當(dāng)你打開WebPageEditor的時(shí)候,它會(huì)自己讀到這些TLD文件(必須保證這些文件能夠被讀出來),然后根據(jù)TLD文件中對(duì)tag的定義,再在畫板上顯示出所能繪制的tag標(biāo)簽工具Entry。所以,我們這個(gè)例子也需要將剛才建好的那個(gè)test.tld文件放置到這個(gè)項(xiàng)目中去。然后我們重新用WebPageEditor打開新建好的JSP文件,你會(huì)發(fā)現(xiàn),工具欄中出現(xiàn)了我們剛才所定義好的那個(gè)tld:
你可以試著把工具欄中的TestButton托到編輯器中,不過它顯示出現(xiàn)的是一個(gè)空白的玩意兒,上面還有該標(biāo)簽的名稱。
ok,準(zhǔn)備工作算是做好了,現(xiàn)在我們開始真正討論如何讓自定義標(biāo)簽可以顯示,而且還能進(jìn)行編輯。
首先讓我們看一個(gè)擴(kuò)展點(diǎn):
org.eclipse.jst.pagedesigner.pageDesignerExtension
這個(gè)擴(kuò)展點(diǎn)就是我們需要擴(kuò)展的。下面幾個(gè)元素比較重要:
tagConverterFactory
elementEditFactory
attributeCellEditorFactory
我們目前只討論tagConverterFactory,其他的擴(kuò)展點(diǎn)會(huì)在以后進(jìn)行講解。
tagConverterFactory有一個(gè)屬性值:class。這個(gè)class是需要我們給出一個(gè)實(shí)現(xiàn)了org.eclipse.jst.pagedesigner.converter.IConverterFactory接口的類。
這個(gè)接口有兩個(gè)方法需要我們實(shí)現(xiàn):
getSupportedURI
這個(gè)方法什么意思呢?打開TLD文件,大家可以看到,TLD文件中有一個(gè)URI的屬性值,這個(gè)屬性值我們可以看成是XML文件中Schema的名字空間,用來唯一確定該TLD文件的一個(gè)標(biāo)識(shí)。WebPageEditor需要我們給出這么一個(gè)URI,其目的很明顯,就是能夠和它將讀出的TLD進(jìn)行匹配。
createConverter
這個(gè)方法有點(diǎn)讓人很茫然,首先看它的參數(shù):
Element element,int mode
第一個(gè)參數(shù)element是指,在我們拖拽進(jìn)入一個(gè)標(biāo)簽后,該標(biāo)簽對(duì)應(yīng)的element模型;mode是指現(xiàn)實(shí)模式,前面忘記說了,
WebPageEditor是多頁編輯器,一頁是編輯頁面的,一頁是預(yù)覽頁面的。這里的mode就是指在編輯頁面模式還是預(yù)覽頁面模式。我們現(xiàn)在可以不考慮這個(gè)參數(shù),在下面的所有文字中,該mode參數(shù)一律被視為編輯頁面模式。
該方法返回的是一個(gè)ITagConverter接口。
可以說,ITagConverter接口詮釋了WebPageEditor的如何對(duì)標(biāo)簽進(jìn)行解析并形成一個(gè)圖形的過程。根據(jù)上面我們給出的一個(gè)簡(jiǎn)單的流程圖可以看出,ITagConverter其實(shí)就是專門轉(zhuǎn)換taglib中定義的tag到標(biāo)準(zhǔn)HTML DOM的這么一個(gè)接口類。
話說多了是水,先看看怎么實(shí)現(xiàn)把。
先羅嗦一下步驟:
1.新建一個(gè)插件項(xiàng)目,加入依賴項(xiàng):
org.eclipse.jst.pagedesigner,
org.eclipse.wst.sse.core,
org.eclipse.wst.xml.core
2.新建一個(gè)為mybutton標(biāo)簽進(jìn)行轉(zhuǎn)換的Converter類
3.新建一個(gè)映射標(biāo)簽名和Converter的ConverterFactory類
4.建立一個(gè)在插件項(xiàng)目中實(shí)現(xiàn)剛才提到的
org.eclipse.jst.pagedesigner.pageDesignerExtension 擴(kuò)展點(diǎn)
新建項(xiàng)目我不就不說了。從新建Converter說起。
3.MyButtonTagConverter
一般情況下,我不建議大家直接實(shí)現(xiàn)ITagConverter,很累人的,而且其實(shí)里面還有很多需要考慮的東西。所以我們應(yīng)該從一個(gè)抽象類開始繼承:
AbstractTagConverter。
這個(gè)類實(shí)現(xiàn)了大部分ITagConverter的功能,并且還提供了好些方法可供使用,它只將轉(zhuǎn)換DOM的這個(gè)工作利用一個(gè)抽象函數(shù) doConvertRefresh暴露出來——
doConvertRefresh函數(shù)的返回值就是我們最終轉(zhuǎn)換成的DOM。
另外兩個(gè)抽象函數(shù)是isMultiLevel和isWidget,這兩個(gè)以后介紹。
我們繼承這個(gè)類后只要將doConvertRefresh函數(shù)實(shí)現(xiàn)就可以了。
剛才我們新建了一個(gè)TLD文件,里面描述了一個(gè)mybutton標(biāo)簽,現(xiàn)在我們來實(shí)現(xiàn)這個(gè)標(biāo)簽的轉(zhuǎn)換。
新建一個(gè)類,名為MyButtonTagConverter,然后我們實(shí)現(xiàn)這個(gè)類的doConvertRefresh方法:
public class MyButtonTagConverter extends AbstractTagConverter{
@Override
protected Element doConvertRefresh() {
// 創(chuàng)建一個(gè)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的屬性全部復(fù)制給新建的button element中:
JSFConverterUtil.copyAllAttributes(getHostElement(), button, null);
return button;
}
}
我說一下這幾個(gè)方法:
createElement
這個(gè)方法是AbstractTagConverter提供的,它是專門用于創(chuàng)建一個(gè)DOM元素的方法,傳入的值則是生成該DOM得元素名,這里我用到了一個(gè)維護(hù)常量的類IHTMLConstants,它是JST提供的,很有用。如果你有興趣可以看看AbstractTagConverter如何實(shí)現(xiàn)這個(gè)方法的,很簡(jiǎn)單,但是很麻煩。
getHostElement
這個(gè)方法是AbstractTagConverter提供的。返回的是一個(gè)被稱為host element的DOM對(duì)象,什么是host element?它就是我們?cè)陧撁嫔蠈懙哪莻€(gè)<mybutton/>的dom對(duì)象。
createText
這個(gè)方法是AbstractTagConverter提供的。創(chuàng)建一個(gè)content節(jié)點(diǎn)
JSFConverterUtil.copyAllAttributes
一個(gè)工具類提供的復(fù)制屬性的方法。很實(shí)用。之所以要進(jìn)行復(fù)制所有的屬性,是因?yàn)椋覀儐为?dú)創(chuàng)建按出來的HTML DOM只是一個(gè)光禿禿的東西,不具備任何屬性,那么host element的屬性值有一部分是可以賦給生成的HTML DOM的,比如說,代碼中給出了這么一段:讀出host element的text屬性值,然后給button dom的 屬性,這樣它就可以顯示出文字來了,而其他一些屬性名相同的屬性,在host element和生成的html dom中具有相同的功效,我們是需要復(fù)制過來的。
我們可以這么想:
我們所寫的<mybutton text="button"/> 被轉(zhuǎn)換成了<button>button</button>HTML dom。
4 MyTagConverterFactory
這個(gè)類很簡(jiǎn)單:
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";
}
}
這里需要強(qiáng)調(diào)的是三點(diǎn):
1.
getSupportedURI方法返回的URI必須和TLD里的一致。
2.返回的Converter的構(gòu)造函數(shù)的參數(shù)必須給出,因?yàn)檫@個(gè)參數(shù)就是我們要的Hostelement,而createConverter傳進(jìn)的element正好就是這個(gè)host lement。
3.不要讓createConverter返回null,給出一個(gè)默認(rèn)的Converter
5 寫好擴(kuò)展點(diǎn)
我們新建一個(gè)
org.eclipse.jst.pagedesigner.pageDesignerExtension,然后寫好tagConverterFactory元素,將它的class設(shè)成我們新建好的
MyTagConverterFactory:
<extension
point="org.eclipse.jst.pagedesigner.pageDesignerExtension">
<tagConverterFactory
class="tagconverters.MyConverterFactory">
</tagConverterFactory>
</extension>
6.運(yùn)行
讓我們運(yùn)行這個(gè)插件。
在運(yùn)行后,建立一個(gè)動(dòng)態(tài)的web項(xiàng)目,然后把我們的tld文件復(fù)制到項(xiàng)目的WebContent下。再新建一個(gè)jsp文件,用WebPageEditor打來,然后我們?cè)賹⒂覀?cè)畫板上的mybutton拖入編輯器:
怎么樣,不錯(cuò)吧。
7.未完待續(xù)
其實(shí)這只是一個(gè)開始,記得一開始為什么我會(huì)將mybutton設(shè)置上width和height,但后面就沒說了,這些都要留到后面。
后續(xù)文章我還會(huì)講一些其他的東西,比如如何擴(kuò)展IElementEdit、屬性的頁、Palette的顯示等等。
謝謝大家,再見。