たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。
の動向はもえじら組ブログで。
宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。
以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
以前、ツリーの折りたたみでアニメーションするようにしてみた事があった。
この界隈には、GUI要素のアニメーションは嫌いで片っ端から無効にしてて、Web上でもアニメーション効果が使われてると「ウザッ」と思う、というタイプの人が多そうだと思う。でも、アニメーション効果ってのはインターフェースの見た目を考える上で結構バカにできない。
現状のように一気にすべての子タブが出たり消えたりすると、「最初の状態」と「最後の状態」の差が大きすぎて、今自分がどのタブを見ているのか見失ってしまう事がある。でもアニメーションで少しずつ折りたたんだり少しずつ展開したりする事で、「最初の状態」と「最後の状態」の間を段階的に変化させてやると、それほど戸惑わなくて済むようになる。こういう、2つの状態の間を埋めるアニメーションのことを一般にトゥイーンと呼ぶ。使い所を間違えなければ、アニメーションするインターフェースは人にやさしいものとなる。
問題は、再描画が頻繁にかかるのでPCの性能次第では激重になってしまうということ。以前試した時も、自分の環境でとんでもなく重い結果になってしまったので、導入を諦めてた。
で、今日ふと思い立ってもう一度試してみたところ、VistaのAeroが快適に動くような環境ではさすがに快適に動作してくれることが分かった。上記のような小難しい理屈を抜きにしてもヌルヌル動きまくりなのが単純にスゲー面白い。今回はかつて諦めた時のようなフレーム数固定(何回描画したら終わり、というやり方)ではなくフレームレート可変(何秒以内にできる限りの回数だけ描画する、というやり方)で処理するように実装してみたので、貧弱な環境でもそれほど重くはならないと思うんだけど……一応会社のマシンとかで試してみて、問題なさそうなら次版でデフォルト有効にしてみようと思う。
ここでは折りたたみのトゥイーンについてだけ書いてるけど、今回最初に取り組んでたのは元々はインデント幅の変更部分のトゥイーンだった。インデント幅の調整くらいだったらそれほど負荷は高くないだろう、という考えでやり始めたんだけど、最終的には折りたたみまで含めてアニメーション化しても結構気持ちよく動いてくれたということで、上のような話になっている。
面白い副作用として、インデント幅の調整と「折り畳まれたタブを元の状態に戻す」処理とが同時に走ると、まるで画面の左上からその位置にタブが落ちてきて填り込むようなエフェクトになる事に気がついた。どこにタブが増えたかを見失いにくくなる、という効果があるんじゃないかと思う。また、Vista+Aeroだと割となんでもアニメーションするので、その中に結構馴染んでる気もする。
追記。Let's note W7のUbuntuだと、Shiretokoだとわりかしヌルヌル、Firefox 3.0.xだとフレーム落ちで単純にアニメーションしてないように見えるだけという感じ。ドスパラのWindows XPマシンでも同じような感じだった。コマ落ちした場合でも最低1回は再描画があるので、ワンテンポ遅れる感じはあるんだけど、アニメーションしてる間反応がなくなるという風なことはないので、とりあえず次版から有効にしようと思う。(無効にする設定はもちろん付ける)
こんなメールが@google.comなアドレスから来たわけですが。(以下、適当訳は僕による物)
We are working on developing extensions for Chrome and are interested in exploring an opportunity to bring Tree Style Tab to Chrome. The initial design documents may be found here:
今私達はChrome用の拡張機能の開発のために働いており、Tree Style TabをChromeに移植する可能性について関心を持っています。最初の設計書は以下にあります:
http://dev.chromium.org/developers/design-documents/extensions
Further information on the API's that are up for consideration may also specifically be found here:
検討中のAPIについてのさらなる情報はこちら:
http://dev.chromium.org/developers/design-documents/extensions/apis As things further develop, the site will be updated and more information will become available."
将来的に、このサイトは更新され、より多くの情報が利用可能になる予定です。
で、この後にアンケートの案内が続く。アンケートはAPIの案に挙がってる物の中でどれが欲しいかというもので、自由回答欄もあったので、こう答えておいた。
Tree Style Tab totally restructures Firefox's tab bar. If I try to import it to Chrome, I'll need high flexibility not only Greasemonkey-like, but userChrome.js-like to control Chrome's UI from script.
Tree Style TabはFirefoxのタブバーを全体的に再構築します。もしChrome用に移植するなら、Greasemonkey風のものだけでなくuserChrome.js的な、ChromeのUIをスクリプトから制御する高い柔軟性が必要です。
どんなアドオンなのか中身を見ないでとりあえずAMOのおすすめリストから適当に選んでコンタクトしてきてんじゃないか?という気もする(速度重視の設計思想のChromeには、ツリー型タブを移植可能にするような高いカスタマイズ性はそぐわないと思う)。とはいえ、アドオン作者の積極的な取り込みのために動いてるとは、Google本気だな。
とりあえず僕個人に関しては、
という感じなので、僕がChromeにツリー型タブを移植するか?というと、可能になったとしてもやらないんじゃないかって気がする。リポジトリは公開してるから、やりたい人はどうぞお好きにってことで……
trunkでとうとうgetBoxObjectForがエラーを吐くようになってしまった - alice0775のファイル置き場 - Yahoo!ジオシティーズ
これを見て焦って今頃になってやっと調べた。
パッチによると、nsIDOMNSDocumentからgetBoxObjectFor()
が消えて、nsIXULDocument専用のメソッドになった。ということなので、HTMLDocumentでgetBoxObjectFor()
を使っているコードは全滅だ。何とかして代わりの方法を見つけないといけない。
document.getBoxObjectFor(element)
で取れるのはnsIBoxObject、element.getBoundingClientRect()
で取れるのはnsIDOMClientRectで、インターフェースが違う。
取りたい値 | nsIBoxObject | nsIDOMClientRect |
---|---|---|
ボックスの幅 | box.width | rect.right-rect.leftまたはrect.width |
ボックスの高さ | box.height | rect.bottom-rect.topまたはrect.height |
ボックスの左上の点のX座標(ドキュメントの原点基準) | box.x+左ボーダー幅 | rect.left+window.scrollX |
ボックスの左上の点のY座標(ドキュメントの原点基準) | box.y+上ボーダー幅 | rect.top+window.scrollY |
ボックスの右下の点のX座標(ドキュメントの原点基準) | box.x-左ボーダー幅+box.width | rect.right+window.scrollX |
ボックスの右下の点のY座標(ドキュメントの原点基準) | box.y-上ボーダー幅+box.height | rect.bottom+window.scrollY |
ボックスの左上の点のX座標(ビューポートの原点基準) | box.x+左ボーダー幅-window.scrollX | rect.left |
ボックスの左上の点のY座標(ビューポートの原点基準) | box.y+上ボーダー幅-window.scrollY | rect.top |
ボックスの右下の点のX座標(ビューポートの原点基準) | box.x-左ボーダー幅+box.width-window.scrollX | rect.top |
ボックスの右下の点のY座標(ビューポートの原点基準) | box.y-上ボーダー幅+box.height-window.scrollY | rect.bottom |
nsIDOMClientRectのwidth
とheight
はどうもGecko 1.9.1以降でしか使えないっぽい。
例えば今使ってる環境のdocument.getElementById('reload-button')
の場合はこんな感じ。
この時の値は以下の通り。
nsIBoxObject | nsIDOMClientRect |
---|---|
box.width==36 | rect.width==36 |
box.height==36 | rect.height==36 |
box.x==83 | rect.left==82 |
box.y==23 | rect.top==22 |
rect.right==118 | |
rect.bottom==58 |
x
とleft
、y
とtop
の間にずれがあるのは、nsIBoxObjectのx
とy
がいわゆるborder-box(border + padding + contentのボックス)ではなくpadding-box(padding + contentのボックス)基準であるからということらしい。nsIBoxObjectからborder辺の座標を取るには、getComputedStyle()
でborderの幅を取って計算してやらないといけない。nsIBoxObjectもnsIDOMClientRectも、これら以外のプロパティはborder-box基準のようだ。
で、上の表には書いてないけど、nsIBoxObjectにはscreenX
とscreenY
というプロパティがあって、こちらで取れる画面上の座標もborder-box基準。そして、nsIDOMClientRectにはこれらプロパティが無いので、画面上の座標を取ることができない。
大まかに言って、nsIBoxObjectのx
はnsIDOMClientRectのleft
、nsIBoxObjectのy
はnsIDOMClientRectのtop
に読み替えて差し支えない。となると、残る問題は、screenX
とscreenY
に相当する値をどう取るかだ。
で、試行錯誤の結果、以下のようなコードができあがった。
function getBoxObjectFor(aNode)
{
// getBoxObjectFor() がある時はそれを使う。
if ('getBoxObjectFor' in aNode.ownerDocument)
return aNode.ownerDocument.getBoxObjectFor(aNode);
var box = {
x : 0,
y : 0,
width : 0,
height : 0,
screenX : 0,
screenY : 0
};
try {
var rect = aNode.getBoundingClientRect();
var frame = aNode.ownerDocument.defaultView;
box.x = rect.left + frame.scrollX;
box.y = rect.top + frame.scrollY;
box.width = rect.right-rect.left;
box.height = rect.bottom-rect.top;
// 親フレームの要素を辿っていく。
box.screenX = rect.left;
box.screenY = rect.top;
var owner = aNode;
while (true)
{
frame = owner.ownerDocument.defaultView;
owner = getFrameOwnerFromFrame(frame);
if (!owner) {
// 最上位のフレームまで来てしまったら、仕方ないのでwindowのプロパティを使う。
// でもウィンドウの枠の外側の座標なので、激しくずれる。
box.screenX += frame.screenX;
box.screenY += frame.screenY;
break;
}
if (owner.ownerDocument instanceof Ci.nsIDOMXULDocument) {
// XULのドキュメント中の要素なら画面上の正確な位置を取れる。
let ownerBox = owner.ownerDocument.getBoxObjectFor(owner);
box.screenX += ownerBox.screenX;
box.screenY += ownerBox.screenY;
break;
}
let ownerRect = owner.getBoundingClientRect();
box.screenX += ownerRect.left;
box.screenY += ownerRect.top;
}
}
catch(e) {
}
return box;
}
function getFrameOwnerFromFrame(aFrame)
{
// window.parentでは、<browser type="content"/> の内容の
// フレームからは親を辿れない。
// nsIDocShellTreeItemを経由すれば可能。
var parentItem = aFrame
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.QueryInterface(Ci.nsIDocShellTreeNode)
.QueryInterface(Ci.nsIDocShellTreeItem)
.parent;
var isChrome = parentItem.itemType == parentItem.typeChrome;
var parentDocument = parentItem
.QueryInterface(Ci.nsIWebNavigation)
.document;
// フレームに結びついてるiframe要素を直接取る方法が分からないので、
// 泥臭い方法を……
var nodes = parentDocument.evaluate(
'/descendant::*[contains(" frame FRAME iframe IFRAME browser tabbrowser ",'+
'concat(" ", local-name(), " "))]',
parentDocument,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null
);
for (let i = 0, maxi = nodes.snapshotLength; i < maxi; i++)
{
let owner = nodes.snapshotItem(i);
if (isChrome && owner.wrappedJSObject) owner = owner.wrappedJSObject;
if (owner.localName == 'tabbrowser') {
let tabs = owner.mTabContainer.childNodes;
for (let i = 0, maxi = tabs.length; i < maxi; i++)
{
let browser = tabs[i].linkedBrowser;
if (browser.contentWindow == aFrame)
return browser;
}
}
else if (owner.contentWindow == aFrame) {
return owner;
}
}
return null;
}
これにさらにborder幅によるズレとかposition:fixed;
の場合への対応とかも盛り込んだ物を、ライブラリにしてみた。見ての通りchrome特権をバリバリに使ってるので、このコードはアドオンの中でしか動かない。画面上の絶対位置が必要になる場面なんてのはアドオンの場合くらいだろうから、別に問題ないと思うけど。
screenX
とscreenY
に相当する値を取るためにけっこう面倒なことをしているので、オーバーヘッドがきっと半端ない。nsIDOMClientRectの持ってる情報だけで済む場合はそれだけ使った方がいいと思う。
ちなみに、安直な発想でXULDocument.getBoxObjectFor.call(HTMLDocument, HTMLElement)
というのも考えてみたけど、これは実際には使えない。残念。
popInが入っているとテキストリンクが動かない、ことの理由はどうも以下の2点によるみたい。
stopPropagation()
しているため、テキストリンクにイベントが渡されなくなっている。stopPropagation()
されない状態にしてテキストリンク側でイベントを拾って処理を行おうとしても、イベント発生時とテキストリンクが処理を行う時とでDOMツリーの構造が微妙に変わっていて、正常に動かない。何か有効な対策が無いか考えてる。
ところでpopInは内部的にjQueryを使ってるようなんだけど、その旨の表記を僕には見つけられなかった。jQueryはMITライセンスとGPLのデュアルライセンスで、MITを選択した場合でもThe above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
(著作権表示とMITライセンスの許諾表示をソフトウェアの全コピーかもしくは重要な箇所で示す必要がある)ということなので、下手したらMITライセンスの違反ということになるような気が…… (一応フィードバックフォームから送ってはみた)
テキストリンクをThunderbirdにもインストールできるようにしたのにAMOのサイト上ではFirefox専用のままになってしまう件についてボヤいたところ、くでんさんに「Bugzillaで言えばいいじゃない」的な指摘を受けたので、確かにその通りだと思って、念のため新しくバグ報告する前に「target」あたりのキーワードで検索してみたら、Adding new compatible application fails when it's the first oneというバグが出てきて、でもFIXEDになってて「おっかしーなー」と思いながら最初に添付されてたスクリーンショットを見てみたら「Add New Application」と書かれたボタンがあって「なんじゃこりゃあああああこんなん見たこと無いぞおおおお?!」と思って、バグ報告しようとした時に「対象アプリケーション」の英語版表記を知りたくて英語ロケールに切り替えた状態になってたままで開発者用ページのトップに移動したら「新しいUIを試してみよう」みたいな今まで見たことない告知が一番上に表示されてて、そこから辿っていったら今テスト中らしい新UIにアクセスできて(新UIはまだ日本語じゃ利用できないようで、日本語に切り替えてアクセスしようとしたら見れなかった)、それを使うと手動で対象アプリケーションを追加できた。
あと、今までは一度アップロードしたバージョンは、ファイルを削除することはできてもその「バージョン」自体を無かったことにはできなかったんだけど、新UIの方ではそういうファイルが無い状態になったバージョンを「削除」する機能も加わってた。やっときたか……ていうかなんで今までできなかったんだ?
テキストリンク バージョン3.1以降で、Thunderbirdでも利用できるようにした。
プレーンテキスト形式のメールでは、Thunderbird自体のURI自動認識の処理を置き換える形で動作する。
Thunderbird本体のURIの認識部分は結構いいかげんなので、地の文とURIが連続してるとたまに酷い事になる。テキストリンク導入後は、Thunderbird自身による抽出結果を一旦全部白紙に戻して、もう一度URIの認識を自力で行うようになる。
同じような事をするアドオンが他にもありそう(っていうかFirefoxではLinkificationがそうだ)だけど、自分では見つけられなかったので……
ところで、AMOの方にもアップロードしたんだけど、過去にFirefox専用として登録したアドオンは後からThunderbirdにも対応した後も、Firefox専用アドオンとして扱われてしまって、Thunderbird Add-onsの方からは辿る事ができないようだ。これってどうにかならんのだろうか。
Tree Style Tabで選択可能な組み込みのスタイル指定の一つとして、Mac OS X上のデフォルトテーマ風の物を、cho45さんのStylish用スタイル定義を参考にして作ってみた。
スクリーンショットはVista上での物だけど、OS X上でも確認はしてるのでご安心を。
Firefox 3以前の環境ではcho45さんのスタイル定義ほぼそのまんまを適用するようになってて、その場合はタブの高さが26ピクセル固定になってしまうのでタブの中に何か追加する系のアドオン(具体的にはInformational Tab)との相性が非常に悪い。
で、それをなんとかする方法として、Firefox 3.5以降ではborder-imageが使えるということを思い出したので、その実験というか練習も兼ねて使ってみる事にした。
普通に考えると、tab要素自体に-moz-border-imageを指定すればそれでおしまいという事になるんだけど……ツリー型タブの場合はドロップ位置のマーカーを表示するためにborderを多用してるので、-moz-border-imageをtabに指定すると都合が悪い(普通のborderと同時に指定した場合、-moz-border-imageの方が優先されるようだ)。かといって、内側や外側にもう一つタブ全体を囲うXUL要素を増やそうとすると、他のスタイル指定と激しく競合して見た目がグチャグチャになるし……
で、色々試行錯誤して、Firefox 3以前でタブの右・左・中央のそれぞれに異なる背景画像を表示するために使っていたボックスを流用して解決する方法を思いついた。
この拡大図で言うと、9個に分けられた各領域を普通だったら一つのボックスのborder-imageでカバーするところを、今回は1~3・4~6・7~9の3つのボックスに分けている。-webkit-border-imageや-moz-border-imageの例として紹介されているコードでは4つの辺の幅を同じにしてる例が多いけど、実は4つの辺はそれぞれバラバラに幅を指定できる。なので、
url("共通の画像") 10 10 10 10 / 10px 0 10px 10px
で右の辺の幅を0に。url("共通の画像") 10 10 10 10 / 10px 0 10px 0
で左右の辺の幅を0に。url("共通の画像") 10 10 10 10 / 10px 10px 10px 0
で左の辺の幅を0に。という風にしてやる事で、1枚の画像で3つのボックスそれぞれに異なる部分を切り出して適用するような効果を得られる。
また、このままだとタブの高さがborder-imageの幅の分だけ高くなってしまう(border-imageの上辺+タブのラベルの高さ+border-imageの下辺=タブの高さ)ので、タブのラベルやアイコンなどに対して上下にネガティブマージンを設定して、強制的にタブの高さを小さくするようにしてみた。上の図は切り出し位置を示すためにわざと高さを広げた状態だけど、ネガティブマージンを効かせれば、冒頭のスクリーンショットのようなスリムなタブになる。
以前、Mac OS X上でタイトルバーとツールバーがくっついた様な見た目を実現するためにFirefox 3から導入されたactivetitlebarcolor属性とinactivetitlebarcolor属性について調べたけど、このあたりの仕組みがFirefox 3.5ではまた変わった。Firefox本体に同梱されるテーマでは上記の仕組みは使われなくなって、代わりに-moz-appearance
プロパティの-moz-mac-unified-toolbar
という値が指定されている。
-moz-appearance: -moz-mac-unified-toolbar
と指定されたtoolbar要素は、外観が自動的にUnified Toolbarになる。-moz-mac-chrome-active
、ウィンドウがアクティブでない時は-moz-mac-chrome-inactive
になる。-moz-appearance: none
等を指定してUnified Toolbarでなくした後も、タイトルバーはUnified Toolbarスタイルのままになる。最後の項の挙動はひょっとしたら今後変わるかもしれない。スタイル指定の意味合い的には、Unified Toolbarが存在しなくなったらタイトルバーの表示も元に戻すべきだろうし。とりあえず2009年3月24日時点のビルドではこうだった、ということで。
ちなみに、activetitlebarcolor属性とinactivetitlebarcolor属性は、今の所はFirefox 3.5でもまだ使えるみたい。
ツリー型タブに似たアドオン2つを新たに知った。
VertTabbarは、タブバーをウィンドウの右または左に移動して縦列タブにするアドオン。Vertigoはずいぶん昔に更新が止まってるようなので、その代替と言えるだろうか。カスタマイズ機能も色々あるみたい。
タブグループマネージャーは、名前から見ても機能的にもTabGroupsの後継っぽい。でも多分中身は全然別物なんだろう。今見てないグループのタブ全部をメモリから追い出して省メモリにする機能とか、検索バーからの検索結果を自動的にグループにする(セカンドサーチとも連携できるらしい)とか、色々高機能だ。
以前のUbuntuではfirefox-2というパッケージ名でFirefox 2をインストールできたけど、Ubuntu 8.10だとそういうパッケージは無いと言われてしまう。仕方がないからMozilla.orgからバイナリを落としてきて/opt以下に置いてみたけど何故か起動できない。
という所で止まってたんだけど、コンソールに出るエラーメッセージをよく見たら「libstdc++.so.5が見つからない」と書いてあって、パッケージマネージャを見たらlibstdc++6は標準で入ってるけどlibstdc++5はインストールされてなかった。5の方を入れてみたら、Firefox 2が無事起動した。
また同じ事で詰まらないようにメモしておこう。