Now browsing the archives for 11月, 2006.

menulist 要素内での menuitem-iconic クラス

xul:menuitem 要素へアイコンの画像を表示させたい場合、menuitem-iconic クラス を付与して src 属性に画像の URI を指定すれば良い。この方法は xul:menu 要素や xul:toolbarbutton 要素 (type=”menu”) 配下に xul:menuitem 要素を置く場合であれば、うまく動作する。

<menu label="MENU">
  <menupopup>
    <menuitem class="menuitem-iconic" label="MENUITEM" src="http://www.mozilla.com/favicon.ico" />
  </menupopup>
</menu>
<toolbarbutton type="menu" label="TOOLBARBUTTON" >
  <menupopup>
    <menuitem class="menuitem-iconic" label="MENUITEM" src="http://www.mozilla.com/favicon.ico" />
  </menupopup>
</toolbarbutton>

ところが xul:menulist 要素配下に xul:menuitem 要素を置く場合、 xul:menupopup 要素のドロップダウンリスト中ではアイコンの画像が表示されない。

<menulist>
  <menupopup>
    <menuitem class="menuitem-iconic" label="2ちゃんねる"   src="http://www.2ch.net/favicon.ico" />
    <menuitem class="menuitem-iconic" label="PINKちゃんねる" src="http://www.bbspink.com/favicon.ico" />
    <menuitem class="menuitem-iconic" label="まちBBS"        src="http://www.machibbs.com/favicon.ico" />
    <menuitem class="menuitem-iconic" label="したらば"       src="http://jbbs.livedoor.jp/favicon.ico" />
  </menupopup>
</menulist>

menuitem-iconic

ドロップダウンリスト中にも画像を表示させるには、 chrome://browser/skin/feeds/subscribe.css を参考にして以下のような CSS を適用してやる。下記の例ではついでにサイズの大きな画像を 16×16 px に縮小させている。

menulist menupopup > menuitem {
  -moz-padding-start: 23px;
}

menulist menupopup > menuitem.menuitem-iconic {
  -moz-padding-start: 2px;
}

menulist menupopup > .menuitem-iconic > .menu-iconic-left {
  display: -moz-box;
  min-width: 16px;
  -moz-padding-end: 2px;
}

menulist .menulist-icon,
menulist menupopup > .menuitem-iconic > .menu-iconic-left > .menu-iconic-icon {
  width: 16px;
  height: 16px;
}

menuitem-iconic

TOP

nsIFeed から各種フィード情報を取得する

Firefox 2 に搭載された Feed content access API を使って、各種フィード情報を取得する。
以下、「feed」を nsIFeed 型オブジェクトとする。

フィードのタイトル

// マークアップされている場合にタグも含んだ文字列を取得する
var feedTitle = feed.title.text;
// マークアップされている場合にタグを除いた文字列として取得する
var feedTitle = feed.title.plainText();
// マークアップされている場合に node に対する DocumentFragment として取得する
var feedTitle = feed.title.createDocumentFragment(node);

フィードのサブタイトル

title, subtitle プロパティはともに nsIFeedTextConstruct 型を返すので、マークアップされている場合の取り扱いは title 同様。

var feedSubTitle = feed.subtitle.plainText();

フィードの最終更新日

nsIFeedContainer の updated プロパティは RFC822 形式の文字列を返すので、そのまま Date オブジェクトを生成することが可能。

var feedUpdated = new Date(feed.updated);

フィードの画像

RSS2.0 の image タグで記述されたフィードの画像を取得する。

var feedImage = feed.fields.getProperty("image").QueryInterface(Components.interfaces.nsIPropertyBag2);
// 画像のURL
feedImage.getPropertyAsAString("url");
// リンク先URL
feedImage.getPropertyAsAString("link");
// タイトル
feedImage.getPropertyAsAString("title");

リファレンス:
nsIFeed – MDC
nsIFeedContainer – MDC
nsIFeedTextConstruct – MDC
Interface Reference – nsIPropertyBag2

TOP

