たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。
の動向はもえじら組ブログで。
宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
ツリー型タブでずっと前から発生条件が分からなくて困ってた「一つもタブが選択されていない状態」になってしまうバグの原因がやっと分かったので、速攻で修正した。
この問題は、以下の条件がすべて揃った時に発生していた。
この時、内部的にどういう処理が行われていたかというと、以下のような感じだ。
この「TabCloseイベント」というのがFirefox 2以降で使えるAPIなんだけれども、問題は7のステップで起こっていた。7のステップで「次に選択するべきタブ」を決定するためのキーとして「現在開いているタブの総数」を使っているのだけれども、その値は1のステップの間に取得しているため、1から7までの間のどこかでタブの数が増減した場合、タブの選択状態が狂ってしまうのである。7のステップで「現在のタブまたはそれよりあとのタブ」が選択される場合、ここでは4のステップでタブの数が減少しているため、「次に選択するタブの番号」が「すでに削除されたタブ」のインデックスを指し示すことになり、selectedTabの値がundefinedとなりNull Pointer Errorが発生してしまう。……というのが事の真相だった。
ツリー型タブの側でselectedTabのセッタを上書きし、もし存在しないタブが選択されそうになった時は強制的に最後のタブを選択するようにしたところ、「一つもタブが選択されていない状態」は発生しなくなった。以下はそのためのコード。
// var b = gBrowser
var getter = b.__lookupGetter__('selectedTab');
var setter = b.__lookupSetter__('selectedTab');
eval('setter = '+setter.toSource().replace(
'{',
'{ if (!val) val = this.mTabContainer.lastChild;'
));
b.__defineGetter__('selectedTab', getter);
b.__defineSetter__('selectedTab', setter);
この部分ではなく、removeTabメソッドを上書きするという手もあるんだけど、ここはいろんなアドオンが上書きしたがるためコンフリクトの原因になると思ったので、「標準的な動作と変わってしまう」ことは仕方がないと割り切って、ほとんど誰も触らないであろうselectedTabの方を上書きするようにした。ちなみに、ゲッタとセッタ両方を定義し直しているのは、片方だけを再定義するともう片方が未定義になってしまうから。
表題の件に流れを戻すと、「タブを閉じる」という操作をイベントとして捕捉できるようにしたのなら、そのイベントをトリガーにして他のタブを連動して操作するという機能も当然登場してくるわけで、そういうことを考慮せずに「はいはいイベント発行すりゃいいんだろdispatchEvent っと!」と適当に設計してしまうとこういうトラブルが起こるので、APIを作る時にはもうちょっと慎重になった方がいいよね、という教訓を得たという話なのでした。
先日、ツリー型タブのアピール文を英語で書くために人の手を借りながらああでもないこうでもないとやってるうちに思ったことなんだけど。図らずも、大学の卒業制作でやったWeb Mapで実現したかったことの一部を、僕はツリー表示とサムネイルによって手に入れていたようだということに、今頃気がついた。
タブのツリーは、今まで「ページ同士の関係性が分かる」という風に説明をしてきた。でも、実際にもたらされる効果の面から言い換えると、「あるページを基点にした閲覧の足跡をそのまま、興味が移り変わっていく様子=ツリーの分岐という形で保持し、好きな時点の興味の対象の間を容易に行ったり来たりできるようにする、視覚的な履歴」ということになると思う。
デスクトップ百景のスクリーンショットを見ての通り、僕はタブをたくさん開く方だと思うけど、べつに、多数のページを本当に平行して見ている訳ではない(そんな聖徳太子みたいなことはできない)。実際には、「後でもう一回読み返そう」「後でコメントしよう」「後で日記のネタにしよう」そう思った物を「読みかけ」「保留状態」で置いたままになっているだけだ。
そういう用途だったらブックマークを使えばいいじゃないかと言われるかも知れないけど、僕にとってはそれでは駄目なんだ。ブックマークはフォルダに放り込んでしまったらもう見えなくなる。画面がスッキリしていいんだけど、それはつまり意識の外に行ってしまうということで、「どこに何がある」ってことをちゃんと記憶しておかないとすぐに忘れてしまう。ソーシャルブックマークもそうだし、同様の理由で多分僕にはRead it Laterも使いこなせないと思う。
でもタブは、明示的に閉じない限りは視界の隅に残り続ける。他のことをし終わって一息ついた時、「ああ、そういえばこれがまだ未処理だった」という風に自分から主張してくる。そういう未処理のがスクが溜まって、タブがどんどん増えてくると、タブバーがだんだん狭苦しくなってきて、「ああ、そろそろ片付けなきゃな」って気になってくる。
ウィンドウ上部に水平に置かれたタブでは、勝手が悪い。たくさんタブを出そうと思ったら、一つ一つのタブが小さくなりすぎて何のタブだったかが分からなくなるし、タイトルが読めるような大きさでタブを表示すると、1画面の中に数個しかタブが表示されなくなる。これでは、自分のしていたことをざっと俯瞰することができない(「タブの一覧を表示」ボタンもあるにはあるけど、「モード」の切り替えを必要とするので、僕には馴染めない)。ある程度の情報を表示できる状態のタブを、10とか20とか表示できるのは、ウィンドウ左右での「縦置きタブ」ならではの利点だ。
単にタブを縦に並べただけでも不十分だ。確かにさっきは「自分のしていたことをざっと俯瞰できないから嫌だ」と書いたけど、でも、していたことの子細が全部一度に見える必要はない。全教科のノートの全ページを並べて見せられるより、それぞれのノートの表紙だけ並べて見せられた方が、余計な情報が少なくて、「ざっと見る」という目的に即しているだろう。そういう意味で、それぞれのツリーを折り畳んで、各ツリーの基点になった「親」のタブだけをざっと眺めることができるツリー型タブは、先ほどのノートの例え話にも似た効果がある。
こういう使い方をするにあたっては、それぞれの「タブ」が含んでいる内容を常時見ることができるようになっていると、なお良い。情報化タブでモードレスに常にサムネイルを見えるようにしているのは、そういうことだ。
最近仕事でRuby on Railsをやらないといけなくなって、MVC(データと、その表現形式と、制御)をきちんと分離するという考え方に今頃になって触れた。確かにプログラムを作る時はそれらは分離した方がうまく行きそうだけど、ユーザの目に見える時にはそれらが一体になっている方が多分いい。レバーを上げ下げすれば「操作できる」と同時に「データ(状態)が変わり」、さらには「今の状態が表現される」、という風に、原始的なUIはMVCが一体になっているからとても分かりやすい。プログラムを作る段階では構成要素ごとにMとVとCに分解しても、その後、それをユーザに見せる時にはもう一度統合するということが必要なんじゃないかと思う。
需要がどれだけあるか分からんけど、ツリー型タブをTab Mix Plusと同時に使えるようにしてみた。といっても左右にタブバーを表示した場合限定で、それ以外の場合については全然まったく動作確認を行っていないので要注意。とりあえず多段タブの設定になってる時はそれを自動的にキャンセルするようにはしてあるけど、TMPの設定次第ではグッチャグチャになる可能性もある。
TMPによって改変された後のDOMツリーは旧TBEを思わせる混沌とした有り様で、解析するのにえらく骨が折れた……
タブブラウザ拡張3を公開しました。
……といっても実際にタブブラウザ拡張のバージョン3を作ったわけではなくて、情報化タブ、マルチプルタブハンドラ、ツリー型タブ、ソース表示タブを以前訳したマルチアイテムパッケージの作り方のまんまで一つにパッケージングしただけですハイ。「TBE3」をインスコすると上記4つのアドオンがアドオンマネージャに普通に並びます。
まあ、色々要望等はあると思うけど、僕にとってはこれだけ揃ってたら「TBE3」と名前を付けてもべつにいっかなーと思えている、僕にとっての「タブブラウザ拡張」の「他では替えが効かないもの」はこういう事かな、という感じです。
僕自身はこれに加えて以下のアドオンを組み合わせて、旧TBEで使ってた操作感をなるべく再現して使ってる。
逆に、TBEが持ってた機能で今の環境(他のアドオンとの組み合わせも含めて)に欠けてるのは、タブの複数行表示、タブの色分け、フォーカスの詳細な制御、タブのロック、自動リロード、別サイトへのリンクを常に新規タブで開く(別サイトへのリンクをタブで開く機能はツリー型タブ 0.3.2007102902に実装した)、リファラの送信禁止(Adaptiva Referer Removerで代用可能)、JavaScript・Cookie・Refreshによる自動リロード・プラグイン・画像表示それぞれのタブごとの有効無効の設定、それらの情報をブックマークに保存する、といった機能か。
また後で改めて書くけど、タブブラウザ拡張いっこのためにOSのアップグレードすら半年以上(Firefox 2リリースの時から数えれば1年近く)できずにいたので、ついにここまで来たかぁ、と感無量です。
なお、TBE3に含まれている4つのアドオンはどれも一応最近のMinefieldで動作確認はしてるので、次のFirefoxメジャーアップデートの時には今回よりはすんなり移行できるんじゃないかなと思ってる。まあまだUIまわりが(特にタブが)色々変わる可能性はあるようなので安心はできないけど。
公開した後から言うのもナンだけど、横長のタブバーでツリー表示にはやっぱり無理があるよねぇ……横長の時は多段タブバー、縦長の時はツリー、というのが最強のような気がする。縦長で多数列とか横長でツリーとか、逆の組み合わせは正直言って使いにくいことこの上ない。設定UIからは削って隠し機能止まりにしといた方がよかったかも。「できる」というのと「するべき」というのとは別問題だ、ということを痛感した。
View Source in Tab。その名の通り、ソースの表示をタブで行うようにするだけという物。ツリー型タブの機能として加えようとしてて、よく考えたらこれツリー関係の機能関係なくね? と思ったので別途リリースすることにした。
作り始める前に「そういえばそんな名前のアドオンがすでにあったような気がするんだが……」と思って「View Source in Tab」で検索してみたけど見あたらなかったのでそれなりに作り込んでさあそろそろ公開するか、と思ったところでふと「Open Source in Tab」で検索してみたらあっさり見つかったし
まあそれでもせっかく作っちゃったから公開しておく。一応、Open Source in TabやView Source Choiceに比べて以下の点でView Source in Tabの方が高機能ではあります。
でも徹底的に探したわけではないので、これで後から「実はすでにView Source in Tabという名前のアドオンがあるんだが」という風に気がついたら、もうどうしようもない。→ありました
25日追記。無難なところで「Source Viewer Tab(ソース表示タブ)」に改名しておきました……
ツリー型タブのAPIと称して3つのメソッドの使い方を公開しました。以下のようにして使ってください。
// 一つだけタブを開く場合
if ('TreeStyleTabService' in window)
TreeStyleTabService.readyToOpenChildTab(gBrowser.selectedTab);
gBrowser.addTab('http://www.example.jp/');
// 複数のタブを開く場合
if ('TreeStyleTabService' in window)
TreeStyleTabService.readyToOpenChildTab(gBrowser.selectedTab, true);
gBrowser.addTab('http://www.example.jp/');
gBrowser.addTab('http://www.example.com/');
gBrowser.addTab('http://www.google.co.jp/');
if ('TreeStyleTabService' in window)
TreeStyleTabService.stopToOpenChildTab(gBrowser.selectedTab);
アドオンとかユーザースクリプトとかで、現在のタブに関連した情報を新規タブで開くような機能を持ってる物は、これを入れておくとユーザ(主に僕)が幸せになれると思います!
ツリー型タブのAPIと称して3つのメソッドの使い方を公開しました。以下のようにして使ってください。
// 一つだけタブを開く場合
if ('TreeStyleTabService' in window)
TreeStyleTabService.readyToOpenChildTab(gBrowser.selectedTab);
gBrowser.addTab('http://www.example.jp/');
// 複数のタブを開く場合
if ('TreeStyleTabService' in window)
TreeStyleTabService.readyToOpenChildTab(gBrowser.selectedTab, true);
gBrowser.addTab('http://www.example.jp/');
gBrowser.addTab('http://www.example.com/');
gBrowser.addTab('http://www.google.co.jp/');
if ('TreeStyleTabService' in window)
TreeStyleTabService.stopToOpenChildTab(gBrowser.selectedTab);
アドオンとかユーザースクリプトとかで、現在のタブに関連した情報を新規タブで開くような機能を持ってる物は、これを入れておくとユーザ(主に僕)が幸せになれると思います!
ツリー型タブのAPIと称して3つのメソッドの使い方を公開しました。以下のようにして使ってください。
// 一つだけタブを開く場合
if ('TreeStyleTabService' in window)
TreeStyleTabService.readyToOpenChildTab(gBrowser.selectedTab);
gBrowser.addTab('http://www.example.jp/');
// 複数のタブを開く場合
if ('TreeStyleTabService' in window)
TreeStyleTabService.readyToOpenChildTab(gBrowser.selectedTab, true);
gBrowser.addTab('http://www.example.jp/');
gBrowser.addTab('http://www.example.com/');
gBrowser.addTab('http://www.google.co.jp/');
if ('TreeStyleTabService' in window)
TreeStyleTabService.stopToOpenChildTab(gBrowser.selectedTab);
アドオンとかユーザースクリプトとかで、現在のタブに関連した情報を新規タブで開くような機能を持ってる物は、これを入れておくとユーザ(主に僕)が幸せになれると思います!
ツリー型タブのAPIと称して3つのメソッドの使い方を公開しました。以下のようにして使ってください。
// 一つだけタブを開く場合
if ('TreeStyleTabService' in window)
TreeStyleTabService.readyToOpenChildTab(gBrowser.selectedTab);
gBrowser.addTab('http://www.example.jp/');
// 複数のタブを開く場合
if ('TreeStyleTabService' in window)
TreeStyleTabService.readyToOpenChildTab(gBrowser.selectedTab, true);
gBrowser.addTab('http://www.example.jp/');
gBrowser.addTab('http://www.example.com/');
gBrowser.addTab('http://www.google.co.jp/');
if ('TreeStyleTabService' in window)
TreeStyleTabService.stopToOpenChildTab(gBrowser.selectedTab);
アドオンとかユーザースクリプトとかで、現在のタブに関連した情報を新規タブで開くような機能を持ってる物は、これを入れておくとユーザ(主に僕)が幸せになれると思います!