Now browsing the archives for the 'General' category.

[Places] ビューと nsIPlacesView インタフェース

nsIPlacesView インタフェース

ブックマークや履歴といった Places データベースに保持されている内容は、ツリー/メニュー/ツールバーといった色々な GUI ウィジェット(「places view」あるいは単に「ビュー」と呼ぶ)として実際に目に見える形で表示される。各ビューはいずれも XBL にて nsIPlacesView インタフェースで定められた各種プロパティ・メソッドを実装しており、ビューの違いを意識することなくコントローラ側で各種機能を実装できる設計となっている。

Places ではデータベースへの問い合わせ結果を所定のインタフェースを介してビューに結びつけて表示させる。問い合わせ結果全体を表す nsINavHistoryResult オブジェクトからは、個々の「行」に対応する nsINavHistoryResultNode オブジェクトへアクセス可能である。このオブジェクトを「result node」あるいは単に「ノード」と呼ぶ。あるビュー上でユーザが現在選択している項目に対応するノードは、 nsIPlacesView インタフェースの selectedNode プロパティや getSelection メソッドによって取得可能である。

placesUIOverlay.js

引き続き、 [Places] 右クリックメニューへのメニュー項目追加 にて新たに追加した「Show Information」メニュー項目をクリックした際に実行される showBookmarkInformation 関数を実装する。

まずは右クリックメニューの対象となるビューと、そのビューにて選択しているノードを取得する。ここで、対象のビューとしてブックマークサイドバーのツリーだけを考慮すると、うっかり以下のようにやってしまうところである。

var view = document.getElementById("bookmarks-view");    // XULElement
var node = view.selectedNode;    // nsINavHistoryResultNode

しかし、これではせっかくのビューの違いを意識しない Places の設計が台無しである。ツリー/メニュー/ツールバーすべてを考慮して右クリックメニューの対象となっているビューを取得するには、以下のようにすればよい。 PlacesUIUtils.getViewForNode は、引数に指定した DOM ノードの先祖をたどって直近のビューを見つけ出す便利メソッドである。

var view = PlacesUIUtils.getViewForNode(document.popupNode);    // XULElement
var node = view.selectedNode;    // nsINavHistoryResultNode

あとはノードの各プロパティの情報を表示するだけ。各プロパティの詳細は nsINavHistoryService.idl 参照。

alert(
    "title     : " + node.title + "
" + 
    "uri       : " + node.uri + "
" + 
    "type      : " + node.type + "
" + 
    "icon      : " + (node.icon ? node.icon.spec : "") + "
" + 
    "itemId    : " + node.itemId + "
" + 
    "tags      : " + node.tags
);

TOP

[Places] 右クリックメニューへのメニュー項目追加

Firefox 2 でのブックマークの右クリックメニューは、ポップアップを表示するたびに JavaScript によって menuitem 要素を動的に生成する実装方式であったため、拡張機能によってメニュー項目を追加しづらいという問題があった。しかし、 Firefox 3 にて Places として実装が一新され、右クリックメニューの menuitem 要素や呼び出される command 要素は placesOverlay.xul という XUL ファイルで実装する形になり、拡張機能からのメニュー項目追加がしやすくなった。

Places の右クリックメニューは、以下の5つの場所で使用される。

ブックマークメニュー chrome://browser/content/browser.xul
ブックマークツールバー
ブックマークサイドバー chrome://browser/content/bookmarks/bookmarksPanel.xul
履歴サイドバー chrome://browser/content/history/history-panel.xul
履歴とブックマークの管理 chrome://browser/content/places/places.xul

