レベル: 中級 Steve K Speicher (sspeiche@us.ibm.com), Senior Software Engineer, IBM Andy Smith (andybs@us.ibm.com), Advisory Software Engineer, IBM
2007年 10月 30日 今日の Web ベースのリッチ・テキスト編集には、ブログやウィキ、ソーシャル・ネットワーキング・サイトその他が含まれます。XForms の標準的なコントロール・セットを拡張し、このリッチ・テキスト編集を実現する方法を学びましょう。
はじめに
XForms は XML コンテンツに対する厳密な処理モデルを提供します。XForms 標準は、対象の XML 要素または属性の中でテキスト編集を行えるコントロール (テキスト入力やコンボ・ボックス、テキスト・エリアなど) を定義しています。Web ベースの多くのアプリケーション (例えば E メールやブログ、ウィキなど) で一般的となっているリッチ・テキスト編集を利用すると、XForms のコントロール・セットを拡張してリッチ・テキスト編集機能を持たせることができます。
ここではいくつかの方法を紹介しますが、それ以外にも多くの方法が考えられます。この記事の目的はリッチ・テキスト編集用に特定の XForms 実装やウィジェットを選び出すことではなく、リッチ・テキスト編集機能を持たせるための現実的な方法を紹介することです。
リッチ・テキスト・エディター・ウィジェットを選択する
HTML コンテンツ用の HTML リッチ・テキスト・エディターや ECMAScript リッチ・テキスト・エディターは、非常にたくさんあります。それらを選択する際の重要な要素を以下に挙げます。
価格: 無料のエディターも購入が必要なエディターも、多数あります。その見つけ方は「参考文献」を参照してください。
XHTML: XForms のデータ・モデルは XML をベースにしているため、XHTML (XML 化されたバージョンの HTML) をサポートするエディターを選択することが最も適当なように思えます。
HTML サポートの完全さ: もう 1 つの要因が、全体としてどんな機能が含まれているかです (つまりリストや表、スタイル設定など)。
ブラウザーのサポート: この記事の作成とテストでは主に Firefox を使いましたが、全体的なサポートを考慮してあります。
拡張性: 必要な機能をエディターに追加するための、あるいは既存の動作を制限するための拡張性。
そこで、この記事では Dojo を使用し、また FCKEditor を使ったサンプルも提供します。
方法
XForms のコントロール・セットを拡張し、リッチ・テキスト編集機能を持たせる方法の詳細を説明する前に、まずは概要を説明しておきます。ここでは XForms とリッチ・テキスト・エディターが必要なので、エディターの内容を XForms のインスタンスにバインドするための機構も必要です。これは、大量の JavaScript を作成することで、あるいはユーザー・インスタンスのコントロールをバインドするための XBL (XML Binding Language) と呼ばれる別の技術を使って実現することができます。Mozilla の XForms には XBL を使って既存のユーザー・インターフェース・コントロールを拡張する方法が用意されているので、XBL による方法を選択した方が得策です。XBL について、また XBL によるこのような Mozilla XForms コントロールの拡張についての詳細は「参考文献」を参照してください。
このコントロールは、最初に読み取り専用モードで表示を行います。Edit ボタンを選択してリッチ・テキスト編集を有効にします。この変更に問題がなければ Save を選択し、そうでなければ Cancel を選択します。
単純なアプリケーション
この記事で使用するアプリケーションは、あるエントリーをブログに投稿するための単純なフォームです。このアプリケーションはテキストの要約をユーザーから収集し、またリッチ・テキスト・マークアップ (XHTML) で構成される、その投稿全体を収集します。下記は編集インターフェースの一例です。
図 1. XForms のリッチ・テキスト・エディター
このエントリーに問題がなければ、この投稿をブログ・アプリケーションに送信することができます。
上記の編集セッションの結果、下記の XML インスタンスが作成されます。
リスト 1. ブログ・エントリーの例の XML インスタンス
<?xml version="1.0" encoding="UTF-8"?>
<blog>
<subject>Sample Blog Entry </subject>
<content>
<span xmlns="http://www.w3.org/1999/xhtml">Sample <b>BOLD</b> text<br/>
and <i>italics</i> and <u>underline</u> and<br/>
<strike><u><i><b>all together</b></i></u></strike><br/></span>
</content>
<tags/>
</blog> |
カスタムのリッチ・テキスト・エディター・コントロールを定義する
このセクションでは、カスタム・コントロールを定義する上で必要なことについて説明します。不自然に思えるかもしれませんが、この機能を実現するために <xforms:trigger> コントロールを拡張します。<xforms:trigger> コントロールを拡張することにした理由は、そうすることで XML の複合コンテンツ・モデル (属性と要素、またはそのいずれかを持つ XML ノード) にバインドできるようになるからです。もし textarea を選んだとすると、xforms-binding-exception を受信することになります。なぜなら textarea は XML の単純なコンテンツ・モデル (テキスト・コンテンツしかもたない XML ノード) に限定されているからです。
CSS を使ってカスタム・コントロールをバインドする
XBL 実装にコントロールをバインドするために、要素と属性の値のマッチングによってバインドを行う CSS セレクターを使います。ここでは <xforms:trigger> を使っており、そしてそれを、値「rte」を持つ属性 appearance を使って修飾します。そうすると XForms コントロールは次のようになります。
リスト 2. XForms のカスタム・トリガー・コントロール
<xforms:trigger ref="/blog/content" appearance="rte">
<xforms:label>Content: </xforms:label>
</xforms:trigger> |
これを XBL バインディングにリンクする CSS は次のようになります。
リスト 3. XBL コントロールへの CSS バインディング
xforms|trigger[appearance='rte'] {-moz-binding: url('rte-dojo.xbl#richtext'); } |
概要を示したとおり、これによって appearance='rte' を持つ <xforms:trigger> が選択され、この <xforms:trigger> は「richtext」で識別されるバインディングを使って rte-dojo.xbl ファイルにバインドされます。CSS のプロパティー -moz-binding は Mozilla の実装に特有のものです。
XBL でエディターを統合する
XForms のコントロールに埋め込んでエディター・ウィジェットを使うための主なコンポーネントは 4 つあります。その 4 つは、バインディング宣言、コンテンツ、プロパティー、そしてメソッドです。
バインディング宣言:
下記は、このシナリオに使われたバインディング宣言です。このセクションで注目すべき重要な部分の 1 つが xformswidget-base の継承です。この継承のおかげで nsIXFormsUIWidget インターフェースを利用することができます。コントロールは、このインターフェースを利用して XForms エンジンとやりとりすることができます。カスタム・コントロールの詳細については「参考文献」を参照してください。
リスト 4. XBL バインディング宣言
<xbl:binding id="richtext"
extends="chrome://xforms/content/xforms.xml#xformswidget-base"> |
コンテンツ:
XBL のコンテンツ・セクションは、バインドされたノードの子として挿入される、デフォルトのコンテンツを定義します。下記で作成される、anonid="content" を持つ <div> はプレースホルダーとして使われ、そこには現在のノードのアクションに応じて、バインドされたコンテンツが挿入されます。このコンテンツ・セクションは、Edit ボタンと Save ボタン、そして Cancel ボタンを作成するためにも使われました。デフォルトで、これらのボタンは「display:none」に設定されます。これらのボタンは、このバインディングで提供されるメソッド実装によって有効になります。
リスト 5. XBL のコンテンツ定義
<xbl:content>
<span>
<xbl:children />
</span>
<div anonid="content" onclick="javascript:parentNode.displayEditor();"
style="border: thin black solid; background-color:
rgb(211,233,254); width: 400px;">
</div>
<input anonid="editButton" type="button" value="Edit"
style="display:none"
onclick="javascript:parentNode.displayEditor();" />
<input anonid="saveButton" type="button" value="Save"
style="display:none"
onclick="javascript:parentNode.saveEditorChanges();" />
<input anonid="cancelButton" type="button" value="Cancel"
style="display:none"
onclick="javascript:parentNode.cancelEditorChanges();" />
</xbl:content> |
プロパティー:
プロパティーは、このバインディングに対する属性を定義するための方法です。現在のエディター・インスタンスに対して、dojo.dom モジュールの基本機能を使用するバインドされたコントロールの固有 ID を作成し、保存するために、属性が必要です。属性によって固有の ID が提供され、さまざまなコントロールがその ID を使って ID ごとのウィジェットにアクセスします。
リスト 6. XBL のプロパティー定義
<xbl:implementation implements="nsIXFormsUIWidget">
<xbl:property name="editorId">
<xbl:getter>
<![CDATA[
if(this.getAttribute('editorId'))
return this.getAttribute('editorId');
else
this.setAttribute('editorId',dojo.dom.getUniqueId());
return this.getAttribute('editorId');
]]>
</xbl:getter>
</xbl:property> |
メソッド:
公開されるメソッドは nsIXFormsUIWidget で提供されるベース・インターフェースを継承します。またカスタムのメソッドによって、エディター・ウィジェットをインスタンス化し、コンテンツを保存し、そして変更をキャンセルします。
refresh - 下記の refresh メソッドは nsIXFormsUIWidget によって提供されるベース・インターフェースを継承します。このメソッドは XForms の refresh イベントがディスパッチされると呼び出されます。最初のステップはすべてのノードを削除することです (これまで使用された間にコンテンツ・セクションにノードが残っているかもしれません)。その次のステップは、アクセサーのインターフェース (nsIXFormsAccessors) を使って、(このコントロールの) バインドされたインスタンスの中にあるノードの値を取得することです。このコンテンツは次に、コンテンツ・ノードの子として挿入されます。
リスト 7. XBL の refresh メソッド
<xbl:method name="refresh">
<xbl:body>
<![CDATA[
var content =
document.getAnonymousElementByAttribute(this,"anonid","content");
// Need to replace the div content with boundNode's children <content>
dojo.dom.removeChildren(content);
dojo.dom.copyChildren(this.accessors.getBoundNode(), content);
// Show Edit button, hide Save and Cancel
document.getAnonymousElementByAttribute(
this,"anonid","editButton").style["display"]="";
document.getAnonymousElementByAttribute(
this,"anonid","saveButton").style["display"]="none";
document.getAnonymousElementByAttribute(
this,"anonid","cancelButton").style["display"]="none";
return;
]]>
</xbl:body>
</xbl:method> |
displayEditor - displayEditor メソッドはコンテンツ・セクションで作成された Edit ボタンによって呼び出されます。これによって Dojo の Editor2 ウィジェットがプログラムで作成され、またコンテンツが XML インスタンスにバインドされたノードの中の値で置き換えられます。
リスト 8. XBL の displayEditor メソッド
<xbl:method name="displayEditor">
<xbl:body>
<![CDATA[
var content =
document.getAnonymousElementByAttribute(this,"anonid","content");
var newWidget = dojo.widget.createWidget("Editor2", // widgetType
{id: this.editorId,
toolbarTemplatePath: "rte-toolbar.html",
toolbarTemplateCssPath: "EditorToolbar.css"
}, // widget attributes, for example {title: "Some Title"}
content);
// replace editor contents with that of the bound node
newWidget.replaceEditorContent(
dojo.dom.innerXML(this.accessors.getBoundNode()));
// Hide Edit button, show Save and Cancel
document.getAnonymousElementByAttribute(
this,"anonid","editButton").style["display"]="none";
document.getAnonymousElementByAttribute(
this,"anonid","saveButton").style["display"]="";
document.getAnonymousElementByAttribute(
this,"anonid","cancelButton").style["display"]="";
return;
]]>
</xbl:body>
</xbl:method> |
saveEditorChanges - このメソッドは Save ボタンで呼び出されます。このメソッドは現在バインドされているノードを取得してそのコンテンツを削除し、そして現在のエディターのコンテンツの値で置き換えます。次に、XForms モデルをリフレッシュして再構築するための呼び出しが行われます。最後のステップとして、clobberFocus メソッドと destroy メソッドが呼び出され、エディター・ウィジェットのインスタンスが削除されます。
リスト 9. XBL の saveEditorChanges メソッド
<xbl:method name="saveEditorChanges">
<xbl:body>
<![CDATA[
var content = document.getAnonymousElementByAttribute(this,"anonid","content");
var boundNode = this.accessors.getBoundNode();
// retrieve the current widget
var editedNode = dojo.widget.byId(this.editorId);
// retrieve the contents of the editor
var newNode = editedNode.getEditorContent();
// generate span stub to hold contents
var stubSpan = document.createElement("span");
// set the innerHtml
stubSpan.innerHTML=newNode;
// swap out the contents of the bound node with editor's content
dojo.dom.removeChildren(boundNode);
dojo.dom.copyChildren(stubSpan, boundNode);
editedNode.clobberFocus();
editedNode.destroy(true);
model = document.getElementById("mMain");
model.rebuild();
model.refresh();
]]>
</xbl:body>
</xbl:method> |
cancelEditorChanges - このメソッドは、アクティブなエディター・ウィジェットに対して clobberFocus メソッドと destroy メソッドを呼び出して実行します。これによってすべての変更は失われます。
リスト 10. XBL の cancelEditorChanges メソッド
<xbl:method name="cancelEditorChanges">
<xbl:body>
<![CDATA[
// retrieve the current widget and refresh
var editedNode = dojo.widget.byId(this.editorId);
editedNode.clobberFocus();
editedNode.destroy(true);
this.refresh();
]]>
</xbl:body>
</xbl:method> |
Dojo にパッチを当てる
Dojo Toolkit の Editor2 ウィジェットには、リッチ・テキスト・エディターのための豊富な、そして拡張可能なプラグイン・セットがありますが、この例の場合には少し変更が必要でした。オリジナルのリッチ・テキスト・テンプレートのある部分が作成する XHTML マークアップと JavaScript モジュールが作成する XHTML マークアップは標準に準拠していません。そのため、XForms の XML インスタンスのコンテンツを描画する際や保存する際にエラーが発生します。デモを単純にするために、これらのテンプレートとモジュールのサブセットのみを含めてあります。このデモに付属しているパッチを適用することによって、リッチ・テキスト・エディターの結果として作成されるコンテンツが XML インスタンスを適切に更新するようになります。
パッチを当て、サンプルをテストするためには下記のステップを完了する必要があります。
- 「ダウンロード」セクションから xforms-rte-sample.zip をダウンロードします。
-
http://www.dojotoolkit.org/downloads から Dojo 0.4.3 をダウンロードします。
- dojo-sample.zip をフォルダーに解凍します。
- Dojo 0.4.3 ダウンロードを、
sample フォルダーの下にある Dojo というラベルのフォルダーに解凍します。これによって sample -> Dojo -> dojo-0.4.3-ajax という構造になるはずです。
-
sample\Dojo フォルダー内で XForms_XBL_Editor_Patch.txt を探します。
- このパッチを、patch.exe や Eclipse などのパッチ・ソフトウェアを使って Dojo に適用します。パッチの当て方の詳細は「参考文献」に挙げてあります。
高度な話題
この記事は、XForms アプリケーション内に単純なリッチ・テキスト・エディターを含める方法の概要を説明しています。このエディターにさらに機能が必要な場合には、このリッチ・テキスト・エディターの資料を参照してそれを実現する最適な方法を判断すればよいのです。
あるインスタンスが使用するリッチ・テキスト・マークアップが、XHTML ではないというシナリオがあるかもしれません。その場合にも、リッチ・テキスト・マークアップと XHTML の間で変換が可能な限り、この方法は相変わらず有効です。リッチ・テキスト・マークアップから XHTML への変換をプログラムして displayEditor メソッドに組み込み、ノードを直接ロードする代わりにノードを最初に XHTML に変換し、それを使ってエディターのコンテンツをロードするのです。そして、保存が呼び出されたら、この XHTML をリッチ・テキスト・マークアップに変換してから、これらのノードを XForms インスタンスへと戻して保存します。
まとめ
Xforms、XBL、そしてリッチ・テキスト・エディターによって定義されるいくつかの統合ルールに従うことによる最終的な結果として、XForms のコントロール・セットに対して単純かつ強力にリッチ・テキスト・エディター機能を追加することができます。これによって、ブログや E メール、ソーシャル・ネットワーキングなど、さまざまなアプリケーションにも XForms を応用できるようになります。そうすると、妥当性の検証や XML 送信、宣言型プログラミングなどのために元々 XForms に組み込まれている機能を活用することができます。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Samples for both Dojo and FCKeditor | xforms-rte-sample.zip | 8KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | |  | Steve Speicher は、インフラ・ベースと (医療) 業界専用の両方に関する新興標準に取り組む IBM の Senior Software Engineer です。彼は W3C の Compound Document Formats Working Group のメンバーであり、Compound XML Document Toolkit の開発のリーダーでした。また彼はモデル駆動開発 (MDD: Model-Driven Development) を使って標準の開発の改善を行っています。以前は Rational 部門と IBM 社内ツール部門で変更とリリースの管理ツールの業務を行っていました。 |
 | |  | Andy Smith は IBM の Advisory Software Engineer であり、さまざまな業界専用の、XML と SODA (Service Oriented Device Architecture) が関係する新興標準に取り組んでいます。彼は以前、IBM の Global Business Services でさまざまな Web 技術とポータル技術に取り組んでいました。 |
記事の評価
|