Home > Latest topics

Latest topics 近況報告

たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。

萌えるふぉくす子さんだば子本制作プロジェクトの動向はもえじら組ブログで。

宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能! シス管系女子って何!? - 「シス管系女子」特設サイト

Page 19/80: « 15 16 17 18 19 20 21 22 23 »

XPIDLで自作コンポーネントのインターフェースを定義する時に気をつけないといけないこと - Oct 01, 2009

XUL/MigemoがTrunk(3.7a1pre)で動かなくなっていた件について原因を調べてた。

エラーの原因

エラーメッセージに見覚えがあるなあと思って検索したら、前に書いたエントリがヒットした。

一個だけ躓いた所として、XPCOMコンポーネントの新しいメソッドをIDL定義に追加して引数にnsISelectionController型のオブジェクトを渡すようにしていた所、XPIDLでのコンパイルは通るんだけど実際に使う時にNS_ERROR_XPC_CANT_GET_PARAM_IFACE_INFOというエラーが出てにっちもさっちもいかなくなってしまった。ダメ元で、引数の型をnsISupportsにして受け取り側でQueryInterfaceするようにしてみたところ、ちゃんと動いてくれた。一体何だったんだろうこれは。

ああ、前にも詰まってたところだったか……この時は結局「理由」が分からないままで、とりあえず動くようにはなったからということでそれ以上は調べなかったんだよね。

改めて検索してみたら、似たような問題にぶち当たった人がいたようだった。で、やっと何が問題の原因だったのかが分かった。

新しいXPCOMコンポーネントを定義する時に、インターフェースも新しく定義する場合、XPIDLを使ってインターフェースを定義してやらないといけない。

[scriptable, uuid(4aca3120-ae38-11de-8a39-0800200c9a66)]
interface xmIXMigemoFileAccess : nsISupports
{
   AString getAbsolutePath(in AString filePath);
   AString getRelativePath(in AString filePath);
   AString getExistingPath(in AString absoluteOrRelativePath);
   AString readFrom(in nsIFile file, in ACString encoding);
   nsIFile writeTo(in nsIFile file, in AString content, in ACString encoding);
};

この時、メソッドの引数や返り値の型として、AStringやlongのようなプリミティブ型(?)だけでなく、nsIFileのように他のインターフェースを使うこともできる。

この時気をつけないといけないのが、インターフェースには2つの識別子があるということ。1つは、上記の例でいえばinterface xmIXMigemoFileAccessという部分で定義されているインターフェース名「xmIXMigemoFileAccess」、もう一つは[scriptable, uuid(4aca3120-ae38-11de-8a39-0800200c9a66)]という部分で定義されているインターフェースID(IID)「4aca3120-ae38-11de-8a39-0800200c9a66」だ。

今回は、XUL/Migemoのコンポーネントの機能のうち、nsIDOMRangeやnsIDOMWindowを値の型として使っていた部分でエラーが起こっていた。

