Document Shellは「Webページのウィンドウ」それぞれに対応する「仮想的なWebブラウザ」と呼べるようなもので、全てのウィンドウ・フレームについて存在しています。それぞれのウィンドウ・フレームごとの「次に進む」「前に戻る」「ページ内を検索」といった機能は、全てこのDocument Shellのメソッドで(正確には、Document ShellからさらにnsIWebNavigationインターフェースを経由します)提供されています……多分。
このDocument ShellはXPCOMにおいてnsIDocShellというインターフェース名で振る舞いが定義されています。XULのツールキットの中ではbrowser
およびtabbrowser
ウィジェットのdocShell
プロパティがnsIDocShellのインスタンスとしてアクセス可能で、例えば現在Navigator/Browserで閲覧中のWebページのDocument Shellは gBrowser.docShell
で取得できます。
前述したとおり、Document ShellはWebブラウザの機能の中枢を担っています。これを直接操作すれば、POSTメソッドで任意の内容を送信したり、ページ中を任意の文字列で検索したりということが可能になります。日本語でのインクリメンタルサーチを実現するXUL/Migemoもその応用例の一つと言えます。
ところが、browserのdocShellプロパティが参照しているのはあくまでトップレベルのフレーム(のwindow
オブジェクト。Webページから見た時のwindow.top
。)に対応するDocument Shellです。フレーム分けされたページやインラインフレームで取り込まれているページのフレームそれぞれに対応するものではないので、これでは、先述したような「応用」はトップレベルのフレームに対してしか利用できません。
では、個々のフレームに対応するDocument Shellにアクセスするのは不可能なのでしょうか。いえいえ、そんなことはありません。以下のやり方を使えば、実際に個々のフレームのDocument Shellにアクセスできます。
フレームはツリー構造になっていて、parent
プロパティやframes
プロパティでそれぞれのフレームを辿っていくことができます。実はDocument Shellもそれと同じようなツリー構造を持っていて、子フレームに対応するDocument Shellから親フレームのDocument Shellを、親フレームのDocument Shellから子フレームのDocument Shellを辿っていくことができます。
ここで使用するのがnsIDocShellTreeItemインターフェースのnsIDocShellTreeItem.parent
とnsIDocShellTreeNodeインターフェースのnsIDocShellTreeNode.getChildAt()
です。以下に例を示します。
var docShell = gBrowser.docShell;
var docShellTreeNode = docShell.QueryInterface(Components.interfaces.nsIDocShellTreeNode);
var forFirstFrame = docShellTreeNode.getChildAt(0)
.QueryInterface(Components.interfaces.nsIDocShell);
var forSecondFrame = docShellTreeNode.getChildAt(1)
.QueryInterface(Components.interfaces.nsIDocShell);
var current = forFirstFrame;
var forParentFrame = current
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.parent
.QueryInterface(Components.interfaces.nsIDocShell);
先の例とは別のアプローチで、フレームに対応するDocument Shellをフレームから取得するやり方もあります。先の例がトップダウン方式なら、こちらはボトムアップ方式といえますね。以下の例を見て下さい。
var win = document.commandDispatcher.focusedWindow; // 現在アクティブなフレーム
// var win = gBrowser.contentWindow; // トップレベルのフレーム
// var win = gBrowser.contentWindow.frames[1]; // 二つめのフレーム
var docShell = win
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShell);
ここではnsIWebNavigationインターフェースがDocument Shellとフレームを繋ぐ架け橋のような役割を果たしています。