各 XUL はいずれも placesOverlay.xul (chrome://browser/content/places/placesOverlay.xul) をオーバーレイしている。そこで、拡張機能から placesOverlay.xul に対してさらにオーバーレイして menuitem 要素などを追加することで、上記すべての場所の右クリックメニューへ一括してメニュー項目を追加することが可能となる。

サンプル

例として、ブックマークの右クリックメニューへ「Show Information」という新しいメニュー項目を追加する。
Places Context Menu

chrome.manifest

overlay    chrome://browser/content/places/placesOverlay.xul    chrome://myext/content/placesUIOverlay.xul

placesUIOverlay.xul

<popup id=”placesContext”>, <commandset id=”placesCommands”> をマージポイントとして menuitem 要素と command 要素を追加する。

<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

    <script type="application/x-javascript" src="placesUIOverlay.js" />

    <commandset id="placesCommands">
        <command id="placesCmd_showInfo" oncommand="showBookmarkInformation();" />
    </commandset>

    <popup id="placesContext">
        <menuseparator insertafter="placesContext_openSeparator" />
        <menuitem id="placesContext_showInfo"
                  command="placesCmd_showInfo"
                  label="Show Information"
                  insertafter="placesContext_openSeparator"
                  selectiontype="single"
                  selection="bookmark|folder"
                  forcehideselection="livemarkChild|livemark/feedURI|PlacesOrganizer/OrganizerQuery" />
    </popup>

</overlay>

ブックマークの右クリックメニューは、右クリックした対象が通常のブックマークか、フォルダか、区切りか、などの条件によってメニュー項目数が増減する。メニュー項目を表示する条件は、 menuitem 要素へ追加された以下の4つの特殊な属性の値によって決定される。詳細は PlacesController クラスの buildContextMenu や _buildSelectionMetadata のコメントを参照。

属性 役割
selectiontype single, multiple のいずれかの値をセットすることで、選択している対象が単数か複数かの条件によってメニュー項目を表示する。
selection any, bookmark, folder, separator といった値を指定することで、選択している対象がブックマークか、フォルダか、区切りかといった条件でメニュー項目を表示する。 | 区切りで複数指定可能。
forcehideselection selection 属性の逆で、選択している対象の種類によってメニュー項目を非表示にする。
hideifnoinsetionpoint よくわからん。

上記の例では、単一のブックマークあるいはフォルダを選択しているときにだけ「Show Information」メニュー項目を表示する。ただし、例外としてライブブックマークや特殊な「ブックマークツールバー」フォルダを選択しているときはメニュー項目を表示しない。
また、上記の例ではメニューの区切り(menuseparator 要素)も追加しているが、ありがたいことに Places の右クリックメニューは連続するメニューの区切りを自動的に1個にして表示してくれるので、新たに追加するメニューの区切りについては、どういった条件で表示するのかを意識する必要が無い。

placesUIOverlay.js

function showBookmarkInformation() {
    // TODO
}

[Places] ビューと nsIPlacesView インタフェース へつづく…

TOP

_base_href 属性

<html>
  <body>
    <base href="http://www.mozilla.com/">
    <a href="/en-US/firefox/"><img src="/img/firefox-title.png"></a>
  </body>
</html>

上記テストケースのように、 <body> 内に <base> を配置した HTML を Firefox で開くと、 <a> や <img> に対して _base_href という属性が勝手に付加される。実際に DOM インスペクタにて確認可能。
もちろん <a> と <img> だけでなく、 <object> や <embed> も影響あり。

TOP

Ts/Txul regression

Bugzilla でたまに見かける「Ts/Txul regression」とかいうのは、以下のような項目の測定をした結果、パフォーマンス低下が見られた、という意味らしい。

Ts: 起動時間
Tp: ページのロード
Txul: 新規ウィンドウのオープン

Policy on Handling Performance Regressions

TOP

XULPlanet の未来

入門者のためのチュートリアル、各種オブジェクトやXPCOMのリファレンスとして長らく重要な役目を果たしてきた XULPlanet であるが、ここにきて転換期を迎えているようだ。

チュートリアルの内容はすでに MDC へ移行しており、 XULPlanet の内容はもはや古くなってしまっている。チュートリアルの作者でもある Neil Deakin 曰く、今後唯一期待できることは Firefox 3 リリース後に XPCOM リファレンスの内容を一括アップデートする程度であるとのこと。 XULPlanet を生き返らせるための何か新しい道を模索するか、あるいはすべてのコンテンツを削除して単なる MDC へのリダイレクトへとするか、問われている。

個人的にはチュートリアルには大変お世話になったし、 XPCOM のメソッドの使い方とかは未だに XULPlanet で検索することがあるので、完全に無くなってしまうのは惜しい気がする。

TOP

FUEL 2.0

FUEL – MDC からリンクされている全オブジェクトのページの和訳が完了した。
以下、 FUEL 2.0 で追加された各オブジェクトについての雑感。

Window

ブラウザウィンドウの新しいタブでURIを開く。
タブを開く・閉じる・移動する・選択するイベントを監視する。
ブラウザウィンドウを開いた直後(つまり browser.xul にて window の load イベント発生時)に、イベントリスナを追加するために、 Application.activeWindow.events.addListener… などとやりたいところだが、アクティブなウィンドウ=今開いたウィンドウとは限らない?つまり、バックグラウンドでウィンドウを開くようなケースもありうるかも?

BrowserTab

タブでURIを読み込む、タブを移動する、タブを選択する、タブの内容ドキュメントを取得する。
タブへの読み込みイベントを監視する。
Window#open と BrowserTab#load は使用頻度高そうだが、引数はどちらも nsIURI オブジェクトってのは痛い。 FUEL の目的は XPCOM を意識しない形へとコードを簡略化することじゃなかったっけ?

BookmarkFolder

Bookmark

ブックマーク・区切り・フォルダの追加、削除、各プロパティの取得と変更。機能的にはそれだけ。
BookmarkFolder#addSeparator の引数にタイトルを指定できないのはなぜ?と思ったら、 Places では区切りにタイトルを付けられなくなっているようだ。

Annotations

Places:Annotation Service 自体は拡張機能開発者的にはかなり期待できそうなシステムだけど、 FUEL の Annotations オブジェクトによってどういうメリットがもたらされるかは現時点では不明。

TOP

WinMerge 7-Zip Plugin (for 7-Zip 4.57)

7-Zip を 4.56 から 4.57 へアップデートしたら、 WinMerge7-Zip Plugin が使用できなくなった。
応急処置としてプラグインのDLL 「Merge7z456.dll」「Merge7z456U.dll」を「Merge7z457.dll」「Merge7z457U.dll」という名前に変更することで、今のところ問題なく動いている。

12/24追記
7-Zip 4.57 用の WinMerge 7-Zip Plugin が SourceForge から入手可能になっています。

TOP

Firefox 2 / Firefox 3 の判別方法

browser.xul にて Firefox 2 か Firefox 3 かを手っ取り早く調べるには、例えば BookmarksUtils か PlacesUtils が存在することを調べる。

if ("PlacesUtils" in window)
  alert("Maybe Firefox 3.");
if ("BookmarksUtils" in window)
  alert("Maybe Firefox 2.");

より厳密に調べるなら、 nsIXULAppInfo を使う。これなら browser.xul 以外の場所でも可能。

var appInfo = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo);
if (appInfo.version.substr(0, 1) == "3")
  alert("Firefox 3");

