2011-04-03
ポップアップにおける画像の大きさを固定,および nsIAlertsService の問題に関して
tips | |
大きさ固定
Twitter クライアントプラグインのポップアップにおけるアイコンの大きさを固定する方法が FAQ なので.改めて取り上げる.
PRESERVE エリアへ以下の記述を.
style.register(<><![CDATA[ @-moz-document url("chrome://global/content/alerts/alert.xul") { image#alertImage { max-width : 48px !important; max-height : 48px !important; } } ]]></>);
nsIAlertsService
Twitter クライアントプラグインのポップアップ表示には nsIAlertsService を使っている.
この nsIAlertsService だが,バックエンドとして Mac OS X では Growl を使い(インストールされていれば),Linux などにおける X 環境では notify-osd や notification-daemon を使う.こうしたバックエンドはきっちりしているものなので,問題はあまりない.(notify-osd の悲惨さについてはまたの機会に語るとしよう)
一方 Windows では(何も入れていなければ) XUL による Firefox 独自のポップアップが使われるのだが,この XUL によるポップアップがクセモノで,確認している限りでも次のような欠点が存在する.
- 文字の折り返しが効かない
- 画像の大きさが制限されていない
- 1024x1024 px など巨大な画像が指定されていた日には大変悲惨なこととなる
折り返しが効かない
一つめの折り返しが効かない,という問題に対処することはなかなか難しい.説明のため,まずポップアップに使われている XUL ファイルの内容を抜粋して以下に示す.この内容は Firefox で view-source:chrome://global/content/alerts/alert.xul
という URI を指定すれば閲覧することができる.
<window id="alertNotification" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" windowtype="alert:alert" xmlns:xhtml="http://www.w3.org/1999/xhtml" xhtml:role="alert" pack="start" onload="onAlertLoad()" onclick="onAlertClick();"> <script type="application/javascript" src="chrome://global/content/alerts/alert.js"/> <box id="alertBox" class="alertBox"> <hbox class="alertImageBox" align="center" pack="center"> <image id="alertImage"/> </hbox> <vbox id="alertTextBox" class="alertTextBox"> <label id="alertTitleLabel" class="alertTitle plain"/> <label id="alertTextLabel" class="alertText plain"/> </vbox> </box> <!-- This method is called inline because we want to make sure we establish the width and height of the alert before we fire the onload handler. --> <script type="application/javascript">prefillAlertInfo();</script> </window>
ここで注目すべきは次の部分だ.
<box id="alertBox" class="alertBox"> <hbox class="alertImageBox" align="center" pack="center"> <image id="alertImage"/> </hbox> <vbox id="alertTextBox" class="alertTextBox"> <label id="alertTitleLabel" class="alertTitle plain"/> <label id="alertTextLabel" class="alertText plain"/> </vbox> </box>
これを見ると,ポップアップのタイトルとメッセージには label 要素が使われている,ということが分かる.
この label 要素がクセモノで,value 属性にテキストが指定された場合は折り返しが一切なされず,内部テキストノードへテキストを与えた場合には折り返しがなされる,という性質を持つ.実例で示すと,以下のようになる.(参考:Piro/Linuxコマンド操作漫画連載中さんのツイート: "@stillpedant labelとdescriptionは、value属性で文字列を指定した場合は「1行で表示・crop属性に従って末尾を省略」、flex="1"で子要素にテキストノードを置いた場合は「指定幅で折り返して複数行表示」で)
<label value="折り返しがなされない" /> <label>折り返しがなされる</label>
さて,先程の XUL における nsIAlertsService が何をやっているかというと,これは view-source:chrome://global/content/alerts/alert.js
を見ると分かるが,次のようにして label の value 属性に値を設定している.つまり,これではどう頑張っても折り返しは出来ない.
document.getElementById('alertTextLabel').setAttribute('value', window.arguments[2]); // 中略 document.getElementById('alertTitleLabel').setAttribute('value', window.arguments[1]);
この問題に無理やり対処する方法としては,ポップアップが表示される瞬間に上記要素の value 属性に設定されたテキストを取得し,その value 属性を削除した後に label の子テキストノードとしてそのテキストを append する,というものが考えられる.実現には userChrome.js のような仕組みを用いる必要があり,とても面倒だ.
画像の大きさが制限されていない
画像の大きさが制限されていないという問題に対しては,幸いながら比較的簡単な対処法が存在する.nsIStyleSheetService の仕組みを使い,CSS で強制的に画像のサイズを制限してしまえば良い.KeySnail の style モジュールを使う方法に関しては,冒頭に示したとおりだ.
まとめ
nsIAlertsService の XUL を用いたポップアップは非常に出来が悪い.これを改善する方法が,これまでにもいくつか提案されているようだ.
Windows でも Growl for Windows のようなソフトウェアを導入した方が幸せになれるのではないかと,個人的には感じる.
2011-04-01
Tanything など prompt.selector() をあらかじめ編集モード ON (キーマップ無効) で起動
tips | |
Tanything を普段は C-a
に割り当て j, k, g, G といった less ライクなキーバインドで利用している.
これを単純な switch-to-buffer
として使おうと考えた場合,上記の less ライクなキーバインドを無効にして編集モードへ移行するために C-z
を入力する必要があり,これが非常な手間となっていた.
何とかならないか,と考えていたところ prompt.selector
の編集モードは,外部から prompt.editModeEnabled
として触ることができることを思い出した.すっかり忘れていた.
そこで,以下のようにしてみると,うまく Tanything が編集モードで起動してくれた.
ext.exec("tanything"); prompt.editModeEnabled = true;
個人的な設定を以下に示す.
C-x b
は文字列絞り込みによるタブ移動のために,C-a
はタブ一覧を眺めて削除やピン留め*1などの操作を行なうために,それぞれ利用する.
key.defineKey([key.modes.VIEW, key.modes.CARET], 'C-a', function (ev, arg) { ext.exec("tanything", arg); }, 'タブを一覧表示', true); key.setGlobalKey(['C-x', 'b'], function (ev, arg) { ext.exec("tanything", arg); prompt.editModeEnabled = true; }, 'タブを一覧表示 (編集モード)', true);
Ireland2011/10/06 14:45Great aitrcle, thank you again for writing.
2011-03-21
KeySnail 1.8.5 - 相対パス指定, underscore.js, 補完強化
info | |
更新頻度も下がってきたので,少しは真面目にリリースノートを書くことに.
新機能
- 要望の多かった設定ファイルの相対パス指定へ限定的ながら対応
- underscore.js を導入 (ver. 1.1.5)
- prompt の JavaScript コード補完がより強力に
- Vimperator キースキームを改良
- これまでのものは
shell
が導入される以前に作成した遺物だったのでtabopen
の類を追加.需要があるかどうか非常に疑問.
- これまでのものは
相対パス指定は,特に設定を行なう必要がない(設定を行なうことが出来ない!).Firefox の実行ファイルが置かれているディレクトリに .keysnail.js, _keysnail.js
が見つかった場合,従来の場所へ置いてある設定ファイルでなくそちらが利用される.
設定ダイアログから,現在どちらのファイルが利用されているかを確認することが可能.Firefox の実行ファイルが置かれているディレクトリを開くボタンがあるので,適宜利用されたい.
修正点
- Firefox 4 になりプラグインマネージャのヘルプが表示されなくなっていた問題を修正
- WikiParser.js が動かなくなっていた.原因は http://twitter.com/stillpedant/status/49767636082495488 というもの.
- Firefox 4 になり prompt の閉じるボタンが表示されなくなっていた問題を修正
一言
二年近く前から開発しているプロジェクトだけあって,コードは既に黒歴史の様相を呈している.毎回,一から書き換えたくなる衝動と戦っている.
clouderいつもありがたく使わせて頂いています。
昨日、Firefoxを4にバージョンアップしたらcommand.bookMarkToolBarJumpTo()がエラるようになってしまいました。
エラーコンソールには以下のエラーが出ていました。
エラー: toolbarBookMarks is null
ソースファイル: chrome://keysnail/content/modules/command.js
行: 330
該当箇所は以下で、
var toolbarBookMarks = document.getElementById('bookmarksBarContent');
bookmarksBarContentのIDがとれてないようです。
なお仕様しているkeysnailのバージョンは1.8.5です。
よろしければ対応をお願いできたらと思います。
mooz報告ありがとうございます.
https://github.com/downloads/mooz/keysnail/keysnail.xpi をお試し下さい.
clouder上記試したところ問題なく動きました。
ありがとうございます!
clouder何度も申し訳ありません!
一見動いたと思ったのですが、Firefox3と4で以下のように挙動が変ってしまいました。
- Firefox3
ブックマークツールバーを非表示にした状態でもcommand.bookMarkToolBarJumpTo()で該当のブックマークツールバーの内容が表示される
- Firefox4
ブックマークツールバーを非表示にするとcommand.bookMarkToolBarJumpTo()で内容が空になってしまいます。
ちなみにブックマークツールバーを表示にすればちゃんと表示されます。
よろしければご対応お願い致します。
mooz>clouder さん
仕様変更が激しく対応できるかどうかは未定ですが,少し調査をしてみたいと思います.
clouderそうですよねぇ<仕様変更
できたらで問題ありませんので、宜しくお願いします。
まだわからないことだらけですが、自身でも同じような機能をもったプラグインでも作ってみようかなと考えています。
2011-03-20
KeySnail の prompt で IME を自動的に OFF
tips | |
かなり前からちょくちょくあった要望.
以下のようなコードを .keysnail.js
の PRESERVE エリアへ.Windows 7 で動作を確認.Mac もおそらく OK.Linux は NG.
style.register(<><![CDATA[ #keysnail-prompt-textbox *|input { ime-mode : inactive !important; } ]]></>);
oct inaodu を参考にした.
ちなみにここで出てくる *|
というセレクタを知らなかったのだが,Selectors Level 3 を紐解いたところ,名前空間に関するものであることがわかった.以下に引用を.
ns|E
elements with name E in namespace ns
*|E
elements with name E in any namespace, including those without a namespace
|E
elements with name E without a namespace
E
if no default namespace has been declared for selectors, this is equivalent to *|E. Otherwise it is equivalent to ns|E where ns is the default namespace.
一つ賢くなれて良かった.
2011-01-02
サジェスト付き辞書引きコマンド (Urban Dictionary, Goo 辞書)
tips | |
以前 こういったものを書いたが, やはり辞書引きコマンドにはサジェストが必要だろうと感じたので書き直した.
あと, Goo 辞書だけでは物足りないので Urban Dictionary も加えた. Urban Dictionary かわいいよ Urban Dictionary.
(function () { function googleSuggest(word) { const domain = "com"; const base = "http://www.google.%s/complete/search?output=toolbar&q=%s"; let ep = util.format(base, domain, encodeURIComponent(word)); let res = util.httpGet(ep); let matched = res.responseText.match("(<toplevel>.*</toplevel>)"); if (!matched) return null; let xml = new XML(matched[1]); return [cs.suggestion.@data for each (cs in xml.CompleteSuggestion)]; } function googleCompleter(args, extra) { let suggestions = googleSuggest(extra.query || ""); return { collection : suggestions, origin : extra.whole.indexOf(extra.left) }; } shell.add("udic", "Urban dictionary", function (args, extra) { const base = "http://www.urbandictionary.com/define.php?term=%s"; util.setBoolPref("accessibility.browsewithcaret", false); gBrowser.loadOneTab(util.format(base, encodeURIComponent(args[0])), null, null, null, extra.bang); }, { bang: true, completer: googleCompleter }); shell.add("goodic", M({ja: "Goo 辞書", en: "Goo dic"}), function (args, extra) { const base = "http://dictionary.goo.ne.jp/search.php?MT=%s&kind=all&mode=0&IE=UTF-8"; util.setBoolPref("accessibility.browsewithcaret", false); gBrowser.loadOneTab(util.format(base, encodeURIComponent(args[0])), null, null, null, extra.bang); }, { bang: true, completer: googleCompleter }); })();
僕は以下のような感じで m に割り当てています. 便利.
key.defineKey([key.modes.VIEW, key.modes.CARET], 'm', function (ev, arg) { shell.input("udic " + (content.getSelection() || "")); }, 'Lookup the meaning of the word');
追記
Urban dictionary は trim と調べれば pussy と出る, といった具合で色々とアグレッシブなため, m は Goo 辞書で M を Urban dictionary に変更した.
key.defineKey([key.modes.VIEW, key.modes.CARET], 'm', function (ev, arg) { shell.input("goodic " + (content.getSelection() || "")); }, 'Lookup the meaning of the word'); key.defineKey([key.modes.VIEW, key.modes.CARET], 'M', function (ev, arg) { shell.input("udic " + (content.getSelection() || "")); }, 'Lookup the meaning of the word');
KevrelShort, sweet, to the point, FREE-exactly as ionfrmation should be!