nsIFeedEntry から各種フィードエントリ情報を取得する

Firefox 2 に搭載された Feed content access API を使って、各種フィードエントリ情報を取得する。
以下、「entry」を nsIFeedEntry 型オブジェクトとする。

エントリのタイトル

フィードのタイトルと同様。

var title = entry.title.text;

エントリのパーマリンク

nsIFeedContainer の link プロパティは nsIURI 型を返す。

var parmaLink = entry.link.spec;

エントリの最終更新日

フィードの最終更新日と同様。

var lastUpdated = new Date(entry.updated);

エントリの本文

// RSS2.0の description タグで記述された内容を取得する
var summary = entry.summary;
// RSS2.0の content:encoded タグで記述された内容を取得する
var content = entry.content;
// node に対する DocumentFragment を生成する
var docFrag = (content || summary).createDocumentFragment(node);

エントリの筆者

for (var i = 0; i < entry.authors.length; i++)
{
    var author = entry.authors.queryElementAt(i, Components.interfaces.nsIFeedPerson);
    // 名前
    var authorName = author.name;
    // E-mail
    var authorMail = author.email;
    // 関連 URI(多くの場合ホームページ)
    var authorURI  = author.uri.spec;
}

エントリのカテゴリ

nsIFeedContainer の categories プロパティは使えないようだ。その代わり、以下のようにすることで成功。

var categories = entry.fields.getProperty("categories").QueryInterface(Components.interfaces.nsIArray);
for (var i = 0; i < categories.length; i++)
{
    var category = categories.queryElementAt(i, Components.interfaces.nsIPropertyBag);
    // カテゴリ名称
    var term = category.getProperty("term");
}

リファレンス:
nsIFeedPerson - MDC
Interface Reference - nsIArray

TOP

[userChrome.css] IE7 Throbber

Firefox 3 の Throbber (読み込み中にクルクル回転するアイコン)が地味であまり好きではないので、Internet Explorer7 風に変更するための userChrome.css です。アイコン画像は Ex Aequo から拝借し、少し改変して回転速度をアップさせています。

実際にアイコンの動きを見る

IE7 Throbber

userChrome.css

/* ::::: IE7 Throbber (Firefox 3) ::::: */