interface xmIXMigemoTextUtils : nsISupports
{
   (略)
   AString range2Text(in nsIDOMRange range);
   (略)

具体的にはこの辺。どうも、Firefox 3.5から3.7a1preまでの間のどこかの時点で、nsIDOMRangeやnsIDOMWindowのIIDが変更されたらしい。XPIDLのコンパイル(.xptファイルの生成)には成功しても、そのあと3.7a1preのFirefoxが.xptを解釈する時に、IIDの方でnsIDOMRangeやnsIDOMWindowのインターフェース定義を探すために、「こんなIIDのインターフェースは定義されてないよ! インターフェースの情報が見つからないよ!」というエラーになっていたようだ。

とぴあさんに色々教えてもらった。元々、XPCOMの元になった(?)COMの世界つまりC++の世界では、インターフェースの識別にはIIDを使うのが原則というかIIDこそが本来の識別子で、nsIDOMRangeとかの名前はそれへの参照に過ぎないということなのだそうな。

インターフェースの内容が変化した時(メソッドの追加等)には、「古いインターフェースの定義が消されて、別のIIDで新たなインターフェースが定義された」というような扱いになるようだ。「IIDが変わった」と前述しているけれども、プログラム的には「IIDが変わっただけで同じインターフェース」なのではなく「全くの別物」という扱いだから、全く互換性は保証されない……というわけ。

なお、互換性を維持したままインターフェースに新しい機能を追加するためには、現在使われているインターフェースの定義はそのまま残して、それを継承した新しいインターフェースを定義する必要があるということになる。「nsIPrefBranch2」とか「nsIGlobalHistory3」などがそれにあたる。

回避策

nsIDOMRangeやnsIDOMWindowのIIDが3.7a1preのものと同じになっている新しいSDKを使って.xptファイルを作り直してやれば、3.7a1preでもXUL/Migemoが動くようになるはず。でも、そうすると今度はFirefox 3.5以下で動かなくなる。それは困る。

無難な解決策は、値の型として使うインターフェースを、古いFirefoxから新しいFirefoxまでの間でずっと変わっていないインターフェースにするということ。nsISupports(すべてのXPCOMの基底インターフェース)ならほぼ確実に使える。

interface xmIXMigemoTextUtils : nsISupports
{
   (略)
   AString range2Text(in nsISupports range);
   (略)

このようにインターフェースの定義を変えた上で、実装の方で受け取った値をQueryInterface()してやる。

range2Text : function(aRange) {
   aRange.QueryInterface(Ci.nsIDOMRange);
   var doc = aRange.startContainer;
   (略)

こうすると、メソッドを呼ぶ時に、DOMのRangeオブジェクトをそのまま引数に渡せる状態を維持できる。

JavaScriptのレイヤからはIIDではなくヒューマン・リーダブルなインターフェース名だけを使うのが一般的なのだけれども、こうしておけばXPCOMのフレームワークが自動的に「新しいIIDのnsIDOMRangeインターフェース」を参照してくれる。実際にインターフェースで定義されている内容には変更が起こっているかもしれないから、確実な動作は保証できなくなるけれども、当該のインターフェースが「既にある機能はなくなったり変更されたりせず、新しい機能が追加されていくだけ」という傾向があるのなら、おおむね問題なく動作し続けてくれると考えられる。

そもそも……

とぴあさんが調べてくれたのだけれども、今回のトラブルの原因になったnsIDOMRangeは定義の頭の方に@status FROZENと書かれていて、本来であれば、IIDが変わることもなければメソッドやプロパティなどのインターフェース定義の内容が変わることもない、安心して永続的に使えるインターフェースだったはず……のようだ。

それが、Bug 396392 – Support for getClientRects and getBoundingClientRect in DOM Rangeに提出されたパッチでメソッドが追加されると同時にIIDも変更されてしまった。本当は、これはあってはならない事態らしい。当該バグのコメントでもnsIDOMRangeのIIDは元に戻して、変更はnsIDOMNSRange(Geckoの独自拡張の機能が色々定義されているインターフェース)に対して行うべきと書かれている。おそらく近いうちに、nsIDOMRangeのIIDは元の物に戻されて、XUL/Migemoが動かなくなってしまった問題も解消されるものと思われる。

個人的な感覚としては、インターフェースに変化が無くても実装が変わって挙動も変わりました……なんて事がMozillaではザラにあるので、インターフェースの部分でだけ「ちょっとでも変化があったらIIDは別の物! インターフェースとしても別物!」という風に厳密に区別しても意味なくね? と思う。ぶっちゃけ、「安心して使えるAPI」なんてのはMozillaの世界じゃリップサービスに過ぎないと思ってる。(とぴあさんには、それはプロジェクトのマネジメントがマズイという別のレイヤの問題だよねと言われた。)

あと、現在のFirefox(Gecko 1.9以降)では、自分で新しくインターフェースを定義してXPCOMコンポーネントを作る必要はほとんど無いと言っていい。JavaScriptでコンポーネントを定義してJavaScriptだけから使うのであれば、JavaScriptコードモジュールを使えばよくなった。また、起動直後に処理を行うような場合なんかには相変わらずXPCOMコンポーネントの定義が必要だけど、それは既存のインターフェース(nsISupportsやnsIObserver)だけでも事足りる。XPIDLが必要になるのは、JavaScriptで書かれた機能をC++のレイヤから呼び出したいような時だけだ。普通に開発する分には、こんな事で悩む必要は今や全くない。という事に気がついて、今更になって激しい徒労感を感じている。

ツリー型タブでセッション復元時にツリーが壊れる問題について調査中 - Sep 29, 2009

表題の件について、どーも実際に表示されてる内容とセッション情報とが食い違ってるケースがあるようだ。

Firefoxのタブとかのセッション情報はJSONっぽい文字列で保存されてて、最初はJSON整形で読みやすい形にして調べようと思ってたけど、めんどすぎたので、以下のようなスクリプトでツリー構造の所だけ可視化してみた。

var sv = gBrowser.treeStyleTab;

var session = sv.SessionStore.getWindowState(window);
eval('session = '+session);

var result = [];

session.windows[0].tabs.forEach(function(aInfo) {
   var entry = aInfo.entries[aInfo.entries.length-1];
   var item = {
         label    : entry.title+' / '+entry.url,
         id       : aInfo.extData[sv.kID],
         children : (aInfo.extData[sv.kCHILDREN] || '').split('|'),
         parent   : (aInfo.extData[sv.kPARENT] || ''),
         items    : []
      };
   var bullet = '*';
   var tab = sv.getTabById(item.id);
   if (tab.getAttribute(sv.kPARENT) != item.parent) {
      item.label += '\n<WRONG PARENT>';
      bullet = '?';
   }
   if (tab.getAttribute(sv.kCHILDREN) != item.children.join('|')) {
      item.label += '\n<WRONG CHILDREN>';
      bullet = '?';
   }
   item.label = item.label.replace(/^/gm, '  ').replace(/^./, bullet);
   var current, index;
   if (result.some(function(aItem) {
         if (!aItem) return false;
         if (aItem.items.some(arguments.callee)) return true;
         current = aItem;
         index = aItem.children.indexOf(item.id);
         return index > -1;
      })) {
      if (current.items.length <= index) {
         while (current.items.length < index) current.items.push(null);
         current.items.push(item);
      }
      else {
         current.items[index] = item;
      }
   }
   else if (result.some(function(aItem) {
         if (!aItem) return false;
         if (aItem.items.some(arguments.callee)) return true;
         current = aItem;
         return aItem.id == item.id;
      })) {
      current.items.push(item);
   }
   else {
      result.push(item);
   }
});

var string = result.map(function(aItem) {
      var children = aItem.items.map(arguments.callee).join('\n');
      return children ?
            aItem.label+'\n'+children.replace(/^/gm, '  ') :
            aItem.label ;
   }).join('\n')+'\n';

alert(string);

で、調べてみたら、やっぱりツリー構造がおかしい。ツリー表示はタブの属性値の方に基づいて行われてて、その属性値をnsISessionStoreのsetTabValue()deleteTabValue()でセッションの方にミラーしてるんだけど、ミラーされてるはずの値が期待通りにミラーされてないようだ。

追記。

……nsSessionStore.jsを読んでたら原因が分かった。

  • setTabValue()では内部で最後にsaveStateDelayed()を呼んでいるため、変更がファイル(プロファイルフォルダ内のsessionstore.js)にすぐ書き出される。
  • deleteTabValue()ではsaveStateDelayed()が呼ばれてないために、他の処理の中でsaveStateDelayed()が呼ばれるまでは変更がファイルに書き出されない。
  • ファイルが書き出されないうちにFirefoxを終了したり再起動したりすると、メモリ上のセッション情報は破棄されて、ファイルに書き出されたセッション情報が次回起動時に読み込まれる。
  • よって、deleteTabValue()だけで情報をミラーしたつもりでいると、ゴミ情報が残ったままになってしまうことが多々ある。そのゴミ情報が邪魔をして、期待通りにツリー構造が復元されなくなってしまっている。
  • 調べてみたらBug 510965 - deleteWindowValue and deleteTabValue API functions need to call saveStateDelayedというバグも立っていた。

deleteTabValue()する前にsetTabValue()で空の値をセットして強制的にセッション情報を書き出させるようにしてみたところ、上記のスクリプトで調査してもセッション情報との間でのツリー構造の不整合は検出されなくなった。

結論:deleteTabValue()マジ使えねえ……

追記。

それでも全然駄目だった。Firefoxがセッション情報をファイルに書き出す時、読み込み中であるというフラグが立っている(Firefox 3.5以前ではtab.linkedBrowser.parentNode.__SS_data._tabStillLoading、Firefox 3.6以降ではtab.linkedBrowser.__SS_data._tabStillLoadingtrueである)タブについてはキャッシュされた情報を書き出すようになってるのに、このフラグがタブの内容の読み込み完了後も立ちっぱなしになってるせいで、常にキャッシュされた古い情報が書き出されてしまい、setTabValue()で設定された新しい値が無視されてしまう。

結論:nsISessionStore/nsSessionStore.jsは腐ってる……

まとめると、以下のようなメソッドを使うようにしてやれば色々と幸せになれそうです。

setTabValue : function(aTab, aKey, aValue) {
   if (!aValue) return this.deleteTabValue(aTab, aKey);

   try {
      this.checkCachedSessionDataExpiration(aTab);
      this.SessionStore.setTabValue(aTab, aKey, aValue);
   }
   catch(e) {
   }

   return aValue;
},

deleteTabValue : function(aTab, aKey) {
   try {
      this.checkCachedSessionDataExpiration(aTab);
      this.SessionStore.setTabValue(aTab, aKey, '');
      this.SessionStore.deleteTabValue(aTab, aKey);
   }
   catch(e) {
   }
},

checkCachedSessionDataExpiration : function(aTab) {
   var data = aTab.linkedBrowser.__SS_data || // Firefox 3.6-
              aTab.linkedBrowser.parentNode.__SS_data; // -Firefox 3.5
   if (data &&
       data._tabStillLoading &&
       aTab.getAttribute('busy') != 'true' &&
       aTab.linkedBrowser.__SS_restoreState != 1)
      data._tabStillLoading = false;
},

2010年1月29日追記。Firefox 3.6以降とFirefox 3.5以前でフラグが保存される場所が少し違っていたので、その旨を修正した。

2010年9月27日追記。Firefox 4 の最適セッションリストア原文)の影響によって、まだ実際にはセッションが復元されていないタブなのに、ビジー状態でなくなっているというケースがあり得るようになった。そのため、aTab.getAttribute('busy')だけでビジー状態を判別すると、これからセッションを復元して欲しい・読み込み中のタブであるにも関わらず_tabStillLoadingをfalseにしてしまい、セッションが復元されなくなってしまうという問題が起こっていた。なので、タブの属性値と併せてaTab.linkedBrowser.__SS_restoringも確認するようにサンプルコードを修正した。

2010年12月6日追記。aTab.linkedBrowser.__SS_restoringが廃止されてaTab.linkedBrowser.__SS_restoreStateというプロパティが使われるようになっていたので、それにあわせてサンプルコードを修正した。

addTab, loadOneTabの引数がFirefox 3.6で変わる? - Sep 16, 2009

trunk gBrowserのloadOneTabとaddTabの引数が変わった - alice0775のファイル置き場 - Yahoo!ジオシティーズを見て初めて知ったけど、TrunkでgBrowser.addTab()gBrowser.loadOneTab()の仕様が変わったようだ。

すでに追加されている「現在のタブの隣に新しいタブを開く」機能は、リファラが渡されていれば現在のタブの隣に、そうでなければタブバーの右端にタブを開くという挙動になっている。これに対し、リファラを渡さなくても現在のタブの隣に新しいタブを開けるようにしたい、という要望が出た(当然と言えば当然だ)。

それを実現するには、普通に考えると、gBrowser.addTab()gBrowser.loadOneTab()の引数でそういう挙動を指定できるようにしてやらないといけない。しかしどっちのメソッドもすでに多数の引数を受け付けるようになってて(現状でもすでに6個ある!)、これ以上引数を増やすのってどうなん? と。関数の引数が多いのは悪い設計の典型例だ。こういう場面ではハッシュなりなんなりを使うのが定石ですわな。そこで件のバグが立ったと。

最初に提出されたパッチは、引数リストにさらにaRelatedToCurrentを加えつつ、各引数に対応する値をプロパティに持つオブジェクトを2番目の引数として渡した時はそっちを使うようにするという風になってる。これだけ見ると「また引数増やすのかよ、しかも新方式(ハッシュによる指定)もサポートするのかよ。マンドクセ。」と思うところだけど、2番目に提出されたパッチでは引数の数の方は変更が無くて、aRelatedToCurrentに相当する引数を指定したい時はハッシュを使わなければならないようになってる。実際にチェックインされた内容は後者のパッチの通りだ。

この事から、今後は新方式のAPI(新しいタブの挙動はgBrowser.addTab()gBrowser.loadOneTab()の第2引数でハッシュで指定する)が標準となり、旧方式のAPI(gBrowser.addTab()gBrowser.loadOneTab()に沢山の引数を渡す)はあくまで後方互換性のためにのみ残されている、という風に考えることができる。

参考までに、新旧それぞれの書き方を示しておこう。

// new API
var newTab = gBrowser.addTab('http://www.example.com/', {
               referrerURI          : referrer, // nsIURI
               charset              : 'Shift_JIS',
               postData             : null,
               inBackground         : true,
               allowThirdPartyFixup : false,
               relatedToCurrent     : false
             });

// old API
var newTab = gBrowser.addTab(
               'http://www.example.com/',
               referrer, // nsIURI
               'Shift_JIS',
               null, // postData
               true, // inBackgorund
               false // allowThirdPartyFixup
             );

本当だったらもっと早く、Firefox 3.0になる前の時点でこういう事は済ませておくべきだったんだろうと思う(そのための「メジャーバージョン」でしょ?)。でもまあ、いつかはやらなきゃいけないことだ。新しい引数が追加されるというタイミングは、移行のいいきっかけではある。

History Tree - Aug 21, 2009

History Tree :: Firefox Add-ons

履歴をビジュアルに見たい、グラフ化して見たいという考え自体はやっぱりよくある話なのかなー。自分も過去にWeb Mapなんてものをやったしなあ。

Web Map、チャンスがあったら作りなおしてみたいところではある。今だったらHTML Canvas使ってもっと軽く作れるだろうから。(必要な道具はある、というだけで、自分の方にその技能があるわけではないんだけど)

ブックマークを常にタブで開くようにするためだけのアドオンを公開したよ - Aug 19, 2009

その名もズバリ「Open Bookmarks in New Tab(ブックマークを新しいタブで開く)」。何のひねりもない。

ツリー型タブにこの機能を付けれという要望が何度も何度もいろんな人から寄せられていて、しかしどうも調べてみると、Tab Mix Plusの一機能としてはこういう機能があるものの、これだけを実現してくれるアドオンが実は存在してなかったらしい(userChrome.jsを使える人はそっちで解決してしまうから、アドオンでなければ使えないというレベルのユーザには行き渡っていない?)、ということで作った次第です。userChrome.jsでやる人が多いんだろうなあということからも分かるように、メインの実装はたったこんだけ。これ以上機能を追加するつもりはないです。全く。

工夫?というか、実際使ってみて感じたことをフィードバックした点としては、ブックマークを中クリックした時にも常にタブで開くようにしてる、というあたりでしょうか。

作り手としてバカ正直に考えると、「普通の左クリックと中クリックの挙動をそれぞれ反転させればいいんじゃね?(そうすれば新しいタブで開きたい時と現在のタブに読み込ませたい時に使い分けれて便利じゃね?)」ということでそうしてしまいそう(事実、最初はそうしてた)なんだけど、実際に使ってみると自分の場合はブックマークを中クリックすることが癖になってて、タブで開きたいのに現在のタブに読み込まれて「ムキー!!!」となってしまった。

それに、こういう要望を出す人というのは多分、ミドルクリックでタブで開けるということをそもそも知らない(ミドルクリックという操作がある事自体を知らない)か、2ボタンマウスを使ってるかで、ハナから操作を使い分ける気なんか無いんだろうなあ。とも考えられる。

つまり「操作によって挙動を変えるという自由」が、混乱の元であったり、そもそも誰もそんな自由を欲してないんじゃないか、と。なので、「左クリックでも中クリックでもとにかくブックマークは新しいタブで開く」という挙動を初期設定としておいた。設定を変更すれば、中クリックした時は現在のタブに読み込ませるという挙動にもできるけど、作者の推奨設定はあくまでこうですよってこと。

サイドバーをタブ(ツリー)の下に表示する - Aug 19, 2009

ツリー型タブを使ってタブバーを左または右に表示してる時に、サイドバーをタブの下に表示したい(コンテンツ領域の左に「タブバー」と「サイドバー」が縦に並ぶようにしたい)、という要望を何度か受け取っている。

「タブをツリー表示する」という基本コンセプトとはあまり関係がない機能なので、機能として付け加えるつもりはない。しかし、実装するとしたらツリー型タブに激しく依存するはずなので、全くフォローしないという訳にもいかなさそう。

ということでuserChrome.cssでなんとかできないか考えてみた。

#sidebar-box {
   bottom: 16px;
   display: -moz-box;
   position: fixed;
   -moz-box-orient: vertical;
}
sidebarheader {
   width: 208px;
}
#sidebar-box,
#sidebar {
   width: 250px;
}
#sidebar {
   height: 300px;
}
.tabbrowser-strip {
   margin-bottom: 316px;
}

