Ubiquityではコマンドのことを「動詞(verb)」と呼んでいます。Ubiquityの動詞は、Ubiquityのchromeエディタ内で、CmdUtilsオブジェクトのCreateCommand()メソッドを使用して作成できます。CmdUtilsは、Ubiquityの動詞と名詞(データ型)の作成を簡略化するルーチンの汎用化ライブラリです。特にCreateCommand()メソッドは最も強力なメソッドで、これを利用して所定の動詞の完全なインフラストラクチャを構築できます。
コマンドを作成するには、オブジェクト構造をCreateCommand()メソッドに渡します。次に示すように、この構造の最初の部分で文書に使用するフックを提供します。
CmdUtils.CreateCommand({
name:"macro",
author: { name: "Kurt Cagle", email: "kurt@oreilly.com"},
contributors: ["Kurt Cagle"],
license: "Apache License, v.2",
homepage: "http://www.xforms.org/xrx/?q=ubiquity",
description: "Performs regular expression replacements of web page content.",
help: "The macro verb takes the URL of a dictionary file (which can be set up as a default using the
defaultURL property) and uses it to replace each regex term with its corresponding replacement value in either
a web page (if no content is selected) or within a given selection (if one has been).",
...
もちろん、本当に必要なのはnameだけです。これは、Ubiquityのコマンドラインから使用する動詞の名前そのものです。残りは、 command-listをUbiquityのコマンドラインに入力することで表示されるものなど、ユーザーインターフェースで使用されるものです。
これらのほかに、takes:、preview:、execute:という3つの非常に重要なタグがあります。takes:タグは、previewとexecuteが使用するパラメータの名前を指定します(値はUbiquityコマンドラインで渡されます)。
takes:{"sourceURL":noun_arb_text},
noun_arb_textは、このパラメータ情報が3つの値(text:、html:、data:)を公開するオブジェクトに格納されることを示します。どのように格納されるかは、パラメータ情報のソースに応じて異なります。
preview:タグは、Ubiquityウィンドウ内にコマンドのプレビューを表示する場合に使用する関数定義です。この関数は、takes:で渡されるパラメータと、プレビューブロック(pblock)を受け取ります。プレビューブロックとは、具体的な出力を扱うためにUbiquityウィンドウ内に作成できるdivです。今回の例では、preview関数は辞書ファイルを読み込み、各用語とそれに対応する置換テキストを表示します。
preview:function(pblock,sourceURL){
this._src = CmdUtils.getHtmlSelection();
var table=<table/>;
try{
this._parseEntries(sourceURL,this._src,function(entries,str){
for each (var entry in entries){
table.tr += <tr>td>{entry.term}</td><td>{entry.expr}</td></tr>;
}
pblock.innerHTML = table.toXMLString();
});
}
catch(e){}
},
このコードでは、CmdUtils.getHtmlSelectionがHTMLコンテンツ内の特定の選択範囲を取得し、それをローカルに定義されている_parseEntriesメソッドに渡しますが、今回の例では選択範囲からの情報は使用しません。しかし、Ubiquityは、項目の読み込み後に呼び出されるコールバック関数を作成します。このコールバック関数は、辞書内の各項目のオブジェクト記述と、選択範囲のコンテンツをすべての辞書項目と比較して構文解析した結果の文字列を渡します。その後、このルーチンは項目を反復処理してHTMLテーブルを作成します。このテーブルが、プレビューブロックの内部コンテンツになります。
プレビューは、コマンドが入力している間に表示されます(つまり、キーストロークのたびに更新されます)。入力している内容からエラーが発生する可能性もあるため、previewでは、「安全」なコンテンツのみでプレビューが作成されるようにtry/catchブロックを使用します。
リターンキーを押すと、executeコマンドが呼び出されます。このコマンドでは一般に、ブラウザウィンドウのコンテンツを変更するか、またはUbiquityが使用するポップアップメッセージスタックにメッセージを送信するかのどちらかが要求されます。いずれにせよ、プレビューブロックは更新されないので、execute関数がコールバックとして呼び出されるときにはブレビューブロックは渡されません。
このマクロのexecuteコマンドは、ページ内の古いコンテンツを置換コンテンツに置き換えるために、同じようにlocal _parseEntries()メソッドを呼び出します。
execute:function(sourceURL){
this._src = CmdUtils.getHtmlSelection();
if(this._src==null){
var doc = CmdUtils.getDocumentInsecure();
this._src=doc.body.innerHTML;
this._parseEntries(sourceURL,this._src,function(entries,str){doc.body.innerHTML=str});
}
else {
this._parseEntries(sourceURL,this._src,function(entries,str){CmdUtils.setSelection(str,{});});
}
},
再び、匿名のコールバック関数の使い方に注目しましょう。preview関数とexecute関数は共通のコードを使用しているので、両者の違いは、コードの結果をどう利用するか、ということだけです。
execute関数もpreview関数も、特に必要なものではありません。Ubiquityの動詞の中には単に情報を入手すること(例えば選択範囲内の単語数のカウントなど)を目的とするものもあり、このような場合はexecuteは必要ありません。同様に、previewは持たないがexecuteステートメントは実行するという動詞も考えられます。例えば、指定のURLを新しいタブに表示する「goto」動詞などです。
また、ヘルパー関数とプロパティをオブジェクト内に挿入し、これらをキーワードを介して使用可能にすることもできます。例えば、上記のコードで使っている_parseEntries()関数は、sourceURLから辞書を取得し、解析対象のソースのテキストを引き渡し、辞書項目と処理結果の文字列を含むコールバック関数を呼び出すというステップを組み合わせます(リスト2を参照)。
_parseEntries:function(sourceURL,src,fn){
// if the sourceURL isn't passed, then use the default URL.
if (sourceURL.text == ""){
sourceURL.text = this.defaultURL;
}
// retrieve the dictionary
jQuery.get(sourceURL.text, function(dictionaryXML){
var dictionary=$(dictionaryXML);
var entries=[];
// create the JavaScript entries from the dictionary
dictionary.find('entry').each(function(){
var entry = {term:$(this).find('term').text(),
expr:$(this).find('expr').text(),
isGlobal:($(this).attr('global')=='yes')?'g':'',
caseSensitive:($(this).attr('casesensitive')=='yes')?'':'i'};
// create a regular expression from the term
var entryRE = new RegExp(entry.term,entry.isGlobal+entry.caseSensitive);
// push the entry into the entries list.
entries.push(entry);
// perform the regular expression and make this
// the active string buffer
str = src.replace(entryRE,entry.expr);
src=str;
});
// this invokes the callback function
fn(entries,src);
});
// update the internal macro _src with the last changes.
this._src=src;
}
この例では、内部ライブラリの一部として利用できるjQuery()関数を使ってHTTP get()を実行し、指定のURLからコンテンツを取得して、対応する項目を作成します。$()メソッドはjQuery()の単なる省略形で、ここでは読みやすくするために省略形を使っています。これを各項目に対して繰り返し、置換対象のオリジナルのHTMLを含む文字列バッファを新しいコンテンツで更新します。