#navigator-throbber[busy="true"],
toolbar[iconsize="small"] #navigator-throbber[busy="true"],
toolbar[mode="text"] #navigator-throbber[busy="true"],
.tabbrowser-tab[busy] > .tab-icon-image,
.alltabs-item[busy] > .menu-iconic-left > .menu-iconic-icon,
#sidebar-throbber[loading="true"],
#checkForUpdates[loading="true"],
#extensionsManager richlistitem[loading="true"] .updateBadge,
#extensionsManager .addonThrobber,
#extensionsManager .throbber {
    list-style-image: url("data:image/gif;base64,R0lGODlhEAAQAIcAAO7y9%2BHs8anG24Kty2Wbv63J23eqx5vC1bvW4tXm7JfC0pq3xYa0x7XU3bLP3Z3F1ZnGzqrO18rm7aO3vYCktqfK2ZG9z97m7GyLlIS8wJW9wXKRl4CotL3Z222hpVqXjmensWyllE%2BMgXqXnFGcoRedoSSdkimBd46nrGeHjUGythS1ryq0o8Dp487p5Ql2YiVmWUu8xIPk4fX7%2FKjW0uvy9p3NzHiztGrL1Jnn5dzy7pvbxujy8kS4qzOPgrnp8T3Z4ur9%2FYPbxdLx83fHxjO2pmC9stPo40nZ1Jn497f3%2BKj08y3YwYDdz8Lp6ozZz0TJuzrLtGTWy1S1qZi7ty7t41fv6Cbc2hXWyRHFsk7ky3je01bMxY7GuWjh1DHl1Vf283vv66Pv6UbTp5LcwdHt5YTfulnYqjvVqovfvr%2Fb42eapXzAz6fFyme9xIfN15zV3UfFyanq7Z7L0VB%2BeyvR09309svn5iJYXMXy79zt667X1CxtcFTWypnx7%2BPz72fUu97y9Vasqavn5jPZ0Xr483HHvlO9tGOspV6LiEPZu8zq65PW0kjFqym7tFnHuCPUtZrDwTbfs1fn4Xnn4Jjj2aHYzeTy96bc5pjO3oLW3qG9x9bt8YKwsBno3j3SztPo7DvJxXrVyg9sbmO5ri7MnlnTt4TEqVuknn3LrIrv6Mf6%2BivBlZLd0FfDqrTu6X3QxXPSqdPy%2BF7H2m%2FY5bzh6ajS35rr7tr6%2BkXq5lp9hTa9yipZYTPBpghhaB5SWEq8nGTZ3SSkmhGtl2jCsqni3H%2FGu1aqwV%2BgwJ3L3JXT3EGyhB%2FFvkjEhoTTypC%2Fsc3o3ZvT0Zrc1EvN4mrw68vs8li1iSyto0upkguSjzeppEu3uGTJxGXGt5%2Fg1gvy55XP0YT7%2BeX9%2FKLV1r%2Fi4qHL0kqeilDe3ZPPyUvTxWXi5tP49pDZ2Fu2nHCyqYnVzp3a3YnFyFmmkmWZk4rRxS6ssLHd3bfn6pPEzHmzyJLY4a7R2tP8%2FCzGwyzOeG359iH%2FC05FVFNDQVBFMi4wAwEAAAAh%2BQQJBAAAACwAAAAAEAAQAAcI1wABCAQQQMAAAgQGCAgwsGEBAwcQJJiowECBhgAWMEDQwMEDCBEaSGCwYOAEChUOWHCQ4IIDCxAqUJgA4AIGjQcwAjiQQQOGCxM2cGCgU2CGDhsmePgAIkJRABFCiBhBooQJCU8TnECRQsUKFi2eungBI0UMGTNo1Chq48aJEThy6NixFiOPHj5ETPgBJEgLIUMa1iBSxMiHIwCQJFGyhEkTJ06eQIkiZQoVgTqQVEli5QqWLEy0bOHShcfAIV6%2BgAmjRIwYGWPImG7Io4yZM2PQnElTpmFAACH5BAkEAAAALAAAAAAQABAABwjTAAEIBBBAwAACBAYICDCwYQEDBxAkSKDmgYECDQEsYIAAQYQHDyp0ZLBg4AQKFQ5YcJDgggMLITlMAJBgDQQ2CjICOJChDYYLbNy8YVNDZ40MCzZMiMEFBxydAiOE2DAijpw5EqDSPEEnRR07HY5ovXMCT4orefTs4QHVxgk%2BI%2Fr4%2BQMokE4egrhOGESo0Jc%2BOhrWMHQIUaILgQAVKqRFUZNFixg1cvRoyswaib8oCcMkSxZIUpo8iiQ4jaRJlMQokVHpkaWiGcuYATRmzBkyehoGBAAh%2BQQJBAAAACwAAAAAEAAQAAcI3AABCAQQQMAAAgQGCAgwcGCNAgYOIEiQAMEDAwUaXrLABgGCCg8eVPDIYIHAQGxwYMqkwEGCCw4sHKhAYQKAH3FyaHpzqSEABRY2YbiAQw6nTD19AmDQacOEOkMuIKihFEAEDxhGeLLTIUFVAAn4wEjxaQmEO19B8cGTIlQVLKKoKrUxis8IQFX8SAmktAapE3Qm3CllhYkpO3IB1DDUA1GiCwBOaVEiSZEQUIsYNWJxCJVNgam0qFrFJEsWVoBauYrUkEeaMV5kVHpVSRSsPX3LmDkzxlWsHXoaBgQAIfkECQQAAAAsAAAAABAAEAAHCNcAAQiswanCAAIEBggIILAhAFmaZmVCkCABggMGCji0M4vWj1q2Dhyo0AABgwUNZ93CNeiNrQQXHFgYSWECgEG5ZgSwdckhAAUnMVzos4SHmho%2BBTLgsGFCqCSgGiBNGmGNrhGQPO36kVRgAj68UvTytMJJVwAJfP1KAYxQFlFnbYziM%2BIUmmBNdCStQUoEnQlHWG2RZIqHT0PCECW6AMCuKkVohCwCxQhYEVeobALgkUoGJTGmVgwrZWoQsUgOeZgZs6VJpWKDYhHb07UMmViuXBmzxLBhQAAh%2BQQJBAAAACwAAAAAEAAQAAcI1gABCATwQ9OsY8gGCAgwsCEtWrd%2BcAKF4ICBAg3tEEoy45IcOMkqOEDAYIHAQFz8dFRjS0ICBxYOVKAwAYAEQqs4IahRo%2BGBkhguGLIS5s2lhgMZcNgwAdikYMqQDoywRteIZXVWSJAqMAEfXimWMSuxlWsCX79SNCtSwllPqTZG8RnxrJejRzy4khJBZwK0ZaK2mHo70JAJRIkuAEjVqE%2BURk9cgIrmioUrVDUFpgIkxtSWYcN6uWplLFLDGjtcAapUSVorWK72SK0RYIcxI6SM0WA4MCAAIfkECQQAAAAsAAAAABAAEAAHCNcAAQgEICcYkGm7ZiULMFBgjSHBrKwKUkPWj2QGCjQM1IcaxRqcMGFCgIDBgoEZrCyppkZNAgm2LByoQGECAGhR%2FMh4c6lGQwUmMVw4ZUoGDp8NBTLgsGGCNS444CBNGmGNrhHLrpWQkHRgAj68UmArkY1rVwAJfP1KYU1bNmVnAcwZxWfEKWzXtv05K8gHnQnQsBnhYqirIROIEl0A8AwYt16NGLkAFe0Qi26obAKo0eVRpUeNWAxj8QgWsUgNa9DoZqiVN2nOYBnZczYADWOkSBmjwXBgQAAh%2BQQFBAAAACwAAAAAEAAQAAcIzwABCARQjdaVb1em0ao2sCG4KuGCzJghTtWsZA0BpKKmZMafPzxmvPrBZsHAZ17E3Noy7kKCcW%2Fg2KIwAcCFZnlkvMkIQAGDBRguUDHVhAhPgQw4bJhgjRy3cUcBRFija8QyYcISRE3Ah1cKa9myaT2awNevFCF8CLIRtRwfPiOomDMxpcZRQSfoTLhgjtQ1oxkNCUOU6AKACYK6FTkUzQWoaIeudUNUU2AkV84AsWAxjMUjZ0YiZdxjBJaQYtKcGTKy52gAGsZIGTFGI0DDgAAh%2BQQJBAAAACwAAAAADwAQAAcImwABCARQxtmnK0CunPsxUCAPdOlU4RIXZMYqdbRk1QDAw5CXdevEiKlRY0YQWjguCeQ2aBA7dk4WdVBTTQ6OBdDaFdPEcSOAGpfevAG35hSxaAD%2BNBRYgw0DACGMEVtKFcAHdyaqLv1w4oULrQ1P%2BAAHdhSACSLMgW2YCFHWtQJRGekhEFRDI0uNwHoEYJjAQ%2B%2FABvYGdyApqgEBACH5BAkEAAAALAAAAAAQABAABwjWAAEIrBHA2aNQoQjRkiOwIQAe6LjkELcOl5Ik6s45BBBLlJ1Xr3J8FDcjybRAAk8ZwpTnHRwnLeAhqDHjFo5LR1BFe%2BNMR8MaNRBwyhNDAhUNNojU2Ajg0htNbuKFkOduHFOBmdwI8jCv04lFVwGAOsEHQ6ITLxKETeALD4ARfF7YCFtuFB8AE%2Bh8ILWUqaATdABcSIRImCGmREyASCRwAqopRQ5FAwUq2qFrh1BNaBjJCKxDLIYNY3EIlpFIG%2FcYMfROmjdnhozsuRqAhjFSpIzRCOAwIAAh%2BQQJBAAAACwAAAAAEAAQAAcI1wABCATggp6bKFAeOVtUY6BAHvQeOckjS5YSVeeCDRlYIwOsFnkGOXEiR4kSK0gCCaRyw0kZZ5actICjSQ4uP0gAXJgHIR49Hg4D2Qow49yPCZ0yZLjkUGANNZfk4BgRwl2Epk4bSMgRIxGdE0ewCpRQz5GKDSFeJBALQEK2EiRG8Hlhg%2B2cUT7WTKDjg1RDrMdO6JpwIREibYawEjGBKtEFABNQHbp2KBqoBNEmH0I1YWAkUrAOsRg2jDIsUpGa7jFiyJk0ac4MGdkjNgANY6RIGaMRwGFAACH5BAkEAAAALAAAAAAQABAABwjXAAEIBKAH3aMe29w4KzOwYTk29u7ZGfJDRh90NRpqIEKOU7EhmDD9UKLOUCCBE26Asgdr3J07cN7kWGKFW6ALGDSgi8ejYSBNMpIgGTRhQ6cMGRsCCJRJ1pI%2BI1B4iKBUYI0GF2RdScTnxJGqAhN0sFNnQ6IXCcACAIVPTpwRIl7YUPtmxa4YE%2BicEJS0YY1t9VTEu5AIUQ9DVQ0JM0ICFIAJqA5dOxQNFKhoh%2BptQzVhYCRSsA6xGDZsMixSkZTuMWLImTRpzgwZ2QM2AA1jpEgZoxGgYUAAIfkECQQAAAAsAAAAABAAEAAHCNsAAQgEEGBOvmPbHtErU2PgwAL5otXiBOqePm70eDhckAEUOXJq4GC698OLsYETOHSIFo%2FGHVC23sCTI%2BUUgAsYIu3B11BgjUtvNPmJcmfChk4ZNDoEEAhHmEmARmDwEGHpQH20rIRKQedEAqsCJcxZ8ikRjBdfwSZoYMfTiBEvyoGtsa%2FDkDoTugoCe4nIvRw4LiRCpI3I0hrcmKkLdQ%2FABFRGrh2KBgpUtEOO%2BsQhEkhgJCOwDrEYNuxaDFFc4l3qCWCPEUPOpEl7Z8jIHrABaBgjRcoYjQAOAwIAIfkECQQAAAAsAAAAABAAEAAHCNcAAQgEEEBAPmTH8oErM7BhAQMQ1IACVUsZN3p%2FGi6wkKCDhHLJatW6x84YD4ETONCYE28fKBe23sDLA%2BgUgAsY2pTD1xBAjTdNBrk6MmFDpwwnewYikqPmCF1rIvQcqEzKOWAp6PABNVWgE2ZVeqWA4StBVwD3toSBNILOCxtda1gqFi7UhEQnBMXdwSNPnwuJEAkj0lOHtzxBcg0CMAGVkSKHok1kBIXSujCzBkYyAusQi2HDHPWh9CVYoIZ7jBhyBk%2FaOynpNMmaGoCGMVJGjI3jVGNgQAAh%2BQQJBAAAACwAAAAAEAAQAAcI2AABCAQQQMAAAsjyPQhQY%2BDAAgYOIEiQQE0yN%2BV4OFxgoYOaBg9sNbB3B06qgRM47CuHbx%2FFffHgFTN0CsAFDG3i4XMIoMabd4vaQZuwgUGGhjxrEHH26NkIXWsi8BRYAw63R81S8OIDaqrAFlCkLMPAx1cCrwDAqls2gs8oG2hFYckFbEIKH4K86jBFLYmhC4kQmSDisAYPb%2BuSYFkEYAKqQyoORVskgd2TV7jCSAkkMJIRWIdYrMhCaAm%2FMF84D9xjxJCzSjkohZmkzmsAGsaMPOqj6ZXDgAAh%2BQQJBAAAACwAAAAAEAAQAAcI1QABCAQQQMAAAgQGCAgwsGEBAwcQJEiAAEK%2BAg0BLGCAAEGFBw4i2OMUL0MNgRM4OHigYN%2FEffGi2YtHBcAFDAsyKMgIAB%2B4PfKgTdiwkSeAGkSIuDs1QteaCEYBRDN0yFoKXnwSRG0B6x22q760Gm0xjNWyEXxGlTNaQ1SUHNYm6DohyOifPky0nLqQCJEwIg1rXOrjh1opaAAmoDp07RA7J4vssZMBpoqxgZFIweLSj5mMV3lW5dLyp%2BEeI1Jk%2BFnFL0kuL0NONgwgTconJEAmvWoYEAAh%2BQQFBAAAACwAAAAAEAAQAAcIzQABCAQQQMAAAgQGCAgwsGEBAwcQJEiAoByDAg0BLGCAoEGFChEiqLmTYcHACRQqHLDgYOI%2BfDbIZZgA4AKGjQoyAsAXD8K8CxM2cGCgU2CGDIiojNC1JkJRANG6GAuRghefBE9duGq3LMUvX1iLuhjmatkIPr7KPaXHypu1CXROCCr6R5SpUlQuJEIljIhOLloo%2BbsAYAKqR%2F3isAMFit2nK1YkPRsYiQulc2Jy5BBj5V%2BVVBnhfLLCT5y4VWA8tSpajRYQT9%2B%2BqBvSMCAAIfkECQQAAAAsAQABAA8ADwAHCJMAAQgcKLBDg3wEEwJw8AAAuQ4WFEqc04GDRII1AGTQgOGiwhATPAq0saeTyIEmfHw4CS3bnpWj5kjMOGyZPAA%2BtmVUCOjJslMk3DDDcWlnjRrcmElZBk1DnHMy2Nlb9KNJqDrnoJwCcAnHuVWrXsnAcgVAGEWxeACosY7WpCQAViUpZEXSDrUEf0z6wldRkzIEAwIAIfkEBQQAAAAsAAAAABAAEAAHCMsAAQgcSLAgwQIGDiBIkECNAwMRCi5ggKCBgwoPInRQY2HBwAkUKhyw4CDBBQcW5kTgMEEghokKDCrIoAHDBQAbODAwKDBDmxEtda2JyJPGsw8jAPDiA4ongAQnPszDMGpUU55lXoRI5MFEiTc8a0TD5iOEBRX9uF0yyOOQK3NUJOy6NWhcjRoDL3Fz9MjckUA4KK17xU6Tkx%2FsoPTr0%2BiUwEDnCvFb8gULljrnKKWLVfBcrn%2BFkvgJM0kRGR4G5Xj5ogjNGTMB8AoMCAA7") !important;
    opacity: 1.0 !important;
}