サイズ固定になってしまうけど、こうするとそれらしくなった(タブバーが左にあって、250ピクセルくらいの幅である場合)。

フレキシブルにやろうと思ったら、それなりのコードを書かなきゃいかんよなあ。誰かやってくんないかなあ。

追記。アドオンにしました。

ツリー型タブとTab Mix Plusの衝突について調べていてGeckoのバグを見つけた - Aug 13, 2009

ツリー型タブが入ってるとスターアイコンからブックマークの内容を編集できない、という報告を見て、そんなバカなこっちじゃちゃんと動いてるのに!と思って薄々そうなんじゃないかなあと思いながらよく報告を見てみたら、Tab Mix Plusと組み合わせた状態であると書いてあり、やっぱり……と思いながら両方を入れてみたら確かに問題が再現した。まあここまではよくある話。

エラーが起こっている箇所はエラーコンソールのメッセージから容易に特定できたんだけど、でもどう見てもそこでエラーになるはずがないという箇所でエラーになっていた。具体的には1つ前のエントリに書いたcreateContextualFragment()の所。色々条件を変えて調べてみたら、どんな簡単なソースを渡した場合でもcreateContextualFragment()の返り値が常にnullになっているようだった(Firefox 3.0.13でのテスト結果)。で、さらに条件を変えながら色々試して分かったのは、そもそもツリー型タブと組み合わせなくても、Tab Mix Plusが入ってるだけでcreateContextualFragment()が全然使い物にならなくなる(Firefox 3.0.xや3.5では常にnullが返り、Trunkでは常に例外が発生する)ということだった。

