たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。
の動向はもえじら組ブログで。
宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
FUEL廃止はJetpackの台頭と対になっているよ、という話。
FUELとJetpackは、コンセプトが確かに重複してるんですよね。
違うのは、FUELはあくまで既存の「拡張機能」という枠組み(JavaScriptやXULやCSSを使って、XPI形式にして、云々)の中でそれを達成しようとしていたのに対して、Jetpackは「そもそもXULとか要らなくね? JavaScriptだけでよくね?」とちゃぶ台をひっくり返してその目的に特化した物をゼロから作った所だと思う。
「Firefoxに機能を追加するなら拡張機能を使いましょう」というのは、実装の仕方をなるべく1種類にまとめて世界を分かりやすくしたいという、開発者目線の考え方のように思う。そうではなく、「Firefoxに機能を追加できるなら、拡張機能でもGreasemonkeyでもUbiquityでもJetpackでもStylishでも何でもイイじゃん。なんで拡張機能に拘らないといけないわけ?」とユーザー目線の発想で考え直したら、FUELみたいな子供だましではなく、Jetpackのように実行環境を1個丸ごと作りなおす事になりました、と。そういう話の流れなのだと僕には思えた。
既存の拡張機能の作り方に特化して知識を溜め込んできた僕にとっては、はっきり言って恐怖ですらある。自分の存在価値、アイデンティティを揺るがす事態だ。だって、大学在学中からMozillaにのめり込んで、それが縁で就職までしてしまって、今もそれをネタに仕事してるんだもの。
そんな僕にとっては、Jetpackが優遇されてFUELが廃止されるというのは、今まで自分が慣れ親しんでいたやり方が否定されて、開発元からも邪険にされて、お前らは時代遅れなんだよプギャーと指さして笑われて、時代の変化についていけない奴らは死ねばいいじゃないと見捨てられてる、正直そんな気分です。
でも、「今までのやり方が全く通用しない世界に飛び込んでいく」事を恐れて今いる所に留まり続けるのは、それこそ座して死を待つだけだという事も分かってる。
それに、そういう「今までのやり方が全く通用しない世界」を作るのであれば、どうせなら、今までのしがらみから完全に切り離された理想の世界を作って欲しいとも思う。XULやXPConnectといった古いやり方しか知らない僕みたいな人間のために「ほうら今までのやり方も使えるんですよ? だから怖がらないで入ってきて下さいよ」と媚びを売って、古いしがらみまでまた抱え込んでしまうのは、やめて欲しい。
僕はそう考えているので、だから今のJetpackでXULやXPConnectを触れるのは非常にマズイ事態だと思ってる。せっかく理想郷を作ろうとしてるんだったら、そこにつまんないしがらみを持ち込んでくれるなよと。僕みたいなロートルが、新しく出てきたJetpackという世界を、古臭い駄目なやり方で汚していってしまう事が許せないのです。老兵は潔く去らないといけないし、潔く去らせないといけないじゃないか。老兵に取り付く島を与えちゃ駄目じゃないか。そんなことをしたら、僕みたいにだらしのない老兵は甘えてしがみついちゃうじゃないか。
まあそれはさておき、FUELを出してきた時に「これで簡単に作れるようになれますよ」「安定したAPIが提供され続けますよ」なんて夢みたいな事を吹聴していた人達には、「すんません自分はバカでした。見る目がありませんでした。」と謝罪して欲しい所ですよね。それを真に受けて酷い目にあった被害者までいるんだし。うん、僕のことですね。ごめんなさい……
こないだから作ってる汎用のアンドゥ・リドゥ用ライブラリを使って、タブ関係の操作をなんでもアンドゥできるようにするアドオンを作ってみた。名前はそのままUndo Tab Operationsです。
ライブラリ自体が実験段階だし、そのライブラリの使い方も(自分で作っておきながら)まだよく把握しきれてないので、練習がてらという感じです。動作は全体的に非常に怪しいです。あと、これを作る上で「あーこういう機能が必要だよな」と躓く度にライブラリの方に手を入れているので、一体何が目的だったのかもうワケが分かりません。
そう。目的。そもそもは「ツリー型タブでウィンドウをまたいだタブの移動を取り消せるようにしたい」的な所が出発点だったはずなんですよね。なのにどうしてこんなに遠回りをしているのか。富豪的にも程がありますよね。
まあ、「リンクからタブを開く時に今のタブのすぐ右にタブを開きたい、ただし連続してリンクを開く時は開いた順に整列させたい」という目的を達成するためだけに、すべてのタブの親子関係を完全に保持する、なんていうめちゃめちゃ無駄なことに力を注ぐような僕のやる事ですからねぇ。
とりあえずこのアドオンで一通りの基本的なところをカバーして、次に親子関係が絡まない単純な応用という事でマルチプルタブハンドラを、最後にツリー型タブを対応させるという感じで作業を進めていこうかなー。と。思ってますけどどうなるかは分かりません。現段階でものすんごいバグバグなので、ひょっとしたら全部お蔵入りになるかもね。
robocopyを使ったズボラなバックアップで1TBのHDDに3世代のバックアップを作ってたんだけど、CD-Rに焼いて逃がしてたMP3ファイルとかiTunesに突っ込みまくってたらとても3世代は入り切りそうにない感じになってきたんで、2世代だけのバックアップだけにすることにして、一番古いバックアップを消そうとした……んだけど、引っかかりまくってうまく行かない。
コマンドプロンプトを開くときは一応、右クリックして「管理者として実行」で。
半年くらい前に真琴さんの記事を見てTwitterIrcGatewayを導入したけど全然使いこなせてなかったけど他の人が他の人に教えてもらってるのを横で盗み見て設定したらちょっと使いこなせるようになった気がしたよ。
酷く今更です。
ツリー型タブのAPIでこんなのが欲しいというのがあったら言っておくれと書いたところ、Alice0775さんからタブバーのドラッグ操作とかツリーのドラッグ操作とかをアンドゥする機能が欲しい(大意)という要望をいただいた。
そういえばこの前のMozilla勉強会の後の懇親会で、新しいタブが開かれたり新しいウィンドウが開かれたりした時に「戻る」ボタンで元のタブや元のウィンドウに戻れないことについて、あらゆる操作がアンドゥ可能になってないといけないんじゃないの?とかそんな感じの話が出ていたと思う。なので実験的にそういう物を作り始めてみた(自動テスト)。
var current = TreeStyleTabService.currentTabbarPosition;
window['piro.sakura.ne.jp'].operationHistory.doUndoableTask(
// やり直し可能にしたい処理
function() {
TreeStyleTabService.currentTabbarPosition = newPosition;
},
// 履歴の名前(省略可)
'TabbarDNDOperations',
// ウィンドウごとの履歴の場合の対象ウィンドウ(省略可)
window,
// 履歴の項目
{
// 項目名
label : 'タブバーの位置変更',
// アンドゥの時に実行する内容
onUndo : function() {
TreeStyleTabService.currentTabbarPosition = current;
},
// リドゥの時に実行する内容(省略可)
// →省略時は上記の「やり直し可能にしたい処理」が自動的に
// onRedoとして登録される
onRedo : function() {
TreeStyleTabService.currentTabbarPosition = newPosition;
}
}
);
という感じでアンドゥ・リドゥ時の動作を登録して、window['piro.sakura.ne.jp'].operationHistory.undo('TabbarDNDOperations', window)
とかwindow['piro.sakura.ne.jp'].operationHistory.redo('TabbarDNDOperations', window)
とか書くとヨロシク処理してくれる……という風な感じ。「あらゆる操作を一次元で記録して」とタイトルに書いてるけど、自動的に記録するんじゃなくてアドオン作者が手作業で記録する前提で、「履歴の記録」「履歴の呼び出し」の所を管理する手間を軽減するだけのライブラリなんで、そこの所はお間違えなきよう。
関数をそのまま登録するというのが乱暴と言えば乱暴なんだけど、柔軟性を高くしようと思ったらこうするのが手っ取り早いかなーって思いまして。一応ウィンドウごとの履歴とグローバルな履歴の両方を持てるようにしてみてる。イメージ的には、Adobe製品のヒストリ機能のような物を目指してる。
で、枠組みは用意したんだけど、タブバーの位置の移動みたいな単純な機能はいいとして、ツリーの移動みたいなややこしい物をどうやってアンドゥ・リドゥさせるかで暗礁に乗り上げてる。
なんとなく、ツリー型タブからは分離して「タブバー上のあらゆる操作をアンドゥ可能にするアドオン」を新しく作った方がいいような気がしてきた。で、ツリー型タブが入ってる時はそいつのアンドゥ履歴の中に「タブバーの位置変更」の項目が混ざってくる、みたいな連携の仕方。
ツリー型タブに他のアドオン向けのAPIを加えていきたいという話を書いた関係でコードをあちこち見直して書き直していて、カスタムイベントを通知→イベントを捕捉した側でキャンセル→イベントを通知した側でキャンセルを検知して処理を中断 という事をやりたくなって調べた結果をmodestにまとめてみた。
ここに書かずにmodestの方に書いたのは、話のレベル的に今更感があったのと、わりと基礎的な話だからこんな世界の果てのオメガギークの日々の下らない愚痴に混ぜて書くだけにしたら誰にも見てもらえないんじゃないか(それよりももっと多くの人に読んで貰って取り入れてもらって、アドオン同士の連携を取りやすい世の中になってくれると嬉しい)と思ったというのと、というあたりが理由です。
でもなんかほんと今更過ぎるというかものすげえ基本的なことを得意げに解説してしまった気がしていて、失敗だったかなあとちょっとブルーです。
Tree Style Tab 0.8.2009122501でTabberwocky用のコードを入れました。とりあえず、選択範囲のリンクをタブで開く機能と、新しいタブを現在のタブのすぐ隣に開く機能については、ちゃんと動くことを確認してます。他にうまく動かない機能があったら言って下さい。Tab Mix Plusに比べたら全然コードの量も少ないんで、たぶん対応できると思う。
Tab Mix Plusと組み合わせた時の問題もどうにかしようと思ったんだけど、見てみたらTMPの中にTST用のコードが入ってたので、さっくり諦めた。お互いがお互いに手を出すともはや収拾が付かなくなるから。なのでちょうどいい機会だと思って、TMPのフォーラムに「いいかげんこの状況なんとかしようよ」的な提案を書き込んでみた。そのついでに、ソースコード中で「PUBLIC API」と書いておきながら説明を書き忘れてたAPIをドキュメントに追加した。
他のアドオンと連携を取りやすくするためのAPIを加えるのはやぶさかじゃないので、要望があれば是非言ってください。最近の例では、TreeStyleTabService.currentTabbarPosition
やTreeStyleTabService.treeViewEnabled
はメールで「こういう事をしたいんだけどどうすればいいのさ」と問い合わせを受けたので追加したAPIです。
ツリー型タブとClose tab by double clickの競合について報告をもらった。
向こうのコードを見てみたら、タブバーの上でダブルクリックされた時にそのイベントがタブの中で発生したものかどうかを検出するのにevent.originalTarget
とそのparentNode
だけを見ていて、ツリー型タブによって追加されたバインディングがあると判別に失敗するようになっていた。これはツリー型タブだけの問題じゃなく、バインディングを加えるあらゆるアドオンと衝突の可能性があるし、テーマによっても衝突する。バインディングに変更を加えなくても、タブの中に何か要素を追加するアドオンは全部衝突する。
いいかげん、こういう時にはDOM3 XPathを使うのが常識になってて欲しいです。こんな所で他のアドオンと衝突する可能性を残す必要はない。
clicked : function(event) {
if (gBrowser.mTabs.length <= 1) return;
var tab = document.evaluate(
'ancestor-or-self::*[local-name()="tab"][1]',
event.originalTarget,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
if (tab) gBrowser.removeTab(tab);
}
こういう風に書けば、クリックされた要素の祖先まで辿って確実に判別できる。他にも絞り込みの条件を付けたければ付けられる。
「シンプルに作る事」と「手抜き」とは、必ずしも一致しませんよね。
画面の描画を一時停止する方法を先日書いたけど、案の定というかやっぱりというか、重大な弊害があることが分かった。また、その弊害にぶち当たらない安全なやり方も見つけることができた。
安全に画面の描画を一時停止・再開する方法は、以下の通り。
var baseWindow = window.top
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIBaseWindow);
baseWindow.setPosition(window.innerWidth, window.innerHeight); // これで画面の描画が止まる
gBrowser.addTab(); // これによって起こる変化は画面上に現れない
gBrowser.addTab(); // この変化も画面上に現れない
gBrowser.addTab(); // 同上
baseWindow.setPosition(0, 0); // ここでやっと描画が再開される
以下、前のエントリに書いたやり方にどういう弊害があるのか、および、このエントリで紹介するやり方の方がどのくらい安全なのかについて詳しく説明する。