#navigator-throbber,
toolbar[iconsize="small"] #navigator-throbber,
toolbar[mode="text"]      #navigator-throbber {
    list-style-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAABGdBTUEAAK%2FINwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALJSURBVHjahFNdTJJRGD7f9%2FEjIcjnYkYmP02dmkJJMCAWXVnOaRvl5hq1uq2rbpqtC8fmjZdd5rzQtdwauWJd2EWNMeCidUMMYRkiytgCg8nPDEig53PVWM58t7Pz%2BzznPc%2FzHor8E%2BPj41KKoq5gqGMY5ix6fqPRSFQqlVhHR8eHxcXFZPN5qnkyNjY2otVq7xuNRpNGo2Hb2toEICOFQuHn9vZ20efzfUW%2F3NvbO%2B90OsschvkDtlgstxDOyclJK03TEoCZzc1NksvliFQqZcRisWhoaOi0QqG44Ha7Gw6H45PX660dEPT09NxEPMHt2kwmQ6%2BtrX2MxWLPotHow2QyOZ9Op7%2Ft7OywQqFQ0d3dLREIBDqPx0PjjJ%2BHVGVYnDKZTIP1ep0Eg8Hn09PTd5qfNjMz8xnd7O7u7ko%2Bn78%2BPDwsB7EDGr1gWJa9arPZ7uGt7Pr6urdard5AavVmAsy51jCbzat7e3vX5HK5AmBxKBTK0FBYWywWT2azWQLwS4izT44I7OVx1h2PxwmIBNDlEo13ddZqtdZAIMAJtkqOiVKp9C4SiRAQMSKRqJNXLperiURiH1bxufFxBNBJbLVaCcAULJXDMTqrVqvLSIfbt%2F4PDBEZmUxmVqlUpKWlpYELUzTSD2IvA38Jn8%2B3Q3HqKAJYLIQDt%2BEaUSqVdQi%2FxTGmwXweTpzDwiA8b7Xb7e855Ztjbm7uFNJ%2F3d%2Ffr5dIJMTlcpUh%2FGMGvh6kj2rTDAwMnIEr5o2NDS3GQrQcqo%2FV6XRTEG22r6%2FvMuqG%2BP3%2BEi5YXlhYeMrj2AFYgbdClO8DvV5%2FEWN7KpWyIzPC%2FQXMCQcEeW1paSkHG992dXU9OvSZRkdHR9rb2%2B8aDAYLNJGjyE5w68jyB0q5EA6Hv0C4NwC%2FQk0kDxFwMTExIUVnQxtEU%2F9eTqD%2BY3h7AOJ9B%2Fiv3b8EGADmHkdJ4SZcewAAAABJRU5ErkJggg%3D%3D") !important;
    opacity: 0.5;
}