さすがにこれは何かおかしいと思って、エラーコンソールに表示されるエラーをよく見ると、XMLのパースエラーで「属性が二重に定義されている」とメッセージが出ている。それでピンと来てTab Mix Plusのソースを見てみたら、怪しい記述を見つけた。オーバーレイ用のXULドキュメントで、idがmain-windowであるwindow要素のオーバーレイ内容にXML名前空間宣言が含まれている、というものだ。もちろんこれはXML的に全く問題がないはずの記述なのだけれども、まさかと思いながらそこを書き換えてみたら、Tab Mix PlusがあってもcreateContextualFragment()が失敗しなくなった。それで、ここが原因だと確信が持てたということで、Bugzillaにバグとして報告してみた。

Bug 510157 – nsIDOMNSRange.createContextualFragment() fails when there is applied XUL-overlay including XML namespace declarations

条件がややこしい上に、一体どこが一番悪いのか分からなかったんだけど、一番表面上のトリガーになってるように見えてるのがDOM Traversal-Rangeだったので、そこのバグとして報告してある。

この問題を回避しようと思ったら、Tab Mix PlusのオーバーレイでXML名前空間宣言を書くのは本当のルート要素だけという風に書き換えるのが一番手っ取り早いんだけど……できれば本体(Gecko)の方を直してほしい所ではある。

ツリー型タブの修正 - Aug 11, 2009

先週1週間は夏休み取って家に缶詰でずっともえじら組のマンガ描いてたんだけど、その間大量にバグ報告が来てたのをずっと見て見ぬふりしてたのを今週になってやっと修正した。

ブックマークフォルダの内容をタブで開けなくなるという問題はFirefox 3.0.xでのみ発生する問題で、原因はJavaScriptコードモジュールのPlacesUtilsにFirefox 3.5から追加された機能をそうとは知らずに使ってしまっていたせいだった。

あとブックマーク周りの変更が結構ボロボロだったのをだいぶ直した。特にスターアイコンのことは自分であんまり使わないからすっかり忘れてて、直すのに難儀した。Firefox自身がeditBookmarkOverlay.xulを動的に読み込んでいて、そのeditBookmarkOverlay.xulに対してツリー型タブがオーバーレイを適用しているために問題が……とか、とてもバッドノウハウくさい。結局、XULオーバーレイでどうこうするのは諦めてJavaScriptで動的にDOM要素を生成して挿入することにした。

var range = document.createRange();
range.selectNodeContents(container);
range.collapse(false);
range.insertNode(range.createContextualFragment(<![CDATA[
   <row align="center" id="treestyletab-parent-row">
      <label id="treestyletab-parent-label"
         control="treestyletab-parent-menulist"/>
      <menulist id="treestyletab-parent-menulist"
         flex="1"
         oncommand="TreeStyleTabBookmarksServiceEditable.onParentChange();">
         <menupopup id="treestyletab-parent-popup">
            <menuseparator id="treestyletab-parent-blank-item-separator"/>
            <menuitem id="treestyletab-parent-blank-item"
               value=""/>
         </menupopup>
      </menulist>
   </row>
]]>.toString().replace(/^\s*|\s*$/g, '').replace(/>\s+</g, '><')));
range.detach();

こんな感じにしておけば、XULの「タグを書くだけでUIを作れる」という利点をそれほど殺さなくても済む……と思う。E4XのXMLオブジェクトを生成した物を既存のDOMツリーに直接組み込むことができれば話は早いんだけど、そういうことは無理っぽいので、createContextualFragment()にしてる。ここではE4XのCDATAマーク区間をヒアドキュメント代わりに使ってるんだけど、文字列置換でタグの間の空白文字を消してるのと、toString()をわざわざ書いていることに注意が必要。前者を忘れると要素ノードの間にいちいちテキストノードが生成されてややこしいことになるし、後者をを忘れるとStringクラスの物ではなくXMLオブジェクト自身の方のreplace()メソッドが呼ばれてしまって文字列置換にならないので。

修正ついでに、ブックマーク項目の「親のタブ」を設定する機能について、もうちょっと自由に使えるように手を入れてみた。ツリー構造を書き換えるのと同時に、ツリーとして表示される時の順番に合わせてブックマークを自動的に並べ替えるようにした。

ツリー型タブでブックマークにツリー構造を保存できるようにしてみた - Jul 31, 2009

ツリー型タブ 0.8.2009073101/02で、「このツリーをブックマーク」や「すべてタブをブックマーク」した時に、ツリーの構造を含めてブックマークを保存するようにしてみた。だいぶ前から要望を受けてて、「確かにそうするべきだよなあ」とは思ってたんだけど、どうやって実現すればいいかで悩んでた。でもFirefox 2のサポートを切ったことによって、API経由でPlacesデータベースに色んな情報を簡単に保存できるようになったので、思い切って実装してみた。

