■シーモンキー(SeaMonkey)をカスタマイズ
みなさんは、シーモンキーをカスタマイズしてますか? ファイアーフォックスやサンダーバードとおなじく、シーモンキーだって、いろいろなカスタマイズが可能です。なんというか、カスタマイズのしがいがあるソフトですよね。
ここでは、シーモンキーの
- アドオン・完全テーマでのカスタマイズ
- 設定のカスタマイズ
- みためのカスタマイズ
- 動作のカスタマイズ
について、ざっくりと紹介していきましょう。
なお、みためや動作をカスタマイズするにあたっては、XUL(ズール=シーモンキーやファイアーフォックスなどのユーザーインターフェース記述言語)、CSS、JavaScriptの知識がある程度、必要です。このあたりはみなさん自身でなんとかしていってください。わたしは“みようみまね”レベルのユーザーにすぎませんから。
1. アドオン・完全テーマでのカスタマイズ
いちばんてがるなカスタマイズ方法は、設定をかえるアドオンや、みためをかえる完全テーマをつかうことでしょう。設定をかえるアドオンとしては「モンキーフィックス」(MonkeyFix)、みためをかえる完全テーマとしては「Firefox 3 theme for SeaMonkey」をあげておきましょう(ちなみに、どちらもおなじひと、ジェレミー・モートンさんがつくっています)。
◆モンキーフィックス(MonkeyFix)
モンキーフィックスは、「MonkeyFix :: Add-ons for SeaMonkey」から、インストールしてください。
再起動したら、メニューの[ツール]→[アドオンマネージャ]→[拡張機能]をえらんで、モンキーフィックスの「設定」ボタンをおしましょう。
「Configure source viewer」をおすと、外部のソースビューアーをえらべるようになります。
ほかには、
- Popup element attributes……ポップアップ表示させる属性について
- Tab behaviour……タブバーやタブの動作について
- Toolbar tweaks……ツールバー、アドレスバー、検索バー、ページ内検索バーについて
- Update behaviour……ソフトウェアの更新について
- Advanced / developers tweaks……高度な設定(画像のリサイズ、検索語の候補表示など)
といった設定が可能です。これくらいの英語ならだいじょうぶ、というひとはつかってみてください。
なお、設定画面はたてにながいので、ひょっとしたら、下がきれるかもしれません。そういう場合は、[Tab]や[Shift]+[Tab]でフォーカスを移動してください。いちばんうえの「About」にフォーカスがある状態で[Shift]+[Tab]を2回おすと、「Apply」ボタンにフォーカスが移動します。ここで[Enter]をおすと、設定が適用されます。
◆Firefox 3 theme for SeaMonkey
かずすくないシーモンキー用完全テーマの1つ、Firefox 3 theme for SeaMonkeyは「Firefox 3 theme for SeaMonkey :: Add-ons for SeaMonkey」から、インストールしてください。
再起動すると、かつてのファイアーフォックスユーザーにはなつかしい(?)みためになりました。もっとも、ブラウザー以外のみためについてはあまりかわってないのが、残念なところですね(まあ、だからこそ「Firefox 3 theme〜」というなまえなんでしょう)。
てきとうな完全テーマをベースにして、あとはユーザースタイルを駆使してカスタマイズする、というやりかたもあるでしょう。実際にわたしは、このFirefox 3 theme for SeaMonkeyを、カスタマイズのベースにしています。クラシック表示ということもあって、まあ、ふるくさいみためですね。
2. 設定のカスタマイズ
シーモンキーは、メニューの[編集]→[設定]からたくさんの項目を設定できます。でも、「about:config」の設定エディターで設定したいこともあるでしょう。設定エディターをつかうような設定項目は、あらかじめ「user.js」にまとめておくと便利です。
◆user.jsファイルをつくる
てきとうなテキストエディターで、ファイルのなまえを「user.js」、文字コードを「BOMなしUTF-8」にして、プロファイルフォルダーに保存します。かきこむなかみは、こんな感じ。
/* 設定ファイル */ //user_pref("設定名", 値);
「/* 〜 */」の部分と「//」の行はコメントです。「/* 〜 */」は複数行を、「//」は1行だけをコメントにします。コメント部分は設定に影響しません。各種の設定は「user_pref("設定名", 値);」という書式でかいていくことになります。
user.jsにかいた設定は、シーモンキーによみこまれて、おなじプロファイルフォルダーの「prefs.js」というファイルにかきこまれます。user.jsの設定をデフォルト値にもどしたいときは、つぎのようにしてください。
- シーモンキーを終了する
- user.jsをテキストエディターでひらいて、もどしたい設定をデフォルト値にかきかえる
- シーモンキーを立ち上げて、終了する(この段階で、もどしたい設定はprefs.jsから削除される)
- user.jsをテキストエディターでひらいて、もどしたい設定をコメントにするか、削除する
念のため「about:config」で設定エディターをひらいて、もとにもどっているかどうか、確認するといいでしょう。
◆user.jsの例
わたしのuser.jsは、いまのところ、以下のようになっています。ファイアーフォックス用のuser.jsにくらべると、設定項目はずいぶんすくなくなりました。
//------------------------------------------------------------------- // タブ //------------------------------------------------------------------- /* 検索バーからの検索結果 true: 新しいタブで開く false: 現在のタブで開く (デフォルト) */ user_pref("browser.search.openintab", true); /* 最後のタブを閉じたとき true: ウィンドウを閉じる (デフォルト) false: ウィンドウを閉じない */ user_pref("browser.tabs.closeWindowWithLastTab", false); /* タブのコンテキストメニューで「他のタブを閉じる」をえらんだとき true: 警告する (デフォルト) false: 警告しない */ user_pref("browser.tabs.warnOnCloseOther", false); /* タブをたくさん開いたときに true: 警告する (デフォルト) false: 警告しない */ user_pref("browser.tabs.warnOnOpen", false); //------------------------------------------------------------------- // プライバシー・セキュリティ関連 //------------------------------------------------------------------- /* 位置情報通知機能 true: 有効 (デフォルト) false: 無効 */ user_pref("geo.enabled", false); //------------------------------------------------------------------- // いろいろ //------------------------------------------------------------------- /* 署名のうえのくぎりマーク true: つけない false: つける (デフォルト) */ user_pref("mail.identity.default.suppress_signature_separator", true); /* 受信メールの引用部分の記号 true: | (デフォルト) false: > */ user_pref("mail.quoted_graphical", false); /* タスクバーのシーモンキーアイコンに表示される項目 true: ひらいているタブ+ひらいているウィンドウ (デフォルト) false: ひらいているウィンドウ */ user_pref("browser.taskbar.previews.enable", false); /* 検索バーにフォーカスがあるときの検索エンジン名 true: 表示する (デフォルト) false: 表示しない */ user_pref("dom.placeholder.show_on_focus", false); /* たてキースクロールの行数 3: (デフォルト) */ user_pref("toolkit.scrollbox.verticalScrollDistance", 6); /* http通信の最大接続数 256: (デフォルト) */ user_pref("network.http.max-connections", 48);
3. みためのカスタマイズ
ここでいう「みため」は
- シーモンキーのみため
- シーモンキーで表示しているページのみため
を意味しています。どちらのみためも、「ユーザースタイルシート」をつかってカスタマイズします。ユーザースタイルシートは、「スタイリッシュ」(Stylish)というアドオンで管理するといいでしょう。
◆スタイリッシュ(Stylish)をつかう
スタイリッシュは、「Stylish :: Add-ons for SeaMonkey」から、インストールしてください。
再起動したら、メニューの[ツール]→[アドオンマネージャ]→[ユーザースタイル]をえらびます。「新しいスタイルを書く」ボタンをおすと、ユーザースタイルシートをかくことができます。
【シーモンキーのみためをカスタマイズする】
「新しいスタイル」の「挿入」ボタンをおして、「XUL名前空間を標準とする」をえらびます。「@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);」という文字が挿入されました。これは、シーモンキーのみために関する記述だという意味。このあとに、実際のスタイルをかいていきます。
/* ステータスバーのアドレス帳アイコンを表示しない */ #mini-addr { visibility: collapse !important; }
たとえばこんなふうにかいて、「お試し」ボタンをおすと……ステータスバーのアドレス帳アイコンがきえましたね。
「#mini-addr」がアドレス帳アイコンをあらわす「id」です。こういったインターフェースの要素をさがすには、シーモンキーに最初からはいっているアドオン「DOM Inspector」をつかいます。メニューの[ツール]→[Web開発]→[DOM Inspector]をえらんで、たちあげてください。
要素をさがす手順としては、こんな感じですね。
- [File]→[Inspect Chrome Document]から、しらべたいソフト(ブラウザー、メールソフト……のページ)をえらぶ
- 「Inspect」ボタンをおす(下側に、しらべたいソフトが表示される)
- ツールバーの左端のボタンをおしてから、かえたい部分をクリックする
- 「id」が表示される
- 「Object - DOM Node」をクリックして、メニューの「CSS Rules」をえらぶと、スタイルの内容が表示される
DOM Inspectorのつかいかたなどについては、「DOM Inspector | MDN」をどうぞ。
【シーモンキーで表示しているページのみためをカスタマイズする】
「新しいスタイル」の「挿入」ボタンをおして、「HTML名前空間を標準とする」をえらびます。「@namespace url(http://www.w3.org/1999/xhtml);」という文字列が挿入されました。これは、シーモンキーで表示しているページのみために関する記述だという意味。このあとに、実際のスタイルをかいていきます。
/* クルミノ コーボーの背景色をかえる */ @-moz-document url-prefix(http://homepage1.nifty.com/akshiba/) { body { background-color: #000000 !important; } }
たとえばこんなふうにかいて、「お試し」ボタンをおすと……このサイトの背景色がかわりましたね。
「@-moz-document」には、つぎのような指定がつかえます。
- @-moz-document url(〜)……URL指定(指定したURLのページだけ)
- @-moz-document url-prefix(〜)……URL先頭一致指定(指定したURLを先頭にふくむすべてのページ)
- @-moz-document domain(〜)……ドメイン指定(指定したドメインをふくむすべてのページ)
「@-moz-document url-prefix(http://homepage1.nifty.com/akshiba/)」で、このサイトのページすべてについて指定しているわけです。
「background-color」などのかえたい要素については、やはり、DOM Inspectorをつかってさがすといいでしょう。手順としては、こんな感じですね。
- [File]→[Inspect Content Document]から、しらべたいページをえらぶ
- 「Inspect」ボタンをおす(下側に、しらべたいページが表示される)
- ツールバーの左端のボタンをおしてから、かえたい部分をクリックする
- 「Object - DOM Node」をクリックして、メニューの「CSS Rules」をえらぶ
- 要素名をクリックすると、スタイルの内容が表示される
◆ユーザースタイルをさがす
「userstyles.org」でさがすといいでしょう。userstyles.orgでは、スタイリッシュ経由でユーザースタイルシートをインストールできます。つまり「お試し」ができるので、便利なんですよね。
シーモンキーでも基本的に、ファイアーフォックス用やサンダーバード用のユーザースタイルシートがつかえますから、いろいろとためしてみてください。もしうまくいかなかったら、DOM Inspectorでしらべてみるようにしましょう。
◆ユーザースタイルをつくる
とりあえず、自作の(といっても、基本はきりばりですが)ユーザースタイルシートをあげておきます。てきとうにおつかいください。
- 読み込み中に一瞬表示される画面のいろを配色設定の背景色にあわせる
/* ウィンドウズのテーマ表示をしているときだけ必要 */ /* いろの指定はおこのみで */ @media (-moz-windows-default-theme) { notificationbox { background-color: #d0d0d0 !important; } }
- ページ内検索バーを下に配置する
#FindToolbar { border-top: 1px solid !important; border-bottom: 0px !important; -moz-box-ordinal-group: 10 !important; } /* ソース表示ウィンドウにはこれが必要 */ #appcontent { -moz-box-direction: normal !important; }
- 多段タブにする
/* 多段タブ */ /* ドラッグ&ドロップによるタブの移動は1段目だけ */ /* ドラッグ&ドロップしたい場合は「DragAndDropTabOnMultiRowsOfTabs.uc.js」が必要 */ /* 段数制限なし */ .tabbrowser-arrowscrollbox scrollbox { overflow: visible !important; } .tabbrowser-arrowscrollbox scrollbox > box { display: block !important; } .tabbrowser-tabs .tabbrowser-tab { vertical-align: top !important; -moz-box-sizing: border-box !important; } .tabbrowser-tab { width: 250px !important; height: 29px !important; } .tabbrowser-tab[selected="true"] { height: 32px !important; }
- 受信メールの行間をあける(HTML名前空間を標準とする)
@namespace url(http://www.w3.org/1999/xhtml); .moz-text-plain { line-height: 1.5em !important; }
- メッセージ作成画面の引用部分の文字色をかえる(HTML名前空間を標準とする)
@namespace url(http://www.w3.org/1999/xhtml); /* #000000で黒になる */ span[_moz_quote=true] { color: #c0c0c0 !important; }
4. 動作のカスタマイズ
ここでいう「動作」は
- シーモンキーの動作
- シーモンキーで表示しているページの動作
を意味しています。どちらの動作も、「ユーザースクリプト」をつかってカスタマイズします。
シーモンキーの動作にかかわるユーザースクリプトは、「ユーザークロームJS」(userChromeJS)というアドオンをつかってうごかします。
シーモンキーで表示しているページの動作にかかわるユーザースクリプトは、ユーザークロームJS用スクリプト「UserScriptLoader.uc.js」をつかってうごかします。
◆ユーザークロームJSをつかえるようにする
ユーザークロームJSは、「mozdev.org - userchromejs」から、インストールしてください。シーモンキーにも対応しているアドオンです。
ユーザークロームJSをインストールすると、プロファイルフォルダーに「chrome」フォルダーがつくられます。そしてchromeフォルダーに「userChrome.js」というファイルがつくられます。
このuserChrome.jsにスクリプトをずらずらとかきこんでいく……というのが本来のつかいかた。でもここでは、本来のつかいかたはしません。スクリプトが管理しづらくなるからです。したがってuserChrome.jsをべつのなまえ、たとえば「userChrome-example.js」などにかえておいてください。
【「userChrome.js」「000-windowhook.uc.js」「rebuild_userChrome.uc.xul」をコピー】
1スクリプト=1ファイルというかたちでスクリプトを管理するには、以下の3つのファイルが必要です。
- userChrome.js(本来のuserChrome.jsをおきかえるもの)
- 000-windowhook.uc.js
- rebuild_userChrome.uc.xul
これらはいずれも、「Alice0775」さんがつくっているユーザークロームJS用スクリプト。「alice0775/userChrome.js」へいって、「Download ZIP」ボタンをおしましょう。Alice0775さんのスクリプトが一括でダウンロードできます。
ダウンロードしたファイルは、「Alice0775.zip」などとリネームしてください。てきとうなフォルダーに解凍して、上記の3つのファイルをchromeフォルダーにコピーします。
以後、ユーザークロームJS用のスクリプトはchromeフォルダーにおいてつかうことになります。
Alice0775さんのuserChrome.jsは、2014年12月13日のバージョン以降、「userchrome.js-0.8.014121301-Fx31.xpi」が必要ということになっています。このxpiをつくるためのファイルは、Alice0775さんのサイトからダウンロードしたファイルのなかの「userchrome.js.xpi」フォルダーにはいっています。
xpiファイルは、以下のような手順でつくります。
・「components」フォルダーと、「chrome.manifest」「install.rdf」ファイルをひとまとめにしてzip形式で圧縮する
・圧縮したファイルの拡張子を「.xpi」に変更する
「mozdev.org - userchromejs」からインストールした「userChromeJS」を無効にしてから、作成したxpiファイルをシーモンキーのウィンドウにドラッグ&ドロップして、インストールしてください。
もっとも、もとの「userChromeJS」のままでも、問題なくうごくスクリプトもあります。このあたり、実際にためしてみてください。
【「UserScriptLoader.uc.js」をコピー】
表示しているページの動作にかかわるスクリプトをうごかすには、以下のファイルが必要です。
- UserScriptLoader.uc.js
ダウンロードしたzipファイルは、「Griever.zip」などとリネームしてください。てきとうなフォルダーに解凍して、上記のファイルをchromeフォルダーにコピーします。
コピーしたら、chromeフォルダーに「UserScriptLoader」フォルダーをつくってください。UserScriptLoader.uc.js用のスクリプトは、UserScriptLoaderフォルダーにおいてつかいます。
【シーモンキー用にかきかえる】
Alice0775さんの「userChrome.js」は、1カ所だけ、かきかえが必要です。以下のようにしてください。
//var BROWSERCHROME = "chrome://browser/content/browser.xul"; //Firfox var BROWSERCHROME = "chrome://navigator/content/navigator.xul"; //SeaMonkey:
「chrome://navigator/content/navigator.xul」は、シーモンキーのインターフェースを記述したファイル。これを指定しないと、ユーザークロームJS用のスクリプトはうごかないんですね。
ですから、ユーザークロームJS用スクリプトで「// @include chrome://browser/content/browser.xul」などとあったら、「// @include chrome://navigator/content/navigator.xul」とかきかえてください。
あるいは、こんなふうにしてもいいでしょう。
// @include main
「main」としておけば、Alice0775さんのuserChrome.jsで「chrome://navigator/content/navigator.xul」におきかえてくれます。
*
ここまでの作業が終わったら、シーモンキーを再起動しましょう。
ユーザークロームJSと、Alice0775さんのuserChrome.jsなどが導入されていれば、メニューの[ツール]はこんなふうになります。また、GrieverさんのUserScriptLoader.uc.jsが導入されていれば、アドレスバーの右端にかみなりマークが表示されます。
◆ユーザークロームJS用スクリプトをつかってみる
【スクリプトをさがす】
ユーザークロームJS用スクリプトをさがすなら、まとめサイト「userChrome.js用スクリプト - wiki@nothing」が便利でしょう。さまざまなスクリプトが配布サイトごとにまとめられています。
【スクリプトのインストール・アンインストール】
スクリプトのファイルをchromeフォルダーに移動してください。シーモンキーをたちあげなおすと、そのスクリプトがつかえるようになります。
つかわなくなったスクリプトは、シーモンキーを終了してから、削除してください。
【スクリプトのかきかえ】
スクリプトは、テキストエディターなどで、かならずなかみをみておきましょう。先頭部分に、そのスクリプトについての説明がかいてあったりします。また、設定を自分でかきこまなくてはならないスクリプトもあります。
さらに、シーモンキー用に、かきかえが必要なスクリプトもあります。「// @include」部分だけならたいした手間じゃないんですが、シーモンキーとファイアーフォックスとでは、メニューのid、コマンドのなまえ……などに微妙なちがいがあるからです。
スクリプトの作者が、かならずしもシーモンキーをつかっているとはかぎりませんから、
【スクリプトをつくる】
スクリプトは、文字コード「BOMなしUTF-8」のテキストファイルです。てきとうなテキストエディターで、ファイル名を「〜.uc.js」(なかみによっては「〜.uc.xul」)として保存すればいいでしょう。
スクリプトをつくるには、けっきょくのところ、XULやJavaScriptの知識が必要になります。すでにあるスクリプトをみながら、あれこれ試行錯誤していくしかないでしょう。
とりあえず、自作のスクリプト(といっても、基本はきりばりですが)をあげておきます。どれもシーモンキー専用です。てきとうにおつかいください。最初にかいたように、わたし自身は“みようみまね”レベルのユーザーにすぎないので、この程度のものをつくるのがやっと。うまくうごかないことがあるかもしれませんね(^^;。
- ダウンロード終了時にダウンロードマネジャーをとじる(「browser.download.manager.closeWhenDone」がtrueの場合だけ)
// ==UserScript== // @name CloseDownloadManagerWhenDone.uc.js // @version 1.0.0.0 // @description ダウンロード終了時にダウンロードマネジャーをとじる // @author あなたのなまえ // @namespace // @include main // @compatibility SeaMonkey 2.26+ // @note 「browser.download.manager.closeWhenDone」がtrueの場合だけ // ==/UserScript== (function() { const PREF_BDM_CLOSEWHENDONE = "browser.download.manager.closeWhenDone"; const DOWNLOAD_NOTSTARTED = Components.interfaces.nsIDownloadManager.DOWNLOAD_NOTSTARTED; const DOWNLOAD_QUEUED = Components.interfaces.nsIDownloadManager.DOWNLOAD_QUEUED; const DOWNLOAD_DOWNLOADING = Components.interfaces.nsIDownloadManager.DOWNLOAD_DOWNLOADING; const DOWNLOAD_FINISHED = Components.interfaces.nsIDownloadManager.DOWNLOAD_FINISHED; const DOWNLOAD_PAUSED = Components.interfaces.nsIDownloadManager.DOWNLOAD_PAUSED; const DOWNLOAD_SCANNING = Components.interfaces.nsIDownloadManager.DOWNLOAD_SCANNING; const DOWNLOAD_FAILED = Components.interfaces.nsIDownloadManager.DOWNLOAD_FAILED; const DOWNLOAD_CANCELED = Components.interfaces.nsIDownloadManager.DOWNLOAD_CANCELED; const DOWNLOAD_BLOCKED_PARENTAL = Components.interfaces.nsIDownloadManager.DOWNLOAD_BLOCKED_PARENTAL; const DOWNLOAD_DIRTY = Components.interfaces.nsIDownloadManager.DOWNLOAD_DIRTY; const DOWNLOAD_BLOCKED_POLICY = Components.interfaces.nsIDownloadManager.DOWNLOAD_BLOCKED_POLICY; var aDownloadManager = Components.classes["@mozilla.org/download-manager;1"].getService(Components.interfaces.nsIDownloadManager); function getDownloadManagerWindow() { var aWindowMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator); var enumerator = aWindowMediator.getEnumerator("Download:Manager"); while(enumerator.hasMoreElements()) { var aWindow = enumerator.getNext(); return aWindow; } } function closeDownloadManagerWindow() { var aPrefBranch = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch); var closeWhenDone = aPrefBranch.getBoolPref(PREF_BDM_CLOSEWHENDONE); var aWindow = getDownloadManagerWindow(); if (closeWhenDone) { if (typeof aWindow != "undefined") { aWindow.close(); } } } aDownloadManager.addListener({ onSecurityChange: function(aWebProgress, aRequest, aState, aDownload) { }, onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus, aDownload) { }, onDownloadStateChange: function(aState, aDownload) { switch(aDownload.state) { case DOWNLOAD_NOTSTARTED: case DOWNLOAD_QUEUED: case DOWNLOAD_DOWNLOADING: case DOWNLOAD_FINISHED: if (aDownloadManager.activeDownloadCount == 0) { closeDownloadManagerWindow(); } break; case DOWNLOAD_PAUSED: case DOWNLOAD_SCANNING: case DOWNLOAD_FAILED: case DOWNLOAD_CANCELED: case DOWNLOAD_BLOCKED_PARENTAL: case DOWNLOAD_DIRTY: case DOWNLOAD_BLOCKED_POLICY: } }, onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress, aMaxSelfProgress, aCurTotalProgress, aMaxTotalProgress, aDownload) { } }); })();
- ミドルクリックで閉じたタブを開く、ダブルクリックで新しいタブを開く・現在のタブを再読み込みする
// ==UserScript== // @name MouseClickOperation.uc.js // @version 1.1.0.0 // @description マウスクリック関連 // @author あなたのなまえ // @namespace // @include main // @compatibility SeaMonkey 2.26+ // @note ミドルクリックで閉じたタブを開く、タブバー上のダブルクリックで新しいタブを開く・タブ上のダブルクリックで現在のタブを再読み込みする // ==/UserScript== (function() { var mouseClickOperation = { leftDoubleClick: function(aEvent) { if (aEvent.button == 0) { var aTab = aEvent.target; // タブバー上 if (aTab.localName == "tabs") { BrowserOpenTab(); aEvent.preventDefault(); aEvent.stopPropagation(); // タブ上 } else { gBrowser.reloadTab(gBrowser.mCurrentTab); aEvent.preventDefault(); aEvent.stopPropagation(); } } }, middleClick: function(aEvent) { if (aEvent.button == 1) { var aTab = aEvent.target; // タブバー上 if (aTab.localName == "tabs") { gBrowser.undoCloseTab(); aEvent.preventDefault(); aEvent.stopPropagation(); } } }, } gBrowser.tabContainer.addEventListener("dblclick", mouseClickOperation.leftDoubleClick, true); gBrowser.tabContainer.addEventListener("click", mouseClickOperation.middleClick, true); })();
- 空白タブを「新しいタブ」にリネームする(「タイトル“無し”」というのはね……。なんとかならないんですかね)
// ==UserScript== // @name RenameBlankTab.uc.js // @version 1.4.0.0 // @description 空白タブを「新しいタブ」にリネームする // @author あなたのなまえ // @namespace // @include main // @compatibility SeaMonkey 2.26+ // @note // ==/UserScript== (function() { var unicodeConverter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); unicodeConverter.charset = "UTF-8"; var renameBlankTab = { init: function() { setTimeout(function() { var index; for (index = 0; index < gBrowser.tabs.length; index++) { var aBrowser = gBrowser.getBrowserForTab(gBrowser.tabs[index]); renameBlankTab.forceRenameBlankTab(aBrowser); } }, 1500); gBrowser.tabContainer.addEventListener("TabOpen", renameBlankTab.renameAddedTab, false); gBrowser.tabContainer.addEventListener("TabAttrModified", renameBlankTab.renameAttrModifiedTab, false); var aAppcontent = document.getElementById("appcontent"); aAppcontent.addEventListener("DOMContentLoaded", renameBlankTab.renameLoadedTab, true); }, renameAddedTab: function(aEvent) { var aBrowser = gBrowser.getBrowserForTab(aEvent.target); aBrowser.addEventListener("load", function() { renameBlankTab.forceRenameBlankTab(aBrowser); }, true); }, renameAttrModifiedTab: function(aEvent) { var aBrowser = gBrowser.getBrowserForTab(aEvent.target); renameBlankTab.forceRenameBlankTab(aBrowser); }, renameLoadedTab: function(aEvent) { var isFrame = (aEvent.target instanceof Components.interfaces.nsIDOMHTMLDocument && aEvent.target != gBrowser.contentDocument); if (isFrame) { return; } var aBrowser = gBrowser.getBrowserForTab(gBrowser.mCurrentTab); renameBlankTab.forceRenameBlankTab(aBrowser); }, forceRenameBlankTab: function(aBrowser) { var aLabel = unicodeConverter.ConvertToUnicode("新しいタブ"); if ((aBrowser.contentDocument.title == "") && (aBrowser.contentDocument.location.href == "about:blank")) { aBrowser.contentDocument.title = aLabel; } } } renameBlankTab.init(); })();
- タブのコンテキストメニューにメニューを追加
// ==UserScript== // @name AddTabMenus.uc.js // @version 1.1.0.0 // @description タブのコンテキストメニューにメニューを追加 // @author あなたのなまえ // @namespace // @include main // @compatibility SeaMonkey 2.26+ // @note タブのコンテキストメニューに[右側のタブをすべて閉じる][最近閉じたタブ][最近閉じたタブをクリア][最近閉じたウィンドウ][最近閉じたウィンドウをクリア]を追加 // ==/UserScript== (function() { var unicodeConverter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); unicodeConverter.charset = "UTF-8"; var ss = Components.classes["@mozilla.org/suite/sessionstore;1"].getService(Components.interfaces.nsISessionStore); var aTabContextMenu = document.getAnonymousElementByAttribute(gBrowser, "anonid", "tabContextMenu"); var aCurrentIndex, aTabCount; var addTabMenus = { init: function() { addTabMenus.addCloseTabsToTheEnd(); addTabMenus.addRecentTabs(); addTabMenus.addRecentWindows(); aTabContextMenu.addEventListener("popupshowing", addTabMenus.adjustMenuDisplay, false); }, getCurrentTabIndex: function() { var aTab; // タブバーの上"tabs" タブの上"tab" if (gBrowser.mContextTab.localName != "tab") { aTab = gBrowser.mCurrentTab; // 選択されたタブ } else { aTab = gBrowser.mContextTab; // クリックされたタブ } return gBrowser.getTabIndex(aTab); }, isLastTab: function(aIndex, aCount) { if (aIndex == aCount - 1) { return true; } else { return false; } }, adjustMenuDisplay: function(aEvent) { // コンテキストメニューがポップアップしたとき if (aEvent.target == aEvent.currentTarget) { var aItem, aBoolStr; // Close Tabs To The End aCurrentIndex = addTabMenus.getCurrentTabIndex(); aTabCount = gBrowser.tabs.length; aItem = document.getElementById("menu_closeTabsToTheEnd"); aBoolStr = addTabMenus.isLastTab(aCurrentIndex, aTabCount).toString(); aItem.setAttribute("disabled", aBoolStr); // Recently Closed Tabs aBoolStr = (ss.getClosedTabCount(window) == 0).toString(); aItem = document.getElementById("menu_recentTabs2"); aItem.setAttribute("disabled", aBoolStr); aItem = document.getElementById("menu_clearRecentTabs"); aItem.setAttribute("disabled", aBoolStr); // Recently Closed Windows aBoolStr = (ss.getClosedWindowCount() == 0).toString(); aItem = document.getElementById("menu_recentWindows2"); aItem.setAttribute("disabled", aBoolStr); aItem = document.getElementById("menu_clearRecentWindows"); aItem.setAttribute("disabled", aBoolStr); } }, addCloseTabsToTheEnd: function() { var aLabel = unicodeConverter.ConvertToUnicode("右側のタブをすべて閉じる"); var aItem = document.createElement("menuitem"); aItem.setAttribute("id", "menu_closeTabsToTheEnd"); aItem.setAttribute("label", aLabel); aItem.setAttribute("accesskey","I"); aItem.addEventListener("command", function() { var index = aTabCount - 1; while (index > aCurrentIndex) { gBrowser.removeTab(gBrowser.tabs[index]); index = index - 1; } }, false); // idなしの最初のセパレータを取得 var aNodes = aTabContextMenu.childNodes; var index, tempIndex; for (index = 0; index < aNodes.length; index++) { if ((aNodes[index].id == "") && (aNodes[index].label == "")) { tempIndex = index; break; } } aTabContextMenu.insertBefore(aItem, aNodes[tempIndex]); }, addRecentTabs: function() { var aLabel = unicodeConverter.ConvertToUnicode("最近閉じたタブをクリア"); var aItem; aItem = document.createElement("menuseparator"); aItem.setAttribute("id", "atmSep1"); aTabContextMenu.appendChild(aItem); var orgItem = document.getElementById("menu_recentTabs"); aItem = orgItem.cloneNode(true); aItem.setAttribute("id", "menu_recentTabs2"); aItem.setAttribute("accesskey", "T"); aTabContextMenu.appendChild(aItem); aItem = document.createElement("menuitem"); aItem.setAttribute("id", "menu_clearRecentTabs"); aItem.setAttribute("label", aLabel); aItem.addEventListener("command", function() { var aCount = ss.getClosedTabCount(window); while (aCount > 0) { ss.forgetClosedTab(window, 0); aCount--; } }, false); aTabContextMenu.appendChild(aItem); }, addRecentWindows: function() { var aLabel = unicodeConverter.ConvertToUnicode("最近閉じたウィンドウをクリア"); var aItem; aItem = document.createElement("menuseparator"); aItem.setAttribute("id", "atmSep2"); aTabContextMenu.appendChild(aItem); var orgItem = document.getElementById("menu_recentWindows"); aItem = orgItem.cloneNode(true); aItem.setAttribute("id", "menu_recentWindows2"); aTabContextMenu.appendChild(aItem); aItem = document.createElement("menuitem"); aItem.setAttribute("id", "menu_clearRecentWindows"); aItem.setAttribute("label", aLabel); aItem.addEventListener("command", function() { // https://github.com/Infocatcher/Custom_Buttons/blob/master/Undo_Close_Tabs/undoCloseTabs.js ss.setWindowState(window, '{"windows":[{}],"_closedWindows":[]}', false); /* var aCount = ss.getClosedWindowCount(); while (aCount > 0) { // SeaMonkeyのnsSessionStore.jsには定義されてない ss.forgetClosedWindow(0); aCount--; } */ }, false); aTabContextMenu.appendChild(aItem); } } addTabMenus.init(); })();
- 多段タブでタブをドラッグ&ドロップする(まえのほうであげた多段タブにするユーザースタイルシートを導入してください)
// ==UserScript== // @name DragAndDropTabOnMultiRowsOfTabs.uc.js // @version 1.0.0.0 // @description 多段タブでタブをドラッグ&ドロップする // @author あなたのなまえ // @namespace // @include main // @compatibility SeaMonkey 2.26+ // @note zzzz-removeTabMoveAnimation.uc.js(Alice0775)を参考にして // @note Firefox・SeaMonkeyのtabbrowser.xmlからきりばり // @note 多段タブにするユーザースタイルはStylishで // ==/UserScript== (function() { // fx20 tabbrowser.xml function getDragTargetTab(aEvent) { var aTab; if (aEvent.target.localName == "tab") { aTab = aEvent.target; } else { aTab = null; } if (aTab && (aEvent.type == "drop" || aEvent.type == "dragover") && aEvent.dataTransfer.dropEffect == "link") { let aBoxObject = aTab.boxObject; if (aEvent.screenX < aBoxObject.screenX + aBoxObject.width * .25 || aEvent.screenX > aBoxObject.screenX + aBoxObject.width * .75) return null; } return aTab; } // fx20 tabbrowser.xml function getDropIndex2(aEvent) { var tabs = gBrowser.tabs; var aTab = getDragTargetTab(aEvent); if (window.getComputedStyle(gBrowser, null).direction == "ltr") { for (let i = aTab ? gBrowser.getTabIndex(aTab) : 0; i < tabs.length; i++) //for (i; i < tabs.length; i++) if (aEvent.screenX < tabs[i].boxObject.screenX + tabs[i].boxObject.width / 2) return i; } else { for (let i = aTab ? gBrowser.getTabIndex(aTab) : 0; i < tabs.length; i++) //for (i; i < tabs.length; i++) if (aEvent.screenX > tabs[i].boxObject.screenX + tabs[i].boxObject.width / 2) return i; } return tabs.length; } // SM2.26 tabbrowser.xml gBrowser.tabContainer._onDragOver = function(aEvent) { aEvent.preventDefault(); aEvent.stopPropagation(); var ib = document.getAnonymousElementByAttribute(gBrowser, "class", "tab-drop-indicator-bar"); // autoscroll the tab strip if we drag over the scroll buttons, // even if we aren't dragging a tab var pixelsToScroll = 0; var tabStrip = gBrowser.mTabContainer.mTabstrip; var ltr = window.getComputedStyle(gBrowser, null).direction == "ltr"; if (gBrowser.mTabContainer.getAttribute("overflow") == "true") { var targetAnonid = aEvent.originalTarget.getAttribute("anonid"); switch (targetAnonid) { case "scrollbutton-up": pixelsToScroll = -tabStrip.scrollIncrement; break; case "scrollbutton-down": case "alltabs-button": pixelsToScroll = tabStrip.scrollIncrement; break; } if (pixelsToScroll) tabStrip.scrollByPixels((ltr ? 1 : -1) * pixelsToScroll); } var ind = document.getAnonymousElementByAttribute(gBrowser, "class", "tab-drop-indicator"); var draggedTab = aEvent.dataTransfer.mozSourceNode; var within = draggedTab && draggedTab.parentNode == gBrowser.tabContainer; var newIndexOn = within ? -1 : gBrowser.getDropOnIndex(aEvent); var ltr = window.getComputedStyle(gBrowser, null).direction == "ltr"; //● //var arrowX, tabBoxObject; var arrowX, arrowY, tabBoxObject; if (newIndexOn != -1) { tabBoxObject = gBrowser.tabs[newIndexOn].boxObject; arrowX = tabBoxObject.screenX + tabBoxObject.width / 2; arrowY = tabBoxObject.screenY; } else { //● //var newIndexBetween = gBrowser.getDropIndex(aEvent); var newIndexBetween = getDropIndex2(aEvent); if (within) { var tabIndex = gBrowser.getTabIndex(draggedTab); if (newIndexBetween == tabIndex || newIndexBetween == tabIndex + 1) { ib.collapsed = true; return; } } if (newIndexBetween == gBrowser.tabs.length) { tabBoxObject = gBrowser.tabs[gBrowser.tabs.length - 1].boxObject; arrowX = tabBoxObject.x; arrowX = tabBoxObject.screenX; arrowY = tabBoxObject.screenY; if (ltr) // for LTR "after" is on the right-hand side of the tab arrowX += tabBoxObject.width; } else { tabBoxObject = gBrowser.tabs[newIndexBetween].boxObject; arrowX = tabBoxObject.screenX; arrowY = tabBoxObject.screenY; if (!ltr) // for RTL "before" is on the right-hand side of the tab arrowX += tabBoxObject.width; } } var boxObject = tabStrip.scrollBoxObject; // Check pixelsToScroll as well to prevent noticable judder. if (pixelsToScroll > 0 || arrowX >= boxObject.screenX + boxObject.width) arrowX = boxObject.screenX + boxObject.width; else if (pixelsToScroll < 0 || arrowX < boxObject.screenX) arrowX = boxObject.screenX; if (ltr) { //● //ind.style.marginLeft = (arrowX - gBrowser.boxObject.screenX) + "px"; ind.style.transform = "translate(" + (arrowX - gBrowser.boxObject.screenX) + "px, " + (arrowY - gBrowser.boxObject.screenY) + "px)"; } else { //● //ind.style.marginRight = (gBrowser.boxObject.screenX + gBrowser.boxObject.width - arrowX) + "px"; ind.style.transform = "translate(" + (gBrowser.boxObject.screenX + gBrowser.boxObject.width - arrowX) + "px, " + (arrowY - gBrowser.boxObject.screenY) + "px)"; } ib.collapsed = false; } gBrowser.tabContainer.addEventListener("dragover", gBrowser.tabContainer._onDragOver, true); // SM2.26 tabbrowser.xml gBrowser.tabContainer._onDrop = function(aEvent) { document.getAnonymousElementByAttribute(gBrowser, "class", "tab-drop-indicator-bar") .collapsed = true; aEvent.stopPropagation(); //● //var newIndex = gBrowser.getDropIndex(aEvent); var newIndex = getDropIndex2(aEvent); var tabIndex; var dt = aEvent.dataTransfer; var draggedTab = dt.mozSourceNode; if (draggedTab && draggedTab.parentNode == gBrowser.tabContainer) { tabIndex = gBrowser.getTabIndex(draggedTab); if (newIndex > tabIndex) newIndex--; gBrowser.moveTabTo(tabIndex, newIndex); } else { var url; var linkHandler = Components.classes["@mozilla.org/content/dropped-link-handler;1"] .getService(Components.interfaces.nsIDroppedLinkHandler); try { // Pass true to disallow dropping javascript: or data: urls. url = linkHandler.dropLink(aEvent, {}, true); } catch (ex) {} // Valid urls don't contain spaces ' '; if we have a space // it isn't a valid url. if (!url || url.indexOf(" ") != -1) return; var bgLoad = gBrowser.mPrefs.getBoolPref("browser.tabs.loadInBackground"); if (aEvent.shiftKey) bgLoad = !bgLoad; var tab = null; tabIndex = gBrowser.getDropOnIndex(aEvent); if (tabIndex != -1) { // Load in an existing tab. tab = gBrowser.tabs[tabIndex]; tab.linkedBrowser.loadURI(getShortcutOrURI(url)); if (gBrowser.mCurrentTab != tab && !bgLoad) gBrowser.selectedTab = tab; } else if (dt.mozSourceDocument && dt.mozSourceDocument.defaultView.top == content) { // We're adding a new tab, and we may want parent-tab tracking. tab = gBrowser.loadOneTab(getShortcutOrURI(url), {inBackground: bgLoad}); if (newIndex != gBrowser.tabs.length - 1) gBrowser.moveTabTo(gBrowser.tabs.length - 1, newIndex); } else { // We're adding a new tab, but do not want parent-tab tracking. tab = gBrowser.addTab(getShortcutOrURI(url)); if (newIndex != gBrowser.tabs.length - 1) gBrowser.moveTabTo(gBrowser.tabs.length - 1, newIndex); if (gBrowser.mCurrentTab != tab && !bgLoad) gBrowser.selectedTab = tab; } } } gBrowser.tabContainer.addEventListener("drop", gBrowser.tabContainer._onDrop, true); })();
- 「タブを保護」(とじられないようにする)機能をつけくわえる
// ==UserScript== // @name ProtectTab.uc.js // @version 1.2.0.0 // @description 「タブを保護」(とじられないようにする)機能をつけくわえる // @author あなたのなまえ // @namespace // @include main // @compatibility SeaMonkey 2.26+ // @note tabProtect_mod1.uc.js (Alice0775) をベースに改造 // ==/UserScript== (function() { const XUL_NAMESPACE = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; const TAB_PROTECTED = "tabProtected"; const ICON_PROTECTED = "tab-icon-protected"; var unicodeConverter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); unicodeConverter.charset = "UTF-8"; var ss = Components.classes["@mozilla.org/suite/sessionstore;1"].getService(Components.interfaces.nsISessionStore); var aTabContextMenu = document.getAnonymousElementByAttribute(gBrowser, "anonid", "tabContextMenu"); var protectTab = { init: function() { protectTab.modifyRemoveTabFunc(); protectTab.applyCss(); protectTab.addProtectTabMenu(); aTabContextMenu.addEventListener("popupshowing", protectTab.adjustMenuDisplay, false); gBrowser.tabContainer.addEventListener("TabMove", protectTab.refreshProtectedIcon, false); gBrowser.tabContainer.addEventListener("SSTabRestoring", protectTab.restoreProtectedTab, false); window.addEventListener("unload", protectTab.unInit, false); }, modifyRemoveTabFunc: function() { var aFuncStr = gBrowser.removeTab.toString(); aFuncStr = aFuncStr.replace('{', '{ \ if (aTab.localName != "tab") \ aTab = this.mCurrentTab; \ if (aTab.hasAttribute(TAB_PROTECTED)) return;' ); eval("gBrowser.removeTab = " + aFuncStr); }, applyCss: function() { var aCss = '@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul); \ \ .tab-icon-protected { \ margin-top: -10px !important; \ margin-left: -8px !important; \ list-style-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAX0lEQVQYlWP4//8/w////xmqE1zPIGOYOFzi/8eO///f1f///6rg//9nSf9h4gzYJP8/Cvn//57bf4QCLJL/b5kjKcAi+f+aJpICLJL/L8lCFMB8gE3y////DAyEvAkAPOeun/e/SAQAAAAASUVORK5CYII="); \ } \ '.replace(/\s+/g, " "); var aPi = document.createProcessingInstruction( 'xml-stylesheet', 'type="text/css" href="data:text/css,' + encodeURIComponent(aCss) + '"' ); document.insertBefore(aPi, document.documentElement); }, unInit: function() { gBrowser.tabContainer.removeEventListener("TabMove", protectTab.refreshProtectedIcon, false); gBrowser.tabContainer.removeEventListener("SSTabRestoring", protectTab.restoreProtectedTab, false); }, adjustMenuDisplay: function(aEvent) { if (aEvent.target == aEvent.currentTarget) { var aItem, aBoolStr; var aTab = gBrowser.mContextTab; aBoolStr = (aTab.hasAttribute(TAB_PROTECTED) && aTab.getAttribute(TAB_PROTECTED)).toString(); aItem = document.getElementById("menu_protectTab"); aItem.setAttribute("checked", aBoolStr); aBoolStr = (aTab.localName != "tab").toString(); aItem.setAttribute("disabled", aBoolStr); } }, // セパレーター存在確認 (lockTab) separatorExists: function() { var aBool = false; var aNodes = aTabContextMenu.childNodes; var aStr = "menuseparator"; var index; for (index = 0; index < 2; index++) { if (aNodes[index].nodeName.indexOf(aStr) >= 0) { aBool = true; break; } } return aBool; }, addProtectTabMenu: function() { var aLabel = unicodeConverter.ConvertToUnicode("タブを保護"); var aItem; if (!protectTab.separatorExists()) { aItem = document.createElement("menuseparator"); aItem.setAttribute("id", "aptmSep"); aTabContextMenu.insertBefore(aItem, aTabContextMenu.firstChild); } aItem = document.createElement("menuitem"); aItem.setAttribute("type", "checkbox"); aItem.setAttribute("id", "menu_protectTab"); aItem.setAttribute("label", aLabel); aItem.setAttribute("accesskey", "P"); aItem.addEventListener("command", function() { var aTab = gBrowser.mContextTab; if (aTab.localName != "tab") { return; } gBrowser.setProtectedAttribute(aTab); }, false); aTabContextMenu.insertBefore(aItem, aTabContextMenu.firstChild); }, refreshProtectedIcon: function(aEvent) { var aTab = aEvent.target; gBrowser.setProtectedIcon(aTab); }, restoreProtectedTab: function(aEvent) { var aTab = aEvent.originalTarget; protectTab.restoreProtectedAttribute(aTab); }, restoreProtectedAttribute: function(aTab) { var aData = ss.getTabValue(aTab, TAB_PROTECTED); if (aData) { aTab.setAttribute(TAB_PROTECTED, "true"); } gBrowser.setProtectedIcon(aTab); } } gBrowser.setProtectedAttribute = function(aTab) { var isProtected; if (aTab.hasAttribute(TAB_PROTECTED)) { aTab.removeAttribute(TAB_PROTECTED); try { ss.deleteTabValue(aTab, TAB_PROTECTED); } catch(e) { } isProtected = false; } else { aTab.setAttribute(TAB_PROTECTED, "true"); ss.setTabValue(aTab, TAB_PROTECTED, true); isProtected = true; } gBrowser.setProtectedIcon(aTab); return isProtected; } gBrowser.setProtectedIcon = function(aTab) { var aBox = document.getAnonymousElementByAttribute(aTab, "class", "tab-middle box-inherit"); var aImage = document.getAnonymousElementByAttribute(aTab, "class", ICON_PROTECTED); if (aTab.hasAttribute(TAB_PROTECTED)) { if (!aImage) { var aLabel = document.getAnonymousElementByAttribute(aTab, "class", "tab-text"); var tempImage = document.createElementNS(XUL_NAMESPACE, "image"); tempImage.setAttribute("class", ICON_PROTECTED); aBox.insertBefore(tempImage, aLabel); } else { aImage.removeAttribute("hidden"); } var aStr = aTab.getAttribute("class") + " " + TAB_PROTECTED; aTab.setAttribute("class", aStr); } else { if (aImage) { aImage.setAttribute("hidden", true); aBox.removeChild(aImage); } var aStr = aTab.getAttribute("class"); aTab.setAttribute("class", aStr.replace(/\stabProtected/g,"")); } } protectTab.init(); })();
- 「タブをできるだけロック」(リンクをできるだけべつのタブでひらく)機能をつけくわえる(コードもいまいちだし、あんまり実用的じゃないかも? “なんちゃって”タブロックですね)
// ==UserScript== // @name LockTabAsPossible.uc.js // @version 1.0.0.0 // @description 「タブをできるだけロック」(リンクをできるだけべつのタブでひらく)機能をつけくわえる // @author あなたのなまえ // @namespace // @include main // @compatibility SeaMonkey 2.26+ // @note a・area・button・inputについて、href="〜"・onclick="〜"を取得 // @note 左クリックでべつのタブでひらく(中クリック、右クリックの挙動はそのまま) // @note べつのタブでひらく // @note 絶対パス、相対パス、location.href=〜、location.assign('〜') // @note なにもしない(=反応しない) // @note 関数 // @note javascript:history.〜 // @note javascript:close() // @note javascript:location.reload() // ==/UserScript== (function() { const XUL_NAMESPACE = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; const TAB_LOCKED = "tabLocked"; const ICON_LOCKED = "tab-icon-locked"; var unicodeConverter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); unicodeConverter.charset = "UTF-8"; var ss = Components.classes["@mozilla.org/suite/sessionstore;1"].getService(Components.interfaces.nsISessionStore); var aTabContextMenu = document.getAnonymousElementByAttribute(gBrowser, "anonid", "tabContextMenu"); function getAbsoluteUrl(aUrl) { // 空白文字列をわたすと現在のlocation.hrefをかえす var div = content.document.createElement("div"); div.innerHTML = ""; div.firstChild.href = aUrl; div.innerHTML = div.innerHTML; return div.firstChild.href; } function extractUrlFromScript(aStr) { var aUrl = aStr; // location.href var aIndex; aIndex = aStr.indexOf("location.href"); if (aIndex > -1) { aStr = aStr.replace("return false", ""); aStr = aStr.replace(/\s+/g, ""); var tempArray = aStr.split("="); aStr = tempArray[1]; aStr = aStr.replace(/\'/g, ""); aStr = aStr.replace(/\"/g, ""); aUrl = getAbsoluteUrl(aStr); } // location.assign aIndex = aStr.indexOf("location.assign"); if (aIndex > -1) { var aLength = "location.assign".length; aStr = aStr.slice(aIndex + aLength); aStr = aStr.replace("return false", ""); aStr = aStr.replace(/\s+/g, ""); aStr = aStr.replace(/\'/g, ""); aStr = aStr.replace(/\"/g, ""); aStr = aStr.replace(/\(/g, ""); aStr = aStr.replace(/\)/g, ""); aStr = aStr.replace(/\;/g, ""); aUrl = getAbsoluteUrl(aStr); } return aUrl; } function getUrlFromNode(aNode) { aHref = ""; while (aNode.tagName != "HTML") { // a, area if ((aNode.tagName == "A") || (aNode.tagName == "AREA")) { aHref = aNode.href; // href カラじゃない javascript:;じゃない voidがない 末尾に#がない if ((aHref != "") && (aHref != "javascript:;") && (aHref.indexOf("void") < 0) && (aHref.charAt(aHref.length - 1) != "#")) { aHref = extractUrlFromScript(aHref); } else { // onclick var tempStr = aNode.getAttribute("onclick"); // 関数 if (tempStr.indexOf("()") > -1) { aHref = ""; //eval(tempStr); } else { aHref = extractUrlFromScript(tempStr); } } return aHref } // input, button else if ((aNode.tagName == "INPUT") || (aNode.tagName == "BUTTON")) { var tempStr = aNode.getAttribute("onclick"); // 関数 if (tempStr.indexOf("()") > -1) { aHref = ""; //eval(tempStr); } else { aHref = extractUrlFromScript(tempStr); } } aNode = aNode.parentNode; } return aHref; } var lockTab = { clickInTheLocked: function(aEvent) { if (aEvent.button == 0) { var aUrl = getUrlFromNode(aEvent.target); if (aUrl != "") { // open url in a new tab openNewTabWith(aUrl, aEvent.target.ownerDocument, null, aEvent); } else { } aEvent.preventDefault(); aEvent.stopPropagation(); } }, init: function() { lockTab.applyCss(); lockTab.addLockTabMenu(); aTabContextMenu.addEventListener("popupshowing", lockTab.adjustMenuDisplay, false); gBrowser.tabContainer.addEventListener("TabOpen", lockTab.refreshLockedIcon, false); gBrowser.tabContainer.addEventListener("TabMove", lockTab.refreshLockedIcon, false); gBrowser.tabContainer.addEventListener("SSTabRestoring", lockTab.restoreLockedTab, false); window.addEventListener("unload", lockTab.unInit, false); }, applyCss: function() { var aCss = '@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul); \ \ .tab-icon-locked { \ margin-top: 8px !important; \ margin-left: -8px !important; \ list-style-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAwUlEQVQYlW3Py4tBcQDF8fvP3f/jrizVbKZ0pdQUC0UsyERpopQUkUgak0czfsQkQp7DeI7XjPXXQlyLWZzNOZ/NkQAJkFRFFve59rdxcErTPkapb1/4WHu4ohvo/Mb43IUQm2eKC4cGVEUWvb8EzX2Y2o+f8tJFfmYlMzGhKrKQVEUWrUOE+jbA+8rN27eN7JeZ5PBRA41dkMraS2FuJzd9IjUyEOvrNVDd+CgtnbzOLKTHRuKDByJd3QX8d/H+6hlqubBlL2WTyAAAAABJRU5ErkJggg=="); \ } \ '.replace(/\s+/g, " "); var aPi = document.createProcessingInstruction( 'xml-stylesheet', 'type="text/css" href="data:text/css,' + encodeURIComponent(aCss) + '"' ); document.insertBefore(aPi, document.documentElement); }, unInit: function() { gBrowser.tabContainer.removeEventListener("TabOpen", lockTab.refreshLockedIcon, false); gBrowser.tabContainer.removeEventListener("TabMove", lockTab.refreshlockedIcon, false); gBrowser.tabContainer.removeEventListener("SSTabRestoring", lockTab.restorelockedTab, false); }, adjustMenuDisplay: function(aEvent) { if (aEvent.target == aEvent.currentTarget) { var aItem, aBoolStr; var aTab = gBrowser.mContextTab; aBoolStr = (aTab.hasAttribute(TAB_LOCKED) && aTab.getAttribute(TAB_LOCKED)).toString(); aItem = document.getElementById("menu_lockTab"); aItem.setAttribute("checked", aBoolStr); aBoolStr = (aTab.localName != "tab").toString(); aItem.setAttribute("disabled", aBoolStr); } }, // セパレーター存在確認 (protectTab) separatorExists: function() { var aBool = false; var aNodes = aTabContextMenu.childNodes; var aStr = "menuseparator"; var index; for (index = 0; index < 2; index++) { if (aNodes[index].nodeName.indexOf(aStr) > -1) { aBool = true; break; } } return aBool; }, addLockTabMenu: function() { var aLabel = unicodeConverter.ConvertToUnicode("タブをロック"); var aItem; if (!lockTab.separatorExists()) { aItem = document.createElement("menuseparator"); aItem.setAttribute("id", "altmSep"); aTabContextMenu.insertBefore(aItem, aTabContextMenu.firstChild); } aItem = document.createElement("menuitem"); aItem.setAttribute("type", "checkbox"); aItem.setAttribute("id", "menu_lockTab"); aItem.setAttribute("label", aLabel); aItem.setAttribute("accesskey", "L"); aItem.addEventListener("command", function() { var aTab = gBrowser.mContextTab; if (aTab.localName != "tab") { return; } gBrowser.setLockedAttribute(aTab); }, false); aTabContextMenu.insertBefore(aItem, aTabContextMenu.firstChild); }, refreshLockedIcon: function(aEvent) { var aTab = aEvent.target; gBrowser.setLockedIcon(aTab); }, restoreLockedTab: function(aEvent) { var aTab = aEvent.originalTarget; lockTab.restoreLockedAttribute(aTab); }, restoreLockedAttribute: function(aTab) { var aData = ss.getTabValue(aTab, TAB_LOCKED); if (aData) { aTab.setAttribute(TAB_LOCKED, "true"); var aBrowser = gBrowser.getBrowserForTab(aTab); aBrowser.addEventListener("click", lockTab.clickInTheLocked, true); } gBrowser.setLockedIcon(aTab); } } gBrowser.setLockedAttribute = function(aTab) { var isLocked; var aBrowser = gBrowser.getBrowserForTab(aTab); if (aTab.hasAttribute(TAB_LOCKED)) { aTab.removeAttribute(TAB_LOCKED); ss.deleteTabValue(aTab, TAB_LOCKED); aBrowser.removeEventListener("click", lockTab.clickInTheLocked, true); isLocked = false; } else { aTab.setAttribute(TAB_LOCKED, "true"); ss.setTabValue(aTab, TAB_LOCKED, true); aBrowser.addEventListener("click", lockTab.clickInTheLocked, true); isLocked = true; } gBrowser.setLockedIcon(aTab); return isLocked; } gBrowser.setLockedIcon = function(aTab) { var aBox = document.getAnonymousElementByAttribute(aTab, "class", "tab-middle box-inherit"); var aImage = document.getAnonymousElementByAttribute(aTab, "class", ICON_LOCKED); if (aTab.hasAttribute(TAB_LOCKED)) { if (!aImage) { var aTabText = document.getAnonymousElementByAttribute(aTab, "class", "tab-text"); var tempImage = document.createElementNS(XUL_NAMESPACE, "image"); tempImage.setAttribute("class", ICON_LOCKED); aBox.insertBefore(tempImage, aTabText); } else { aImage.hidden = false; } var aStr = aTab.getAttribute("class") + " " + TAB_LOCKED; aTab.setAttribute("class", aStr); } else { if (aImage) { aImage.hidden = true; aBox.removeChild(aImage); } var aStr = aTab.getAttribute("class"); aTab.setAttribute("class", aStr.replace(/\stabLocked/g,"")); } } lockTab.init(); })();
- IE(インターネットエクスプローラ)でページやリンクをひらく(IEでひらきたいURL、たとえば「http://homepage1.nifty.com/akshiba/」は、chromeフォルダーに作成されるOpenWithIE.datに自分でかきこむ)
// ==UserScript== // @name OpenWithIE.uc.js // @version 1.1.0.0 // @description IEでページやリンクをひらく // @author あなたのなまえ // @namespace // @include main // @compatibility SeaMonkey 2.26+ // @note 設定ファイル: OpenWithIE.dat (カラのファイルを自動作成する) // @note IEでひらきたいUrl「http://〜〜」をられつしていく // @note 前方一致で判断する // ==/UserScript== (function() { const IEPATH = "C:\\Program Files\\Internet Explorer\\iexplore.exe"; const DATFILENAME = "OpenWithIE.dat"; var unicodeConverter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter); unicodeConverter.charset = "UTF-8"; var aContextMenu = document.getElementById("contentAreaContextMenu"); var urlArray = []; var openWithIE = { init: function() { openWithIE.setUrlArray(); openWithIE.addOpenPageMenu(); openWithIE.addOpenLinkMenu(); var aAppcontent = document.getElementById("appcontent"); aAppcontent.addEventListener("DOMContentLoaded", openWithIE.compareUrl, true); gBrowser.tabContainer.addEventListener("TabSelect", openWithIE.compareUrl, false); aContextMenu.addEventListener("popupshowing", openWithIE.adjustMenuDisplay, false); }, setUrlArray: function() { var aFile = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("UChrm", Components.interfaces.nsIFile); aFile.append(DATFILENAME); if (!aFile.exists()) { aFile.create(Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 0664); } var aStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream); aStream.init(aFile, -1, 0, 0); aStream.QueryInterface(Components.interfaces.nsILineInputStream); var aObj = {}, hasMore; // hasMore: Boolean; do { hasMore = aStream.readLine(aObj); urlArray.push(aObj.value); } while (hasMore); }, compareUrl: function(aEvent) { var isFrame = (aEvent.target instanceof Components.interfaces.nsIDOMHTMLDocument && aEvent.target != gBrowser.contentDocument); if (isFrame) { return; } var index, aPos; var aUrl = content.location.href; for (index = 0; index < urlArray.length; index++) { aPos = aUrl.indexOf(urlArray[index]); // 前方一致 if (aPos == 0) { gBrowser.removeCurrentTab(); openWithIE.runIE(aUrl); } } }, adjustMenuDisplay: function(aEvent) { if (aEvent.target == aEvent.currentTarget) { var aItem, aBool; aBool = (gContextMenu.onLink || gContextMenu.onImage); aItem = document.getElementById("context_openPageWithIE"); aItem.hidden = aBool; aBool = ((!gContextMenu.onLink) || (!gContextMenu.onLink && gContextMenu.onImage)); aItem = document.getElementById("context_openLinkWithIE"); aItem.hidden = aBool; } }, addOpenPageMenu: function() { var aLabel = unicodeConverter.ConvertToUnicode("ページを IEで ひらく"); var tempItem = document.getElementById("context-sep-open"); var aItem = document.createElement("menuitem"); aItem.setAttribute("id", "context_openPageWithIE"); aItem.setAttribute("label", aLabel); aItem.setAttribute("accesskey", "Z"); aItem.addEventListener("command", function() { openWithIE.runIE(content.location.href); }, false); aContextMenu.insertBefore(aItem, tempItem); }, addOpenLinkMenu: function() { var aLabel = unicodeConverter.ConvertToUnicode("リンクを IEで ひらく"); var tempItem = document.getElementById("context-sep-open"); var aItem = document.createElement("menuitem"); aItem.setAttribute("id", "context_openLinkWithIE"); aItem.setAttribute("label", aLabel); aItem.setAttribute("accesskey", "Z"); aItem.addEventListener("command", function() { openWithIE.runIE(gContextMenu.link.href); }, false); aContextMenu.insertBefore(aItem, tempItem); }, runIE: function(aUrl) { var aApp = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile); aApp.initWithPath(IEPATH); if (!aApp.exists()) { alert("File not found: \n" + IEPATH); return; } var aProcess = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess); aProcess.init(aApp); var options = [aUrl]; aProcess.run(false, options, options.length); } } openWithIE.init(); })();
◆UserScriptLoader.uc.js用スクリプトをつかってみる
【スクリプトをさがす】
UserScriptLoader.uc.jsはスクリプトをよみこむスクリプト。ファイアーフォックスのアドオン「グリースモンキー」(Greasemonkey)のユーザークロームJS版、といえます。実際、グリースモンキー用スクリプトのおおくがそのままつかえるようにつくられています。
グリースモンキー用スクリプトをさがすなら、「Greasy Fork」がいいでしょう。「userscripts.org」(http://userscripts.org/)が管理のゆきとどかない状況になったためにつくられたサイトです。
そんなわけで、userscripts.orgのスクリプトを利用する場合は、安全であるかどうか、よくたしかめることをおすすめしておきます。
なお、UserScriptLoader.uc.js用スクリプトは、表示しているページの動作にかかわるものですから、シーモンキーでつかうからといってかきかえる必要は(基本的に)ありません。
【スクリプトのインストール・アンインストール】
Greasy Forkには、「Install this script」というボタンがあるので、これをおしてみましょう。スクリプトのコードが表示されるので、メニューの[ファイル]→[ページを保存]をえらびます。これでスクリプトが保存されます。
保存したスクリプトは、UserScriptLoaderフォルダーに移動してください。移動したら、ロケーションバーのかみなりマークをホイールクリックするか、かみなりマークの右クリックメニューから[Menu]→[Rebuild]をえらびます。UserScriptLoader.uc.js用スクリプトがすべて再よみこみされて、移動したスクリプトがつかえるようになります。
つかわなくなったスクリプトは、削除してください。削除したら、[Rebuild]をおわすれなく。
【スクリプトをつくる】
スクリプトは、文字コード「BOMなしUTF-8」のテキストファイルです。てきとうなテキストエディターで、ファイル名を「〜.user.js」として保存すればいいでしょう。
ユーザークロームJS用スクリプトをつくるのとおなじように、すでにあるスクリプトをみながら、あれこれ試行錯誤してみてください。
とりあえず、自作のスクリプト(といっても、基本はきりばりですが)をあげておきます。まえにファイアーフォックス用にかいたものですが。てきとうにおつかいください。
- ヤフーの検索結果画面でクリックトラッキングを無効にする
// ==UserScript== // @name DisableYahooClickTracking.user.js // @version 1.1.0.0 // @description ヤフーの検索結果画面でクリックトラッキングを無効にする // @author あなたのなまえ // @namespace // @include http://search.yahoo.* // @compatibility SeaMonkey 2.26+ // @note // ==/UserScript== (function () { var trackingStr = "http://wrs.search.yahoo"; var searchStr = "**http"; // リンク情報を全部取得 var linkArray = document.getElementsByTagName("a"); for (var i = 0; i < linkArray.length; i++) { // onmousedown を無効にする linkArray[i].onmousedown = doNothing(); // href をかきかえる var decodedStr = decodeURIComponent(decodeURIComponent(linkArray[i].href)); // "http://wrs.search.yahoo" をさがす if (decodedStr.indexOf(trackingStr) == 0) { // "**http" をさがす var strPos = decodedStr.indexOf(searchStr); if (strPos > -1) { // href をきりだして、かきかえる var tempStr = decodedStr.slice(strPos + 2); linkArray[i].href = encodeURI(tempStr); } } } function doNothing() { return false; } })();
*
シーモンキーのカスタマイズについて、ざっくりと紹介してきました。みなさんがカスタマイズをしていくときのとっかかりになれば、うれしいかぎりです。