TOP

nsIScriptSecurityManager で危険なURIを除外する

nsIScriptSecurityManager の checkLoadURI や checkLoadURIStr メソッドによって、ある URI のページからリンクされる別の URI がポリシーに沿ったものであるかどうかを判別することができる。
以下のサンプルは、現在のURI (sourceURI) に対して、リンク先のURI (targetURI) が javascript: や data: プロトコルで表された危険が潜む可能性のある URI であるかどうかをテストしている。

var sourceURI = "http://www.example.com/";
var targetURI = "javascript:alert('Blah');";

var SECMAN = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
             .getService(Components.interfaces.nsIScriptSecurityManager);
// disallow javascript: and data: protocols
const flags = Components.interfaces.nsIScriptSecurityManager.DISALLOW_SCRIPT_OR_DATA;
try {
    SECMAN.checkLoadURIStr(sourceURI, targetURI, flags);
    alert("SAFE URI: " + targetURI);
} catch (ex) {
    // if the URI is unsafe, threw NS_ERROR_DOM_BAD_URI
    alert("UNSAFE URI: " + targetURI);
}

Firefox 2 で備わったフィードプレビュー機能では、見かけ上 http: プロトコルのXMLデータを表示させているように見えても実際にロードされているデータはクロム権限で動作する以下のXHTMLである。

