2010年6月11日金曜日

[Safari Extension] コンテキストメニューの動的書き換え

レファレンスを見る限りでは、safari.extensionにcontextMenuプロパティがあり、appendContextMenuItemメソッドによりアイテムを追加できそうに見えるのですが、インスペクタで見てもそれらしきプロパティは見当たりません。Global HTML がロードされた時にonloadハンドラ内でコンテキストメニューを構築すれば良いだろう、と考えていたんですがアテが外れました。

頭を抱えていたのですが、イベント受信時にSafariExtensionContextMenuItemがevemt.targetとして渡されるということがわかったので、これのtitle, command, disabledプロパティを設定することでコンテキストメニューを書き換えるという手でやってみましたところ上手くいきました。書き換えるタイミングは、コンテキストメニューが実際に表示される前に発行されるvalidateイベントを受信した段階で、ということになります。

コンテキストメニューに関して制御出来るのはtitleとcommandの書き換えおよびdisabledの設定によりアイテムの表示/非表示を切り替えることだけで、新たにアイテムを追加する事は出来ません。よって、機能拡張ビルダーでダミーのアイテムをあらかじめ10個ほど確保しておきます。こんな感じです。



実際に表示するタイトルとコマンドは設定から読み込みます。patternというキー名で、中味はJSON形式で記述することにしました。



設定はサイト毎に
{"command": "googleEJ", "url": "http://translate.google.co.jp/?hl=ja&tab=wT#en|ja|{}", "title": "lookup: Google翻訳(英和)"}
と記述したものを配列でまとめています。ちなみにurlの{}の部分は、単語やフレーズをencodeURIComponent()したもので置き換えられます。

実際の書き換え処理はvalidateイベントのリスナーで行います。ビルダーで登録したアイテム数ぶんvalidateイベントが発生しますので、設定の個数ぶんだけtitleとcommandを書き換え、余った分はdisabled=trueとして非表示にしています。以下はGlobal HTMLの一部です。initAll()はonloadハンドラで、設定をvar patternに読み込み、addEventListenerでvalidateイベントを監視しています。
var pattern = undefined;
function initAll() {
pattern = JSON.parse(safari.extension.settings.pattern);
safari.application.addEventListener(
"validate",
function(event) {
if (event.command < pattern.length) {
event.target.command = pattern[event.command].command;
event.target.title = pattern[event.command].title;
event.target.disabled = false;
}
else {
event.target.disabled = true;
}
},
false
);
...
という感じで、とりあえず目的は達成したのですが、このやり方はかなりややこしいですね。邪道ぽいですし。やはりレファレンス通り、appendContextMenuItem等で制御出来るようになるのを待った方が賢明かもしれません。

以上の追加内容はGitHubにバージョン1.0.1として上がっていますので、詳細はそちらを御覧下さい。

0 件のコメント:

コメントを投稿