他のアドオンからもこの機能を使えるように、APIを用意してある。複数のタブからブックマークを作成する場合、以下のように、PlacesUIUtils.showMinimalAddMultiBookmarkUI()でブックマークの追加を行う前後にツリー型タブのAPIを呼んでやると、タブのツリー構造がブックマークに保存される。

var tabs = Array.slice(gBrowser.mTabContainer.childNodes);

var isTSTBookmarksTreeStructureAvailable = (
        'TreeStyleTabBookmarksService' in window &&
        'beginAddBookmarksFromTabs' in TreeStyleTabBookmarksService &&
        'endAddBookmarksFromTabs' in TreeStyleTabBookmarksService
    );
if (isTSTBookmarksTreeStructureAvailable)
    TreeStyleTabBookmarksService.beginAddBookmarksFromTabs(tabs);
try {
    PlacesUIUtils.showMinimalAddMultiBookmarkUI(tabs.map(function(aTab) { return aTab.linkedBrowser.currentURI; }));
}
catch(e) {
}
if (isTSTBookmarksTreeStructureAvailable)
    TreeStyleTabBookmarksService.endAddBookmarksFromTabs();

このAPIはマルチプルタブハンドラでもさっそく使ってる。

やってることはどういう事かというと……

  1. まずTreeStyleTabBookmarksService.beginAddBookmarksFromTabs()の方では、ブックマークされる予定のタブのツリー構造をシリアライズして内部に保持した上で、ブックマークの監視を開始する。
  2. 次に、PlacesUIUtils.showMinimalAddMultiBookmarkUI()で複数のブックマーク項目が新たに作成される。この時、TreeStyleTabBookmarksServiceはブックマークの追加を監視していて、新しく作られたブックマークのIDを内部に保持する。
  3. 最後に、TreeStyleTabBookmarksService.endAddBookmarksFromTabs()の中で、追加されたブックマークと元になったタブとを対応させ、ツリー構造の情報(親のタブにあたるブックマーク項目はどれか、という情報)を、ブックマークのアノテーションとして保存する。この時、タブの数と作られたブックマークの数とが一致しない場合(ブックマークの追加がキャンセルされたとか、未知の機能によってタブと関係ないブックマークが同時に作成されたとか)は想定外のエラーということで、何もせず終了する。

とりあえず一番簡単なやり方で実装してみたので、保存した後のブックマークの順番や親子関係をいじくり回すとちょっと変なことになる。一応、そんなに大きな問題は起こらないで見た目上は何となく自然な形に収まるように、と工夫はしてみたんだけど……どうだろう。

保存された「どのタブが親か?」という情報は、ブックマークのプロパティから編集できるようにしてある。親を付け替えられるようにしてみたけど、横着してるのでちょっと制限が厳しい。そのうち、親を付け替えたらそれに応じてブックマーク項目自体の親フォルダ内での位置も自動的に入れ替えるようにでもしてみようかなー。

ブラウザのタブの改革 - Firefox.nextへの道:タブをより良くする。 - Jul 30, 2009

Mozilla Corporationの中の人であるAlexander Limi氏次世代のFirefoxのタブインターフェースをどのように改善するかについての議論の叩き台となるエントリを6月に公開されている。その中にツリー型タブへの言及もあった。だからというわけでもないけど、英辞郎とExcite翻訳に頼りながらどうにかこうにか日本語に訳してみた。誤訳があったらごめん。

なお、翻訳を公開することについてはご本人の許諾を得ております。


ブラウザのタブの改革 - Firefox.nextへの道:タブをより良くする。

よく知られた技術ニュースサイトのスクリーンショットから話を始めましょう。「Digg」ボタンを押したくなる気持ちはよく分かりますが、押さないように。何も起こりませんからね。

(スクリーンショット:mashable.comの「40+ Add-Ons for Managing Firefox Tabs」という記事に474のdiggが付いている)

さて、ここで何が起こっているか? 以下のようなことが言えます:

  • ブラウザ上で複数のページを扱うための現在の手法は、十分であるとは言えません。少なくとも、先進的なユーザ以外にとっては。
  • 複数のページを一度に開いて操作するのに「これさえあれば十分」と言えるアドオンは無いようで、タブの挙動を変えるために途方もない数のアドオンが存在しています。

タブがブラウザの中に登場した時――OperaとFirefoxがその急先鋒だったわけですが――、Web(とコンピュータも)は今とは非常に異なった状態にありました。人々は1つのウィンドウの中だけで6つか7つほどのページを同時に扱えるというだけでも、ことのほか幸せでした。

2009年に時計の針を進めると、多くのユーザが、一度にいくつのページを開けるかという点でブラウザの限界を打破しようとしています。この新たな試みは大量のメモリ容量とCPUパワーを必要とします――しかし、ユーザーインターフェースにおいて、これよりも明らかな課題はありません。大量のタブを扱う方法については、複数行表示(Opera)から現在開かれているタブのプルダウンリスト(FirefoxやSafari)まで、ブラウザごとに色々な方法がとられています。これらのアプローチのいずれも、いまいち上手く機能していません。これが、今Mozillaが複数のページを管理するための別のアプローチを探している理由です。

目次

長大な投稿ですので、あなたが興味がある所から読めるように、節ごとのリンクを用意しました:

壊れていないのなら、直さない

私たちはタブ機能こそが、多くの人々がFirefoxに乗り換えた最大の理由であることを認識しています。私たちが別のアプローチを探しているということを明らかにした時、人々が最初に言うのはだいたいこういう事です。「でも、私はタブが好きだ。タブ機能をなくさないでくれ!」

ですので、はっきりとこう言っておきましょう。私たちは、タブは未だ健在だと思っており、タブをなくそうとは考えていません。タブは現在の物と似た形で残り続けるでしょう。なぜなら、ほとんどの人にとってタブは大変有効に働いているからです。ユーザの大多数はタブについて特に問題意識を持ってはおらず、あなたがタブの限界に挑もうとしない限り、タブは複数のページを扱うための非常に自然且つエレガントな解決策と言えます。

その上で私たちがしたいのは、多数のページを管理するのに現在タブを使っていて不満を感じていたり不幸せになっていたりする人々のための、より良い解決策を見つけ出すことです。タブに関して、この議論のために、ユーザをいくつかの大まかなグループに分類しましょう:

初心者
このグループはタブを全く使っていません。これらの人々は、私の祖母に似ています。技術に精通したおばあちゃんでも、彼女は4つか5つほどのWebサイトしか訪れておらず、タブは全く使っていません。
中級者
このグループの人達は、現状のタブに満足しているユーザです。彼らはたいてい5~10個前後のタブを開いています。
上級者/パワーユーザ
このグループのユーザは多数のタブを開いています。ブラウザの中で100を超えるタブを開いており、ページを全く閉じないで、代わりに新しいタブを開いていく、というタイプの友人を誰もが持っています。あるいはあなたがまさにその人かもしれません。

これらの分類のためにありがちな名前を使っていることについてはご容赦下さい。みんな十人十色で、人によっては「うちのおばあちゃんは……」と言いたくなるかもしれませんが――これらは単に議論を分かりやすくするための分類です。

現存しているアプローチ

