Firefox userChrome.js用ユーザースクリプトを作成する
Firefox を使いやすくするため、タブのタイトルとURLをコピーしたかったけど、できなかったので自作してみた。
userChrome.js とは
userChrome.js は、 Firefox のブラウザに対するユーザースクリプトを実行する方法です。(ページのユーザースクリプトとは異なります)
Firefox の拡張機能(WebExtensions)と同様にブラウザを制御できます。ですが、 userChrome.js は拡張機能よりも制約がゆるく細やかな制御が可能です。逆に言えば、拡張機能よりも危険です。
userChrome.js の導入方法
次のスクリプト導入法を参照してください。
※userChrome.js は、正式な機能ではないため、バージョン毎に導入方法が変化しています。また、今後 userChrome.js が廃止される可能性があります。
Firefox92+の導入方法(最新版用)
- alice0775/userChrome.js - GitHub
- 下記の3ファイルを所定の場所に配置する。
/92/userChrome.js
/92/install_folder/config.js
/92/install_folder/defaults/pref/config-prefs.js
- 以前に
userChrome.js
を導入している場合、以前のファイルをすべて削除する- 以前のファイルが残っている場合、誤動作や動作しないことがあります
- プロファイルフォルダの「
chrome
」フォルダを作成して次のファイルを配置する/92/userChrome.js
- アプリケーションのインストールフォルダに次のファイルを配置する
/92/install_folder/config.js
/92/install_folder/defaults/pref/config-prefs.js
config.js
は、インストールフォルダ直下に配置するconfig-prefs.js
は、インストールフォルダの「/defaults/pref
」に配置する
※プロファイルフォルダは、「about:support
」のプロファイルフォルダーを確認する。
※アプリケーションのインストールフォルダは、「firefox.exe
」の格納フォルダです。
例:C:\Program Files\Mozilla Firefox
※上記のファイルは、 UTF-8 で保存してください。文字コードが異なると動作しません。
Firefox72-91の導入方法(ESR78用・ESR91用)
- alice0775/userChrome.js - GitHub
- 下記の3ファイルを所定の場所に配置する。
/72/userChrome.js
/72/install_folder/config.js
/72/install_folder/defaults/pref/config-prefs.js
- 以前に
userChrome.js
を導入している場合、以前のファイルをすべて削除する- 以前のファイルが残っている場合、誤動作や動作しないことがあります
- プロファイルフォルダの「
chrome
」フォルダを作成して次のファイルを配置する/72/userChrome.js
- アプリケーションのインストールフォルダに次のファイルを配置する
/72/install_folder/config.js
/72/install_folder/defaults/pref/config-prefs.js
config.js
は、インストールフォルダ直下に配置するconfig-prefs.js
は、インストールフォルダの「/defaults/pref
」に配置する
※プロファイルフォルダは、「about:support
」のプロファイルフォルダーを確認する。
※アプリケーションのインストールフォルダは、「firefox.exe
」の格納フォルダです。
例:C:\Program Files\Mozilla Firefox
※上記のファイルは、 UTF-8 で保存してください。文字コードが異なると動作しません。
alice0775版以外の userChrome.js
探せば、他にもあるかもしれません。それぞれでメタデータの扱いや BootstorapLoader の有無などが異なります。
※userChrome.js 毎でユーザースクリプトの変更が必要となる場合があります。
Windows 以外への導入(macOS / Linux)
install_folder
とプロファイルディレクトリー(フォルダー)に上記と同様にファイルを配置してください。 install_folder
とプロファイルディレクトリーは、次の場所にあります。
install_folder
を探すabout:support
を開く- [アプリケーションの実行ファイル] を開く
- 付近のディレクトリーを探す
- 例:macOS12
- アプリケーションの実行ファイル:
/Applications/Firefox.app/Contents/MacOS/firefox
install_folder/
:/Applications/Firefox.app/Contents/Resources/
install_folder/defaults/pref/
:/Applications/Firefox.app/Contents/Resources/defaults/pref/
- アプリケーションの実行ファイル:
- 例:Ubuntu20
- アプリケーションの実行ファイル:
/usr/lib/firefox/firefox
install_folder/
:/usr/lib/firefox/
install_folder/defaults/pref/
:/usr/lib/firefox/defaults/pref/
- アプリケーションの実行ファイル:
- 例:macOS12
- プロファイルディレクトリーを探す
about:support
を開く- [プロファイルディレクトリー] を開く
- 例:macOS12
/Users/(ユーザー名)/Library/Application Support/Firefox/Profiles/(プロファイル名)/
- 例:Ubuntu20
/home/(ユーザー名)/.mozilla/firefox/(プロファイル名)/
- 例:macOS12
コードを書くために
userChrome.js のドキュメントは、特に存在しません(筆者は見つけられませんでした)。そのため、ブラウザーツールボックスを確認したり、他人の書いた動作するソースコードを元に求める機能を実現する必要があります。
また、 Firefox のバージョンによって動作しないコードもあります。バージョンアップ後動作しなくなる場合、動作に必要な機能がなくなっていたり、名称が変更していたりします。また、 userChrome.js そのものが、動作していなくなっていることもあります。
覚書(全般)
userChrome.js を探す
- GitHub - alice0775/userChrome.js
- userChrome.js用スクリプト - wiki@nothing
- firefox用スクリプトアップローダー | uploader.jp
ユーザースクリプトの設定
ファイルの先頭にユーザースクリプトの設定を記述する。
// ==UserScript==
// @name スクリプト名.uc.js
// @description 機能の概要
// @version 1.0.0
// @include main
// @charset UTF-8
// ==/UserScript==
※日本語を使用する場合、 charset に UTF-8 を指定することで文字コード関連の大抵の問題を回避できます。
ログ出力する
// 「console.log() を表示する」参照
console.log('Hello World');
// アラーム
alert('Hello World');
console.log() を表示する
ブラウザーツールボックスで確認する
- ブラウザーツールボックスを有効化する
- [F12] > […] > [設定] > [詳細設定]
- 「ブラウザーとアドオンのデバッグを有効化」をチェックする
- 「リモートデバッガーを有効化」をチェックする
- [F12] > […] > [設定] > [詳細設定]
- ブラウザーツールボックスを開く
Ctrl + Alt + Shift + i
- 「接続しますか?」を「OK」する
- コンソールタブを表示する
console.log()
出力が表示されます- ただし、 Firefox の各種出力も表示されます
覚書(アクション系)
コンテキストメニューを追加する
var menuItem = document.createXULElement("menuitem");
menuItem.setAttribute("id", "context-menu-item-id");
menuItem.setAttribute("label", "追加したメニューラベル");
menuItem.addEventListener('command', function() {
console.log('追加したメニューラベルを選択しました。');
alert('追加したメニューラベルを選択しました');
});
var contextMenu = document.getElementById("contentAreaContextMenu");
contextMenu.appendChild(menuItem, contextMenu.firstChild);
タブコンテキストメニューの末尾追加する
// 「コンテキストメニューを追加する」参照
var tabContextMenu = document.getElementById("tabContextMenu");
//var contextMenu = document.getElementById("contentAreaContextMenu");
tabContextMenu.appendChild(menuItem, tabContextMenu.firstChild);
タブコンテキストメニューに先頭追加する
// 「コンテキストメニューを追加する」参照
var tabContextMenu = document.getElementById("tabContextMenu");
tabContextMenu.insertBefore(menuItem, tabContextMenu.firstChild);
タブコンテキストメニューにセパレータを追加する
var menusSparator = document.createXULElement("menuseparator");
var tabContextMenu = document.getElementById("tabContextMenu");
tabContextMenu.appendChild(menusSparator, tabContextMenu.firstChild);
アクセスキー(ショートカットキー)を変更する
// [閉じたタブを開きなおす(O)] のアクセスキーを Uキーに置き換える(Firefox87-の設定に戻す)
document.getElementById('tabContextMenu').addEventListener('popupshowing', function() {
//document.getElementById('context_undoCloseTab').setAttribute('label', '閉じたタブを元に戻す');
document.getElementById('context_undoCloseTab').setAttribute('accesskey', 'u');
});
※メニュー表示前に変更すると元の設定に戻される
もっと良い方法を要検討
ツールチップを配置する
try {
var id = 'id';
// 複数ウィンドウで使用する場合、ウィンドウ毎に個別のIDを指定する必要がある
//var id = 'id'+(''+Math.random()).substring(2);
CustomizableUI.createWidget({
id: id,
type: 'custom',
defaultArea: CustomizableUI.AREA_NAVBAR, // ナビゲーション
// defaultArea: CustomizableUI.AREA_TABSTRIP,// タブステップ
onBuild: function(doc) {
const toolbaritem = doc.createXULElement('toolbarbutton');
const props = {
id: id,
class: 'toolbarbutton-1 chromeclass-toolbar-additional',
removable: false,
label: 'ラベル',
tooltiptext: 'ツールチップテキスト',
image: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNTEyIDUxMiIgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIj4KICAgIDxwYXRoIHN0cm9rZS13aWR0aD0iMjQiIGZpbGw9IiM1NTU1NTUiIHN0cm9rZT0iI2ZmZmZmZiIgZD0iTSA2IDQ4MCBsIDUwMCAwIGwgMCAtNjAgbCAtNTAgMCBsIDAgLTIyMCBsIC00MDAgMCBsIDAgMjIwIGwgLTUwIDAgeiIvPgogICAgPHBhdGggc3Ryb2tlLXdpZHRoPSIzMCIgZmlsbD0iIzQ0ODhmZiIgc3Ryb2tlPSIjZGRlZWZmIiBkPSJNIDI3MiAzMiBsIC0xNjAgMTMwIGwgMTYwIDEzMCBsIDAgLTc1IGwgNjAgMCBhIDYwIDYwIDAgMCAxIDAgMTIwIGwgLTIwIDAgbCAwIDExMCBsIDIwIDAgYSAxNzAgMTcwIDAgMCAwIDAgLTM0MCBsIC02MCAwIHoiLz4KPC9zdmc+',
// BASE64で画像を埋め込み
onclick: `
if (event.button == 0) {
console.log('ツールチップをクリックしました。');
alert('ツールチップをクリックしました。');
}
`,
};
for (var key in props) {
Object.keys(props).forEach(key => toolbaritem.setAttribute(key, props[key]));
}
return toolbaritem;
}
});
} catch (e) {}
覚書(イベント系)
簡易なイベント
マウスジェスチャ用ですが動作します。簡易の「戻る」「進む」などがあります。
次のコードも参考になります。
新しいタブを開く
var url = 'https://www.yahoo.co.jp/';
gBrowser.addTrustedTab(url);
新しいタブを選択する(アクティブにする)
var url = 'https://www.yahoo.co.jp/';
gBrowser.selectedTab = gBrowser.addTrustedTab(url);
クリップボードにコピー
var text = 'Hello World';
var clipboard = Cc['@mozilla.org/widget/clipboardhelper;1'].getService(Ci.nsIClipboardHelper);
clipboard.copyString(text);
サンプル
作るもの
下記の機能を実現します。
- タブコンテキストメニューからタイトルのコピー
- タブコンテキストメニューからURLのコピー
ソースコード
CopyTabTitleUrl.uc.js// ==UserScript==
// @name CopyTabTitleUrl.uc.js
// @description タブコンテキストメニューから、タイトルとURLをコピーする。
// @include main
// @charset UTF-8
// @author toshi (https://github.com/k08045kk)
// @license MIT License | https://opensource.org/licenses/MIT
// @compatibility 69+
// @version 5
// @since 1 - 20180212 - 初版
// @since 2 - 20180212 - 「CopyTabTitleAndURL.uc.js」から名称変更
// @since 3 - 20190905 - Firefox69対応 createElement → createXULElement に置換
// @since 4 - 20201122 - 「タイトルとURLをコピー」を追加
// @since 4 - 20201122 - リファクタリング
// @since 5 - 20210910 - メタデータ修正
// @since 5 - 20211008 - メタデータ修正
// @see https://github.com/k08045kk/userChrome.js
// @see https://www.bugbugnow.net/2018/02/CopyTabTitleAndURL.uc.js.html
// ==/UserScript==
(function() {
// クリップボードコピー
const copyToClipboard = function(text) {
Cc['@mozilla.org/widget/clipboardhelper;1'].getService(Ci.nsIClipboardHelper).copyString(text);
};
// copyToClipboard('['+title+']('+url+')'); // Markdown
// copyToClipboard('<a href="'+url+'">'+title+'</a>'); // Hyperlink
// タイトルとURLをコピー
const m0 = document.createXULElement('menuitem');
m0.setAttribute('id', 'context-copytab-titleurl');
m0.setAttribute('label', 'タイトルとURLをコピー');
m0.addEventListener('command', function() {
const title = TabContextMenu.contextTab.linkedBrowser.contentTitle;
const url = TabContextMenu.contextTab.linkedBrowser.currentURI.spec;
copyToClipboard(title+'\n'+url);
});
// タイトルをコピー
const m1 = document.createXULElement('menuitem');
m1.setAttribute('id', 'context-copytab-title');
m1.setAttribute('label', 'タイトルをコピー');
m1.addEventListener('command', function() {
const title = TabContextMenu.contextTab.linkedBrowser.contentTitle;
copyToClipboard(title);
});
// URLをコピー
const m2 = document.createXULElement('menuitem');
m2.setAttribute('id', 'context-copytab-url');
m2.setAttribute('label', 'URLをコピー');
m2.addEventListener('command', function() {
const url = TabContextMenu.contextTab.linkedBrowser.currentURI.spec;
copyToClipboard(url);
});
// セパレータ
const ms = document.createXULElement('menuseparator');
ms.setAttribute('id', 'context-copytab-sep');
// メニューバーの最上部に要素を追加
// タイトルとURLをコピー
// タイトルをコピー
// URLをコピー
// セパレータ
const tabContextMenu = document.getElementById('tabContextMenu');
tabContextMenu.insertBefore(ms, tabContextMenu.firstChild);
tabContextMenu.insertBefore(m2, tabContextMenu.firstChild);
tabContextMenu.insertBefore(m1, tabContextMenu.firstChild);
tabContextMenu.insertBefore(m0, tabContextMenu.firstChild);
}());
※プロファイルフォルダ内のchrome
フォルダにCopyTabTitleUrl.uc.js
の名称で保存
※本スクリプトは、「k08045kk/userChrome.js - GitHub」でも公開