chrome://browser/content/feeds/subscribe.xhtml

したがって、フィードのパーマリンクに javascript: プロトコルによる危険な URI が潜んでいる場合、ユーザがフィードのエントリをクリックすることでそのスクリプトが発動してしまうことになり兼ねない。
そこで、フィードプレビューを生成する際、 FeedWriter クラスの _safeSetURIAttribute メソッドが上記のように nsIScriptSecurityManager を利用し、 危険な URI を a要素等のhref属性等にセットしない(つまりリンクしない)仕組みになっている。

TOP

開発中のアドオンのソースファイルへの上書きインストール問題

以下のような手順で開発中のアドオンのソースファイルを配備したとする。

1. ファイル「myapp@example.com」を作成
2. ファイルの内容を「c:xulmyapp」とする
3. ファイルをプロファイルフォルダextensions下へ配置
4. c:xulmypp に各種ソースファイルを配置して開発

ここで、誤って同一のem:idを有するアドオンをXPIファイルからインストールすると、「c:xulmyapp」内部が一度全削除され、myapp フォルダ下にXPIが展開して配備されてしまうということが Firefox 1.5 時代にあったように思う。

しかし、この問題は Firefox 2.0 へアップグレードする過程でいつの間にか治ったようだ。今では誤って同一のem:idを有するアドオンをXPIファイルからインストールしても「c:xulmyapp」内部は削除されず、普通に extensions フォルダ下にXPIファイルが展開され、通常の手順でアドオンをインストールした状態となる。