当然ながら――先ほどのスクリーンショットが示しているように――タブ周りの状況を改善するための試みについては、様々な努力がすでにあります。Mozilla LabsでもSummer 2009 Design Challengeという企画を主催しており(Reinventing Tabs in the Browser)、1つ前のSpring 2009 Design Challengeでは、可能な限りの最小のユーザーインターフェースでどのようにWebブラウズを行うかを思い描いてもらいました。

最近パワーユーザの間で評価されているFirefox用アドオンの1つが、ツリー型タブアドオンです。

(ツリー型タブのスクリーンショット。タブバーがコンテンツ領域の左横に表示されており、Googleの検索結果から開かれたタブがインデント表示されている)

人気の理由は分かりやすく、このアドオンはパワーユーザの要求によく合っています:

  • このアドオンはタブを、水平表示の代わりにサイドバー風の縦長表示で表示します。その結果、見えるタブの数が最大化されます。
  • ワイドスクリーンのモニタが新製品の主流になってきているために、より多くのユーザが水平方向の画面スペースを利用できるようになってきていますが、このアドオンはその水平方向のスペースを活用します。(例えば、2006年第1四半期のノート機向け出荷台数では、ワイドスクリーンモニタの出荷台数は普通のモニタを超えました。)
  • このアドオンは、そのタブがどこから開かれたかに基づいてタブを自動的にグループ化します。例えばあなたがGoogleの検索結果から別れる形で新しいタブを開いたのなら、そのタブは上のスクリーンショット内の「Apple」タブのように、入れ子の形で表示されます。現在、他のブラウザを使っている人々は、関連するタブをグループ化するために異なるウィンドウや色分けされたタブを使っています――そして、望んだとおりのグループ分けを行うためにウィンドウの間でタブをドラッグ&ドロップしています。この解決策は、それよりもエレガントです。
  • このアドオンは、ホイールスクロールというほとんど労力のいらない操作によって、画面に収まりきらないタブをより簡単に操作できるようにします

もう1つの注目に値するアプローチは、Safariでタブを操作するためのSafariStandアドオンが取っている道です。

(SafariStandのスクリーンショット。コンテンツ領域の左横にサムネイルが縦に並んでいる。) SafariStandが提供する機能の一部は以下のようなものです:

  • ツリー型タブと同じように、このアドオンは画面の中に収まりきらないほどのタブがある時に、ホイールスクロールによって多数のタブを簡単に扱えるようにします。
  • タブは非常に視覚的で、簡単に識別できます。
  • タブはクリックに反応する大きな領域を持っています。
  • 最も重要な事として、SafariStandは、私たちがMozillaにおいて部分的サムネイルと読んでいる機能を含んでいます。

ページのほとんどがテキストである場合には特に、ページ全体のスクリーンショットのサムネイルはページを識別するためにはそれほど便利ではありません。ページの左上の角(ロゴとページのタイトルの一部を含むのに十分な大きさの領域)のスクリーンショットを取ることによって、部分的サムネイルはあなたがページを探すために識別する上で、飛躍的により便利になります。上のスクリーンショットでは、もしあなたが他に3つほどWikipediaのページを開いていたとしても、「User Interface」のWikipediaのページを識別することができます。


先のアプローチが正しいことを検証するために、Opera 10ベータ版の場合を見てみましょう。このブラウザはタブを表示する方法として似たアプローチを取っていますが、しかし他の物に比べて、この実装には色々と問題があります:

(Opera 10のスクリーンショット。コンテンツ領域の上にタブが並んでおり、各タブにはスクリーンショットが表示されている)

  • あなたはここで、ページ全体のサムネイルが何故使いにくいのかを示すいい例を見ることができます。このスクリーンショットでは、サムネイルにおいて、あるWikipediaのページは他の異なるWikipediaのページと見分けることができません。
  • サムネイルを横ではなく上に置くことによって、タブがコンテンツ領域からより多くのスペースを奪っています。Chromeや――最近までの――Safari 4がウィンドウ枠自体をタブを表示するための追加のスペースとして使っている(それによってWebページのためにより多くのスペースを確保している)ように、あなたはすでに、ウィンドウの上の部分を可能な限り細くしたいと望んでいるでしょう。
  • ここでは見えてこない問題が1つあります。もしあなたが多数のタブを追加すると、サムネイルはタブの幅に合わせて縮んでしまい、あなたが探しているタブを見つけ出す上での視覚的な材料としては役に立たなくなってしまいます。
  • この実装があなたに対して、マウスのホイールを使うことで横方向にスクロールできる機能を――あなたが40個のタブを開いた時に、サムネイルが2ピクセルの幅になってしまう代わりに――提供していたとしても、多くの人はそれを試しすらしないでしょう。縦方向のホイールスクロールを横方向のスクロールのために使うでしょうか?

あなたが見たとおり、Operaは既存のいくつかのアドオンが取っているアプローチに似た試みをしていますが、残念ながら、それらのアドオンの便利さの元となっている多くの細かいポイントを見落としています。

念のために言っておきますが、私はOperaの長年の大ファンです。私の近しい友人の一人はつい最近までリードUIデザイナーとしてOperaで働いてすらいました。私はここでOperaのあら探しをしているのではなく、単にこの議論の実によい例示だったから挙げただけなのです。

測定についての覚え書き

私たちが検討したいと思っているいくつかの話題に移る前に、調査と統計の側面から以下のことについて手短に述べておきます:

タブについて考えるためには、タブの利用のされ方のデータが多ければ多いほど助かります。幸いなことに、Mozilla LabsのTest Pilot測定プロジェクトが、実際にどれだけの数の人がFirefoxを使っているのかを計測するためにブラウザに測定ツールを取り付けるという目標において先行しています。

このツールを使って、私たちは有益な数字――どれだけの人々が2~5個/10~20個/50個以上のタブを使っているのかという風な、Test Pilotのユーザの間でのタブの使われ方の分布などのような――を得ることができます。私は、5~10個よりも多くのタブを開いているユーザはそう多くないと確信していますが――しかしもちろん、50個以上のタブを開いている人達が本当にFirefoxに最初の段階で乗り換えてきたパワーユーザであって、私たちは彼らの生産性が高まるようにするべきとも考えています。

あなたは実際に、Jetpack用のアドオンであるTab Grapherを使うことによって、利用時間の経過に応じてあなた自身のタブの利用状況をグラフ表示することができます。あなたがタブの利用頻度の上記の尺度の中のどの位置にいるのかを知りたければ、この拡張機能を使うことは、それを明らかにする面白い方法となるかもしれません。

データは多ければ多いほどよいです。近い将来により多くのデータを収集するために、Firefoxをより良くするためにすべての人が私たちの助けになってくれることを願っています。

提案:Firefoxのためのいくつかの調査のステップ

上記の通り、あらゆる種類のユーザのためにタブの欠点を解消するたった1つのアプローチというものはありません。私たちがするべき事は、あなたが好みのタイプの操作方法を選べるようにして、それらの間をシームレスに移行できるようにすること、そして、以下に詳しく述べるような自然な移行のポイントを提供することです。