TOP

tabbrowser.xml と関連ファイルの移動

Bug 339964 – move tabbrowser.xml out of mozilla/toolkit and into mozilla/browser
Firefox のタブブラウザ関連UI (<xul:tabbrowser> 要素) は Firefox 固有の性質が強いため、 toolkit.jar から browser.jar 配下へ移動された。これに伴い、関連する XBL や DTD などの URL が以下のように変更となった。

Firefox 2.0.0.6 Firefox 3.0a8pre
chrome://global/content/bindings/tabbrowser.xml chrome://browser/content/tabbrowser.xml
chrome://global/skin/tabbrowser.css chrome://browser/skin/browser.css へ統合?
chrome://global/locale/tabbrowser.dtd chrome://browser/locale/tabbrowser.dtd
chrome://global/locale/tabbrowser.properties chrome://browser/locale/tabbrowser.properties

TOP

en-US 言語パックの作り方

追記:コメントにて、わざわざ言語パックを作る必要の無いもっと簡単な手順を教えていただきました。

日本語版 Firefox 2 をインストールしたが、スクリーンショット撮影用に一時的に英語版 (en-US) に切り替えて使いたいときがある。ここを見てもイギリス英語版言語パック (en-GB.xpi) しか置いていない。もしかしてどこかで配布されているかもしれないが、何とかして自前で en-US の言語パックをインストールする。以下 Windows 版 Firefox 2 が前提。

手順

  1. firefox-2.0.0.6.en-US.win32.zip をダウンロードして展開する
  2. プロファイルフォルダの extensions フォルダ内にフォルダ「langpack-en-US@firefox.mozilla.org」を作成
  3. 1.で展開した chromeen-US.jar と en-US.manifest を2.のフォルダへ配置
  4. en-US.manifest を chrome.manifest にリネーム
  5. 2.で作成したフォルダにファイル「install.rdf」を作成し、以下の内容を記述
    <?xml version="1.0"?>
    
    <RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:em="http://www.mozilla.org/2004/em-rdf#">
      <Description about="urn:mozilla:install-manifest"
                   em:id="langpack-en-US@firefox.mozilla.org"
                   em:name="English (US) Language Pack"
                   em:version="2.0"
                   em:type="8">
        <em:targetApplication>
          <Description>
            <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
            <em:minVersion>2.0</em:minVersion>
            <em:maxVersion>2.0.0.*</em:maxVersion>
          </Description>
        </em:targetApplication>
      </Description>
    </RDF>
    
  6. about:config から general.useragent.locale を en-US に変更して Firefox 再起動

TOP