この間は JavaScript で XPCOM コンポーネントを作ったので、今回はその発展として XTF[LINK] の実装に挑戦。XTF (eXtensible Tag Framework) っていうのは XPCOM を用いて新しい XML 要素を実装できるというもので、IE でいうところの Element Behavior (日本語での要約記事) に似てる。Gecko 1.8 (Firefox 1.5) からのサポートなので現時点で試すためには nightly ビルドを使う必要あり。
といってもどんな要素を作ったものかうまく思い浮かばないのでとりあえずカレンダーを作ってみることにする。<calendar xmlns="http://www.ne.jp/asahi/nanto/moon/ns/calendar" />
とすることで今月のカレンダーが表示されるというもの。
XTF ではまず特定の名前空間に対応する XPCOM コンポーネントをひとつ作り、要素の生成はそのコンポーネントが受け持つという形になる。デザインパターンでいうところの Factory Method ってところか。で、そのコンポーネントが実装しなくてはいけないのが nsIXTFElementFactory インターフェース。
interface nsIXTFElementFactory : nsISupports
{
nsIXTFElement createElement(in AString tagName);
};
メンバは createElement
メソッドのみ。というわけでサクッと実装。
function nntCalendarFactory() {}
nntCalendarFactory.prototype = {
createElement: function (tagName)
{
switch (tagName) {
case "calendar":
return new nntCalendarElement();
default:
throw Components.results.NS_ERROR_FAILURE;
}
},
QueryInterface: function (iid)
{
if (iid.equals(Components.interfaces.nsIXTFElementFactory) ||
iid.equals(Components.interfaces.nsISupports))
return this;
Components.returnCode = Components.results.NS_ERROR_NO_INTERFACE;
return null;
}
};
nntCalendarElement
っていうのが実際の要素に当たるオブジェクト。その解説は後回しにしてとりあえずこれを登録してみる。
const XMLNS_NNT_CALENDAR = "http://www.ne.jp/asahi/nanto/moon/ns/calendar";
var nntCalendarFactoryModule = {
_description: "XTF Calendar Factory",
_classId: Components.ID("{1abb1e29-c7a7-45c7-8670-ba8919f0ae6d}"),
_contractId: "@mozilla.org/xtf/element-factory;1?namespace="
+ XMLNS_NNT_CALENDAR,
...
registerSelf: function (compMgr, fileSpec, location, type)
{
...
compMgr.registerFactoryLocation(this._classId,
this._description,
this._contractId,
fileSpec,
location,
type);
},
...
};
function NSGetModule(compMgr, fileSpec)
{
return nntCalendarFactoryModule;
}
"@mozilla.org/xtf/element-factory;1?namespace=NamespaceURI"
という Contract ID で Factory
を登録することによって、<elementName xmlns="NamespaceURI">
という要素が現れたときに Factory.createElement("elementName")
が呼び出されるようになるらしい。CID (Class ID?) は適宜生成。
次は実際に要素を表すオブジェクトの作成。これは nsIXTFElement インターフェースを実装しなくてはいけない。
function nntCalendarElement() {}
nntCalendarElement.prototype = {
// nsIXTFElement の実装
elementType: Components.interfaces.nsIXTFElement.ELEMENT_TYPE_XML_VISUAL,
セコメントをする