また、今はバージョン3.5の出荷を間近に控えている(訳注:元文書が書かれた日付はFirefox 3.5正式版リリースの直前にあたる2009年6月16日)状況なので、これは私たちがこれからFirefox.nextに向けて今後の数ヶ月の間により詳細に描き出していく予定の非常に大きな絵のうちの、小さな一部分に過ぎないということを心に留めておいてください。その時には、この最初の投稿よりもはっきりとした提案が世に出ていることでしょう。

初心者/中級者向け:サムネイルの見直し

既存のタブインターフェースが中級者のユーザに適しているのであれば、何故それにも関わらずインターフェースを変える必要があるのでしょうか? 主な理由は、この中間層のグループに分類される人々は、ユーザとしてどんどん注文が厳しくなってくるからです。彼らはより多くのタブを使い始め、そして彼らのうちの半数以上はすぐに、私たちが数年前にパワーユーザと定義した領域に突入します。

これは、タブのUIを自動的に移行するより良い方法、もしくは、最低でもせめて人々に対して以下のようなインターフェースの間を可能な限りシームレスに移行できるようにするオプションを、私たちは必要としているということです。

初心者中級者の理想的なインターフェースは、以下の特徴を持つことでしょう:

  • ごくわずかなWebサイトとほんの2~3のタブだけを使うユーザのために、良い体験を提供する。
  • 1つのタブだけを使っている状態を卒業して複数のタブを使うようになるのが、現在のそのステップよりももっと容易である。
  • 最近のワイドスクリーンのディスプレイを効率的に利用しつつ、低解像度のディスプレイのためのオプションも有している。
  • そのインターフェースで扱うことのできるタブの数を超えようとした時、次のレベルのUIに切り替える手段を提供する。

今までの所私たちが検討してきた解決策の中では、サイドバーベースの解決策が新しいオプションとその可能性を示しています。

固定されたサイドバーというアプローチが有効でない人もいる――画面上のあまりに多くの領域を占めてしまうために――ということには気をつける必要があります。これに対する1つの解決策となり得るのが、Mozilla Labsでプロジェクトの1つであるJetpackの一部として検討されており、また現在FennecモバイルブラウザのUIとして利用されている、スライドバーというコンセプトです(「サイド(side)」ではなく「スライド(slide)」であることに注意してください)。基本的なコンセプトは通常のサイドバーと同じですが、スライドバーの場合は常時表示されるのではなく、画面の端を使って、パネル自体を内容と一緒に横にずらして見えなくすることができます。これはあなたが低解像度の環境を利用している場合には良い解決策となり得ます。他の似た解決策がOperaのサイドバーに見られ、こちらはクリックされた時に展開されます。いずれにしても、サイドバーを一時的に隠すための方法には様々な可能性があります。

(「展開」モードのサイドバー) これらのワイヤーフレームは様々な機能について検討しています:

  • 開いている複数のページの間を切り替えるための主な方法として、サイドバー内に表示される部分的サムネイルによるSafariStand風のインターフェースを取っかかりとしています。
  • TVの「チャンネル選択」とコンセプト上の類似点があります――初心者はおそらく、彼らの好みのサイトをサイドバーに常時表示させておくだけの使い方をするでしょう。そのページがまだ開かれていない場合はそのページを開き、すでに開かれている場合はタブを切り替える、という物になるでしょう。
  • RSSアイコンやスターなど、いくつかのインジケータやボタンがサムネイルの中に追加され得ます――とはいえ私たちはそれを最小限にとどめるべきでしょう。
  • そこには大きな空のタブがあり、それによって、新しいタブをどうやって開けばよいかに気付きやすくします。
  • また、新しいタブには、タブから直接検索を実行して、タブが有効化される時に検索結果のページに切り替わるというオプションもあります。
  • (「閉」モードのサイドバー) 一旦、開かれているページの数が、部分的サムネイルを表示するのにもはや適切でないという閾値に達した時には、ツリー型タブのファビコン+タイトルというアプローチに遷移します。これにより、次のレベルのタブの管理の仕組みに気付きやすくなります。
  • もちろん、最上部に表示されるモード切り替えのUIによって、明示的にモードを切り替えることもできます。
  • 表示されるタブのリストをページのタイトルや内容によって絞り込むことができる、検索ボックス状の「タブを絞り込む」UIが備わっています。
  • 同様に、あなたの環境が低解像度であるなら、サイドバーの挙動をスライドバーへ任意に変更することができます。画面の横端をポインタでタップすることによって、ページ全体の表示がスライドアウトするでしょう。Fennecがそうしているように、これは小さな画面のデバイス向けの既定の挙動となると考えられます。

おっと、私たちはこのワイヤーフレームの中に戻る/進むボタンやアドレスバーなどを敢えて描きませんでしたが、もちろんそれらは引き続き存在し続けるでしょう。私たちはこれらの部分についていくらか変更を加えるつもりで、それについては今後の記事の中で詳細を語っていく予定なので、問題をややこしくしないためにこのワイヤーフレームからは除外しました。

このことから1つの素晴らしい結論を導き出せます。それは、開いている複数のページ――「タブ」――とブックマークは、シンプルな利用のされ方においては同じ物となり得るということです。Mac OS XのDockはアプリケーションが現在起動しているかどうかを気にせずに利用できますが、それに似ています。この話題も私たちが今後の記事の中でさらに語っていくであろう話題の中の1つですが、議論に集中するために、今はテーブルの上に載せたままにしておきます。

私たちは、私の祖母のような人達のためにほぼ確実に、既存のインターフェースよりもより良い形へと切り詰められており、また、タブの数が8~10個ほどという限界を超えようとした時には次の段階へシームレスに移行することができる、というインターフェースを持っています。

上級者向け:QuicksilverとFirefoxの出会い

私たちがパワーユーザを観察していて気がついたパターンとして、彼らはブラウズ用のインターフェースを可能な限り多く取り除く傾向があります。彼らはしばしば、すべてのツールバーやボタンを隠します――それらはすべて、ページの内容を表示するためにより広い領域を確保し、邪魔な物を最小限にするためです。なぜなら、彼らはほとんどすべてのことをキーボードショートカットを使って行うからです。彼らはブラウザの機能を示す物理的なリマインダ(ツールバーのボタンやタブなど)が全く無くても困らず、ただページの内容を表示するためのスペースを可能な限り広く取ることを望んでいます。

あなたがアプリケーションランチャ(※Mac用のQuicksilverやLaunchBarのようなツール、OS X(のSpotlight)やWindows Vistaの物のようなアプリケーションの起動と検索が一体化したインターフェース、あるいはLinuxにおける様々なアプリケーションランチャ)を使ったことがあれば目にしたことがあるかもしれませんが、もう1つの興味深いパターンとして、パワーユーザは彼らのファイルやアプリケーションがコンピュータ内のどこかにあるということだけを覚えていて、それらが実際にはどこに置かれているかについては気にしないでいても不満を感じない、ということをあなたはおそらく知っているでしょう。