TOP

独自のプロトコルを追加する

以下のページで解説されている通りに JavaScript 製 XPCOM を登録してやることで、簡単に実現可能。
Adding a New Protocol to Mozilla

日本語訳
Latest topics > Firefoxで独自プロトコルを定義する方法 – outsider reflex

TOP

[userChrome.js] 新しいタブを現在のタブの右隣に開く

リンク先を新しいタブを開いたときに、最後尾ではなく現在のタブの右隣(連続して2つ開く場合はさらにその右隣)に開くための userChrome.js 用ユーザスクリプトである Tabs to the Right では、Firefox 本体で定義された gBrowser.addTab 関数と gBrowser.moveTabTo 関数の改造を以下のような方法で実現させている。

  1. 元の関数(つまり Function オブジェクト)を toString() で文字列化
  2. 関数内の改造したい部分の文字列を置換
  3. evalで文字列から関数を再定義する
eval(
  "gBrowser.moveTabTo = " + 
  gBrowser.moveTabTo.toString().replace(/{/, "$& if (aTab == this.mCurrentTab) this.__uc_addedTabs = 0;")
);

なるほどこれは面白いやり方だ。拡張機能によって Firefox 本体で定義された関数の動作の一部分だけを無理やり変更したいときには苦肉の策として有効である。

同じく Firefox 本体で定義された関数の動作に変更を加えたいケースで、元の関数の前後に何らかの処理を割り込ませたい場合は、以下のような手段が有効である。

  1. 元の関数を新しい関数としてコピー
  2. 元の関数を書き換え、その関数内で割り込ませる処理とともにコピーされた関数を呼び出して実行

たとえばブックマークを削除するときに確認ダイアログを表示させるようにしたければ、 BookmarksCommand.deleteBookmark 関数の前へ確認ダイアログを表示する処理を割り込ませる。

// 関数のコピー
BookmarksCommand.deleteBookmarkOriginal = BookmarksCommand.deleteBookmark;
// 関数の書き換え
BookmarksCommand.deleteBookmark = function(aSelection)
{
    // 確認ダイアログ表示
    if ( !window.confirm("Are you sure you wish to delete bookmarks?") ) return;
    // ブックマークを削除
    this.deleteBookmarksOriginal(aSelection);
};

この方法でいくと、先ほどの、新しいタブを現在のタブの右隣に開くための userChrome.js は、以下のようにも書くことができる。どちらが良いかは好みの問題であろう。

(function()
{
    getBrowser().__uc_addedTabs = 0;
    gBrowser.addTabOriginal    = gBrowser.addTab;
    gBrowser.moveTabToOriginal = gBrowser.moveTabTo;
    gBrowser.addTab = function(aURI, aReferrerURI, aCharset, aPostData, aOwner, aAllowThirdPartyFixup)
    {
        var oldTabPos = this.mCurrentTab._tPos;
        var t = this.addTabOriginal(aURI, aReferrerURI, aCharset, aPostData, aOwner, aAllowThirdPartyFixup);
        if ( aURI != "about:blank" ) {
            this.moveTabTo(t, oldTabPos + 1 + this.__uc_addedTabs++);
        }
        return t;
    };
    gBrowser.moveTabTo = function(aTab, aIndex)
    {
        if ( aTab == this.mCurrentTab ) {
            this.__uc_addedTabs = 0;
        }
        return this.moveTabToOriginal(aTab, aIndex);
    };
    gBrowser.mTabContainer.addEventListener("select", function() { gBrowser.__uc_addedTabs = 0; }, false);
})();

TOP