この事は、以下のようなことを示しています:

  • パワーユーザは、UIが「脇に寄っていて」可能な限り最小限であることを好む。
  • パワーユーザは、どのページで何をしていたのかの詳細を彼らの頭の中で記憶しておくことが苦痛でなく、それらを保持しておくためのUIを必要としない。

手元にある情報に基づいて、私たちはパワーユーザ向けあるいはフルスクリーン表示用のインターフェースをこのように想像することができます:

(パワーユーザが使用している環境のイメージ)

  • あなたが新しいURLを入力するためにCtrl-Lまたは⌘-Lキーを押すまで、そこには全くUIがありません。タブもボタンもありません。
  • Ctrl-Lまたは⌘-Lキーを押すと、アドレスバーが出現します(もちろん、Ctrl-スペースまたは⌘-スペース、あるいはそれに似た別のショートカットを指定する方法も存在するべきです)。
  • すでに開かれているページは項目の横にインジケータが表示されており、プルダウンリストからその項目を選択すると、現在のタブにそれを読み込む代わりに、そのタブへジャンプします。
  • そこには選択されたページを新しいタブで開くための簡単な方法もあります。

これによってパワーユーザは、何百というページを一度に開いてブラウズするのに素晴らしいUIを手に入れ、同時に私たちはフルスクリーン表示――TVやプロジェクタなど――でWebブラウズするための良いUIを手に入れます。

開かれているタブの間の切り替えは、このように動作するでしょう:

  1. Ctrl-Lまたは⌘-Lキー(あるいは、自分で定義したショートカット、ウィンドウ上部におけるスライドバーのようなジェスチャなど)を押してアドレスバーを出現させ、
  2. タブの名前をアドレスバーに入力し始め、
  3. あなたが入力した内容に該当する開かれているタブがアドレスバーのプルダウンリストの最初の結果として提示され、
  4. その項目を選択するとそのタブに切り替わる。
  5. または、普段そうしているように、Ctrl-Tまたは⌘-Tによって新しいタブが開かれる。

どのようにしてパワーユーザ向けのモードを有効にすればよいのでしょうか? そこにはモードの切り替えという概念は無く、単にページ上であなたにとって不要な要素の表示をオフにするだけでよいでしょう。もしあなたがアドレスバーの表示をオフにしたら、ワイヤーフレームで描かれているような形で機能するようになるでしょう。

今すぐパワーユーザ向けのUIを試す

だいたいの所を把握するために、これがどのように機能するのか――「UI無しでのブラウズ」――を実際に試してみるには、Firefox 3.5を使って以下のようにして試してみることをお勧めします:

  1. すべてのツールバーを「表示」メニューからオフにする。
  2. ステータスバーを非表示にする。
  3. 新しいURLを入力するためにCtrl-Lまたは⌘-Lを使い、新しいタブを開くためにCtrl-Tまたは⌘-Tを使う。

現在のバージョンのFirefoxにおいて、私たちがパワーユーザとフルスクリーンモード向けに使いやすくするために修正するべきである、現状において欠けている点は以下の通りです:

  • 現状では、あなたはタブバーを隠すことができません。これは可能になっているべきです。
  • フルスクリーンモードはMac OS Xでは動きません。これは修正される必要があります。
  • (訳注:フルスクリーンモードにおいて)新しいURLを入力するためにCtrl-Lまたは⌘-Lを使った時、アドレスバーはURLの入力が終わった後も残り続けます。つまり、もう一度手動でそれをオフにする必要があるということです。これは、元の状態を覚えておいて、それが隠れていた状態であったのなら自動的に再び隠れるようになっているべきです。追記:これはFirefox 3.5で動きますが、Firefox 3.0では動きません――フル機能のスマートロケーションバーの代わりに小さなダイアログを得るにも関わらず。それでも、さしあたって実験の上では(訳注:その小さなダイアログは)十分よく働き、将来のバージョンでは可能であれば、スマートロケーションバーの全機能をあなたに提供するようになるでしょう。
  • アドレスバーはすでに開かれているタブの名前にも反応するべきです。これは大きな問題です。もしこの機能を加えることができればすぐに、あなたはSlashdotを表示したタブがどこにあるのかを気にしなくても良くなり、タブの名前を入力し始めるだけで、Firefoxばブラウザ上であなたが開いている200以上のタブからそれを見つけ出し、それに切り替えるでしょう。

組み合わせ

絶対に明らかなことがあります:あなたは上で述べられている可能性の中であなたのブラウジングスタイルに合う物を任意に選ぶことができます。

  • パワーユーザだが、開いているページの一覧を常に表示させておきたい、という場合には? LOLcat(訳注:lolcat翻訳機などを参照のこと)の200個のタブを一覧表示するための「閉」モードのサイドバーを除いて、他の物を非表示にするといいでしょう。
  • 4つのサイトしか見ないおばあちゃんのようなユーザのために設定をしたい時は? URLバーを隠して4つのサイトをサイドバーに置いておけば、おばあちゃんはそれをテレビのように使えるでしょう。

……などなど。ここに見られるように、これらの改善はあなたのWebブラウズ用ツールに対して強力な新しい機能と能力を加えます。

議論に参加する方法

Mozillaプロジェクトは、あなたの参加を歓迎します。私たちはその向こうに多くの素晴らしいアイデアが生まれてくると確信しています。私はAlex Payneの彼のブログにおける方針と同じ理由で、個人的にこのブログ(訳注:原文が掲載されているAlexander Limiのブログ)のコメント機能を有効にしていませんが、議論に参加するための最良の方法としては以下の物があります:

  • Firefoxのタブがどのように働くべきとあなたが考えているかについての記事を書いて、あなた自身のWebサイトに載せて下さい。あなたが私のサイト(訳注:原文が掲載されているAlexander Limiのサイト)へリンクし、私宛に言及していれば、私はそれを見つけて読むでしょう。いや、本当に。私の前の雇用主はGoogleで、物事を探すことは私たちがしていたことです。
  • Mozilla LabsのSummer 2009 Design Challenge(Reinventing Tabs in the Browser)に参加して下さい。
  • コメントが短いのであれば、あるいは書かれたことに対して単に何かを付け加えたい場合は、dev.apps.firefox Google Groupでそれらを投稿したいと思うかもしれません――Usenetのニュースグループ古典的なメーリングリストの形でも。
  • もしあなたが何らかのモックアップやワイヤーフレーム、あるいはこの議論に関連する図を作成したなら、FlickrやTwitter、あるいはその他のサービスにおいてmozconceptタグを付けてください。私たちはそれを見るでしょう。
  • もしあなたが誰もが見ることのできる場所で意見を公開することを望まないのなら――もしくは単に、Firefox User Experience Teamから私が新しいウェルカムパッケージとして受け取った新しい難燃性スーツを試してみたいなら――limi@mozilla.com宛にメールを送って下さい。

聞いて下さってありがとうございます! 次世代のFirefoxのタブをより良い物とするために皆さんがどんなアイデアを思いつくのか、楽しみにしています。

Page 19/80: « 15 16 17 18 19 20 21 22 23 »

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のコメント

最近のつぶやき