diff --git a/.gitignore b/.gitignore index 92aa312..37ec0ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ -./xpi/ -{8620c15f-30dc-4dba-a131-7c5d20cf4a29} -*.xpi .DS_Store +web-ext-artifacts/ diff --git a/History.md b/History.md index 5adce9c..8e0fdc7 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,7 @@ +4.0 / TBD +================== + * Rewrite extension to use the WebExtension API since the legacy XUL format is no longer supported (#235) + 3.10 / 2017-05-16 ================== * Update maxVersions of applications in install.rdf (#238) diff --git a/README.md b/README.md index 4137b57..08378ed 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,70 @@ # Nightly Tester Tools -Nightly Tester Tools is an addon for aiding testers of nightly builds of Mozilla apps like Firefox and Thunderbird. Some features are: - -* Copy Build ID to Clipboard -* Copy List of Extensions to Clipboard -* Copy about:support to Pastebin -* Open Profile Folder -* Open Pushlog -* Screenshots utility -* Title bar customization + +Nightly Tester Tools (NTT) is an add-on for aiding testers of Nightly builds of Mozilla apps including Firefox. + +Screenshot + +## Features + +* Copy the build ID or list of extensions to the clipboard using the toolbar button +* Insert the build ID or list of extensions into a textbox using the context menu +* Option to customize the Title Bar + +## Limitations + +There are a couple of known issues due to the limited [WebExtensions APIs](https://developer.mozilla.org/Add-ons/WebExtensions/API): + +* The changeset cannot be retrieved +* The extension list does not include system add-ons +* Some variables are not available for the custom title template + +The following features found in the original XUL-based extension are not yet implemented, and some of them may not be implemented again: + +* Copy `about:support` to Pastebin +* Open the profile folder (Use `about:support` or `about:profile` page instead to open it) +* Open the pushlog +* Screenshot utility (Use [Firefox Screenshots](https://support.mozilla.org/kb/firefox-screenshots) instead) * Crash options -* Extension compatibility fixing +* Extension compatibility fixer +* Menu items under Tools + +## Compatibility + +The current WebExtension version is only compatible with Firefox. Use legacy [version 3.10](https://addons.mozilla.org/firefox/addon/nightly-tester-tools/versions/3.10) for Thunderbird and SeaMonkey. -# Install -You can install the latest stable NTT from [addons.mozilla.org](https://addons.mozilla.org/en-US/firefox/addon/nightly-tester-tools/). To install for development, clone the repo: +## Install - git clone git://github.com/mozilla/nightlytt.git +You can install the latest stable NTT from [addons.mozilla.org](https://addons.mozilla.org/firefox/addon/nightly-tester-tools/). -then add a file titled '{8620c15f-30dc-4dba-a131-7c5d20cf4a29}' to the "extensions" directory in your [profile folder](http://kb.mozillazine.org/Profile_folder) with the text: +To install for development, clone the repo: - ~/nightlytt/ +``` +git clone git://github.com/mozilla/nightlytt.git +``` -or whatever the path to your nightlytt folder is. +Install the [`web-ext` command line tool](https://developer.mozilla.org/Add-ons/WebExtensions/Getting_started_with_web-ext): -To package the extension into an xpi for distribution simply `ant` and the default dev script/target will be invoked: +``` +npm install --global web-ext +``` - ant +To test with Firefox: -You can override the build number used in the filename: +``` +web-ext run -s extension +``` - ant -Dbuild.number=1 +To build for release: +``` +web-ext build -s extension +``` -To build for release (no build number in filename): +You can also [temporarily install the extension](https://developer.mozilla.org/Add-ons/WebExtensions/Temporary_Installation_in_Firefox) in your Firefox without having to use `web-ext`. - ant release +## Development -# Development All bugs and feature requests are filed in the Nightly Tester Tools project at GitHub. You can [view the list of open issues](https://github.com/mozilla/nightlytt/issues), or you can [file a new issue](https://github.com/mozilla/nightlytt/issues/new). Check out [the wiki](https://wiki.mozilla.org/Auto-tools/Projects/NightlyTesterTools) for a list of current and proposed features and feel free to file bugs and submit patches. -This project uses [.editorconfig](http://editorconfig.org/#overview), which sets defaults for the formatting of the code. So enjoy the use of [compatible editor](http://editorconfig.org/#download). Just download and install the corresponding plugin. +This project uses [`.editorconfig`](http://editorconfig.org/#overview), which sets defaults for the formatting of the code. So enjoy the use of [compatible editor](http://editorconfig.org/#download). Just download and install the corresponding plugin. -# Related Add-ons -* [Add-on Compatibility Reporter](https://addons.mozilla.org/en-US/firefox/addon/add-on-compatibility-reporter/) -* [Screengrab (fix version)](https://addons.mozilla.org/en-US/firefox/addon/screengrab-fix-version/) +Also, it's encouraged to use the `web-ext lint` command to [check the code](https://developer.mozilla.org/Add-ons/WebExtensions/Getting_started_with_web-ext#Checking_for_code_lint). diff --git a/build.xml b/build.xml deleted file mode 100644 index 4f336a0..0000000 --- a/build.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - build.version: ${build.version} - - - diff --git a/extension/_locales/en_US/messages.json b/extension/_locales/en_US/messages.json new file mode 100644 index 0000000..4f16a0a --- /dev/null +++ b/extension/_locales/en_US/messages.json @@ -0,0 +1,113 @@ +{ + "extension_name": { + "message": "Nightly Tester Tools" + }, + "extension_description": { + "message": "Useful tools for the nightly tester." + }, + "copy_build_info": { + "message": "Copy Build ID to Clipboard" + }, + "insert_build_info": { + "message": "Insert Build ID into Textbox" + }, + "insert_build_info_context": { + "message": "Insert Build ID" + }, + "copy_extension_list": { + "message": "Copy List of Extensions to Clipboard" + }, + "insert_extension_list": { + "message": "Insert List of Extensions into Textbox" + }, + "insert_extension_list_context": { + "message": "Insert List of Extensions" + }, + "open_options_page": { + "message": "Options…" + }, + "customize_title": { + "message": "Customize Title Bar" + }, + "enable_custom_title": { + "message": "Use custom title" + }, + "custom_template": { + "message": "Custom title template:" + }, + "variable_table_caption": { + "message": "The following variables can be used in the title (case insensitive)." + }, + "variable_key": { + "message": "Variable" + }, + "variable_desc": { + "message": "Description" + }, + "variable_value": { + "message": "Value" + }, + "variable_AppID": { + "message": "Application Identifier" + }, + "variable_Vendor": { + "message": "Application Vendor" + }, + "variable_Name": { + "message": "Application Name" + }, + "variable_Version": { + "message": "Application Version" + }, + "variable_AppBuildID": { + "message": "Application Build Identifier" + }, + "variable_Changeset": { + "message": "Built from that changeset" + }, + "variable_PlatformBuildID": { + "message": "Gecko Platform Build Identifier" + }, + "variable_PlatformVersion": { + "message": "Gecko Platform Version" + }, + "variable_GeckoBuildID": { + "message": "Gecko Build Identifier" + }, + "variable_GeckoVersion": { + "message": "Gecko Version" + }, + "variable_BrandName": { + "message": "Application Brand Name" + }, + "variable_UserAgent": { + "message": "User Agent String" + }, + "variable_Locale": { + "message": "Current Locale" + }, + "variable_OS": { + "message": "Compilation OS" + }, + "variable_Processor": { + "message": "Compilation Processor" + }, + "variable_Compiler": { + "message": "Compiler" + }, + "variable_DefaultTitle": { + "message": "Default Application Title" + }, + "variable_TabTitle": { + "message": "Current Tab's Title" + }, + "variable_Profile": { + "message": "Current Profile" + }, + "variable_Toolkit": { + "message": "Graphics Toolkit" + }, + "variable_TabsCount": { + "message": "Count of visible tabs" + } +} diff --git a/extension/_locales/ja/messages.json b/extension/_locales/ja/messages.json new file mode 100644 index 0000000..d7eb7cd --- /dev/null +++ b/extension/_locales/ja/messages.json @@ -0,0 +1,113 @@ +{ + "extension_name": { + "message": "Nightly Tester Tools" + }, + "extension_description": { + "message": "開発版のテスト利用者のための有用なツールを提供します" + }, + "copy_build_info": { + "message": "ビルド ID をクリップボードにコピー" + }, + "insert_build_info": { + "message": "ビルド ID をテキストボックスに挿入" + }, + "insert_build_info_context": { + "message": "ビルド ID を挿入" + }, + "copy_extension_list": { + "message": "アドオンの一覧をクリップボードにコピー" + }, + "insert_extension_list": { + "message": "アドオンの一覧をテキストボックスに挿入" + }, + "insert_extension_list_context": { + "message": "アドオンの一覧を挿入" + }, + "open_options_page": { + "message": "オプション..." + }, + "customize_title": { + "message": "タイトルバーのカスタマイズ" + }, + "enable_custom_title": { + "message": "カスタマイズしたタイトルを使用する" + }, + "custom_template": { + "message": "書式" + }, + "variable_table_caption": { + "message": "タイトルには以下の変数が使用できます (大文字小文字は区別しません)" + }, + "variable_key": { + "message": "変数" + }, + "variable_desc": { + "message": "説明" + }, + "variable_value": { + "message": "現在の値" + }, + "variable_AppID": { + "message": "アプリケーション ID" + }, + "variable_Vendor": { + "message": "アプリケーションのベンダー" + }, + "variable_Name": { + "message": "アプリケーションの名称" + }, + "variable_Version": { + "message": "アプリケーションのバージョン" + }, + "variable_AppBuildID": { + "message": "アプリケーションのビルド ID" + }, + "variable_Changeset": { + "message": "ビルド元のチェンジセット" + }, + "variable_PlatformBuildID": { + "message": "Gecko プラットフォームのビルド ID" + }, + "variable_PlatformVersion": { + "message": "Gecko プラットフォームのバージョン" + }, + "variable_GeckoBuildID": { + "message": "Gecko のビルド ID" + }, + "variable_GeckoVersion": { + "message": "Gecko のバージョン" + }, + "variable_BrandName": { + "message": "アプリケーションのブランド名" + }, + "variable_UserAgent": { + "message": "ユーザーエージェント文字列" + }, + "variable_Locale": { + "message": "現在の言語" + }, + "variable_OS": { + "message": "コンパイルの対象 OS" + }, + "variable_Processor": { + "message": "コンパイルの対象プロセッサー" + }, + "variable_Compiler": { + "message": "コンパイラー" + }, + "variable_DefaultTitle": { + "message": "現在のアプリケーションのタイトル" + }, + "variable_TabTitle": { + "message": "現在のタブのタイトル" + }, + "variable_Profile": { + "message": "現在のプロファイル" + }, + "variable_Toolkit": { + "message": "グラフィックツールキット" + }, + "variable_TabsCount": { + "message": "表示されたタブの数" + } +} diff --git a/extension/_locales/pl/messages.json b/extension/_locales/pl/messages.json new file mode 100644 index 0000000..cdf01d8 --- /dev/null +++ b/extension/_locales/pl/messages.json @@ -0,0 +1,113 @@ +{ + "extension_name": { + "message": "Nightly Tester Tools" + }, + "extension_description": { + "message": "Użyteczne narzędzia dla testerów wersji Nightly." + }, + "copy_build_info": { + "message": "Kopiuj identyfikator kompilacji do schowka" + }, + "insert_build_info": { + "message": "Wstaw identyfikator kompilacji do pola tekstowego" + }, + "insert_build_info_context": { + "message": "Wstaw identyfikator kompilacji" + }, + "copy_extension_list": { + "message": "Kopiuj listę rozszerzeń do schowka" + }, + "insert_extension_list": { + "message": "Wstaw listę rozszerzeń do pola tekstowego" + }, + "insert_extension_list_context": { + "message": "Wstaw listę rozszerzeń" + }, + "open_options_page": { + "message": "Opcje…" + }, + "customize_title": { + "message": "Dostosuj pasek tytułu" + }, + "enable_custom_title": { + "message": "Własny tytuł" + }, + "custom_template": { + "message": "Szablon tytułu:" + }, + "variable_table_caption": { + "message": "Następujące zmienne mogą być użyte w tytule (wielkość liter nie ma znaczenia)." + }, + "variable_key": { + "message": "Zmienna" + }, + "variable_desc": { + "message": "Opis" + }, + "variable_value": { + "message": "Wartość" + }, + "variable_AppID": { + "message": "Identyfikator aplikacji" + }, + "variable_Vendor": { + "message": "Organizacja" + }, + "variable_Name": { + "message": "Nazwa" + }, + "variable_Version": { + "message": "Wersja" + }, + "variable_AppBuildID": { + "message": "Identyfikator kompilacji" + }, + "variable_Changeset": { + "message": "Rewizja kompilacji" + }, + "variable_PlatformBuildID": { + "message": "Identyfikator kompilacji platformy Gecko" + }, + "variable_PlatformVersion": { + "message": "Wersja platformy Gecko" + }, + "variable_GeckoBuildID": { + "message": "Identyfikator kompilacji Gecko" + }, + "variable_GeckoVersion": { + "message": "Wersja Gecko" + }, + "variable_BrandName": { + "message": "Nazwa wersji" + }, + "variable_UserAgent": { + "message": "Identyfikator programu" + }, + "variable_Locale": { + "message": "Wersja językowa" + }, + "variable_OS": { + "message": "System kompilacji" + }, + "variable_Processor": { + "message": "Procesor kompilacji" + }, + "variable_Compiler": { + "message": "Kompilator" + }, + "variable_DefaultTitle": { + "message": "Domyślny tytuł" + }, + "variable_TabTitle": { + "message": "Tytuł karty" + }, + "variable_Profile": { + "message": "Profil" + }, + "variable_Toolkit": { + "message": "Grafika" + }, + "variable_TabsCount": { + "message": "Liczba widocznych kart" + } +} diff --git a/extension/_locales/ru/messages.json b/extension/_locales/ru/messages.json new file mode 100644 index 0000000..92c4f9c --- /dev/null +++ b/extension/_locales/ru/messages.json @@ -0,0 +1,113 @@ +{ + "extension_name": { + "message": "Nightly Tester Tools" + }, + "extension_description": { + "message": "Полезные инструменты nightly-тестера." + }, + "copy_build_info": { + "message": "Копировать Build ID в буфер обмена" + }, + "insert_build_info": { + "message": "Вставить Build ID в текстовое поле" + }, + "insert_build_info_context": { + "message": "Вставить Build ID" + }, + "copy_extension_list": { + "message": "Копировать список расширений в буфер обмена" + }, + "insert_extension_list": { + "message": "Вставить список расширений в текстовое поле" + }, + "insert_extension_list_context": { + "message": "Вставить список расширений" + }, + "open_options_page": { + "message": "Настройки…" + }, + "customize_title": { + "message": "Настроить заголовок" + }, + "enable_custom_title": { + "message": "Использовать свой заголовок" + }, + "custom_template": { + "message": "Шаблон заголовка:" + }, + "variable_table_caption": { + "message": "Следующие переменные могут быть использованы в заголовке (регистронезависимо)." + }, + "variable_key": { + "message": "Переменная" + }, + "variable_desc": { + "message": "Описание" + }, + "variable_value": { + "message": "Значение" + }, + "variable_AppID": { + "message": "Идентификатор приложения" + }, + "variable_Vendor": { + "message": "Поставщик приложения" + }, + "variable_Name": { + "message": "Имя приложения" + }, + "variable_Version": { + "message": "Версия приложения" + }, + "variable_AppBuildID": { + "message": "Идентификатор сборки приложения" + }, + "variable_Changeset": { + "message": "Собрано из этого changeset" + }, + "variable_PlatformBuildID": { + "message": "Идентификатор сборки платформы Gecko" + }, + "variable_PlatformVersion": { + "message": "Версия платформы Gecko" + }, + "variable_GeckoBuildID": { + "message": "Идентификатор сборки Gecko" + }, + "variable_GeckoVersion": { + "message": "Версия Gecko" + }, + "variable_BrandName": { + "message": "Имя бренда приложения" + }, + "variable_UserAgent": { + "message": "User Agent String" + }, + "variable_Locale": { + "message": "Текущая локаль" + }, + "variable_OS": { + "message": "Целевая ОСь" + }, + "variable_Processor": { + "message": "Целевой процессор" + }, + "variable_Compiler": { + "message": "Компилятор" + }, + "variable_DefaultTitle": { + "message": "Заголовок по-умолчанию" + }, + "variable_TabTitle": { + "message": "Заголовок текущей вкладки" + }, + "variable_Profile": { + "message": "Текущий профиль" + }, + "variable_Toolkit": { + "message": "Graphics Toolkit" + }, + "variable_TabsCount": { + "message": "Количество видимых вкладок" + } +} diff --git a/extension/_locales/sv_SE/messages.json b/extension/_locales/sv_SE/messages.json new file mode 100644 index 0000000..493fdae --- /dev/null +++ b/extension/_locales/sv_SE/messages.json @@ -0,0 +1,113 @@ +{ + "extension_name": { + "message": "Nightly Tester Tools" + }, + "extension_description": { + "message": "Användbara verktyg för Nightly-testaren." + }, + "copy_build_info": { + "message": "Kopiera byggets ID till Urklipp" + }, + "insert_build_info": { + "message": "Infoga byggets ID i textruta" + }, + "insert_build_info_context": { + "message": "Infoga byggets ID" + }, + "copy_extension_list": { + "message": "Kopiera lista över tillägg till Urklipp" + }, + "insert_extension_list": { + "message": "Infoga lista över tillägg i textruta" + }, + "insert_extension_list_context": { + "message": "Infoga lista över tillägg" + }, + "open_options_page": { + "message": "Alternativ…" + }, + "customize_title": { + "message": "Anpassa namnlisten" + }, + "enable_custom_title": { + "message": "Använd egen rubrik" + }, + "custom_template": { + "message": "Mall för egen rubrik:" + }, + "variable_table_caption": { + "message": "Följande variabler kan användas i rubriken (ej skiftlägeskänsligt)." + }, + "variable_key": { + "message": "Variabel" + }, + "variable_desc": { + "message": "Beskrivning" + }, + "variable_value": { + "message": "Värde" + }, + "variable_AppID": { + "message": "Programmets identifierare" + }, + "variable_Vendor": { + "message": "Programmets leverantör" + }, + "variable_Name": { + "message": "Programmets namn" + }, + "variable_Version": { + "message": "Programversion" + }, + "variable_AppBuildID": { + "message": "Programbyggets identifierare" + }, + "variable_Changeset": { + "message": "Byggt utifrån den här ändringsuppsättningen" + }, + "variable_PlatformBuildID": { + "message": "Gecko-plattformsbyggets identifierare" + }, + "variable_PlatformVersion": { + "message": "Gecko-plattformens version" + }, + "variable_GeckoBuildID": { + "message": "Geckobyggets identifierare" + }, + "variable_GeckoVersion": { + "message": "Geckoversion" + }, + "variable_BrandName": { + "message": "Programmets märkesnamn" + }, + "variable_UserAgent": { + "message": "Sträng för användaragenten" + }, + "variable_Locale": { + "message": "Aktuell språkkonvention" + }, + "variable_OS": { + "message": "Kompileringens operativsystem" + }, + "variable_Processor": { + "message": "Kompileringsprocessor" + }, + "variable_Compiler": { + "message": "Kompilerare" + }, + "variable_DefaultTitle": { + "message": "Standardprogramrubrik" + }, + "variable_TabTitle": { + "message": "Rubrik för aktuell flik" + }, + "variable_Profile": { + "message": "Aktuell profil" + }, + "variable_Toolkit": { + "message": "Grafikverktyg" + }, + "variable_TabsCount": { + "message": "Count of visible tabs" + } +} diff --git a/extension/_locales/zh_CN/messages.json b/extension/_locales/zh_CN/messages.json new file mode 100644 index 0000000..3c4d828 --- /dev/null +++ b/extension/_locales/zh_CN/messages.json @@ -0,0 +1,113 @@ +{ + "extension_name": { + "message": "Nightly Tester Tools" + }, + "extension_description": { + "message": "nightly 测试者的实用工具集。" + }, + "copy_build_info": { + "message": "复制 Build ID 到剪贴板" + }, + "insert_build_info": { + "message": "插入 Build ID 到文本框" + }, + "insert_build_info_context": { + "message": "插入 Build ID" + }, + "copy_extension_list": { + "message": "复制扩展列表到剪贴板" + }, + "insert_extension_list": { + "message": "插入扩展列表到文本框" + }, + "insert_extension_list_context": { + "message": "插入扩展列表" + }, + "open_options_page": { + "message": "选项…" + }, + "customize_title": { + "message": "定制标题栏" + }, + "enable_custom_title": { + "message": "使用自定义标题" + }, + "custom_template": { + "message": "自定义标题模板:" + }, + "variable_table_caption": { + "message": "下列变量可以用在标题中(大小写敏感)。" + }, + "variable_key": { + "message": "变量" + }, + "variable_desc": { + "message": "描述" + }, + "variable_value": { + "message": "值" + }, + "variable_AppID": { + "message": "应用程序标识符" + }, + "variable_Vendor": { + "message": "应用程序供应商" + }, + "variable_Name": { + "message": "应用程序名称" + }, + "variable_Version": { + "message": "应用程序版本" + }, + "variable_AppBuildID": { + "message": "应用程序构建标识符" + }, + "variable_Changeset": { + "message": "由此变更集构建" + }, + "variable_PlatformBuildID": { + "message": "Gecko 平台构建标识符" + }, + "variable_PlatformVersion": { + "message": "Gecko 平台版本" + }, + "variable_GeckoBuildID": { + "message": "Gecko 构建标识符" + }, + "variable_GeckoVersion": { + "message": "Gecko 版本" + }, + "variable_BrandName": { + "message": "应用程序商标名称" + }, + "variable_UserAgent": { + "message": "用户代理字符串" + }, + "variable_Locale": { + "message": "当前语言区域" + }, + "variable_OS": { + "message": "编译操作系统" + }, + "variable_Processor": { + "message": "编译处理器" + }, + "variable_Compiler": { + "message": "编译器" + }, + "variable_DefaultTitle": { + "message": "默认应用程序标题" + }, + "variable_TabTitle": { + "message": "当前标签标题" + }, + "variable_Profile": { + "message": "当前配置文件" + }, + "variable_Toolkit": { + "message": "图形工具包" + }, + "variable_TabsCount": { + "message": "Count of visible tabs" + } +} diff --git a/extension/background.js b/extension/background.js new file mode 100644 index 0000000..156de54 --- /dev/null +++ b/extension/background.js @@ -0,0 +1,95 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Update the title bar prefix of each window. + */ +const update_titlebar = async () => { + const windows = await browser.windows.getAll(); + const values = await get_variable_values(); + let pref; + let prefix = ' '; // An empty string doesn't work + + try { + pref = await browser.storage.local.get(); + } catch (ex) { + return; + } + + if (pref.enable_custom_title && pref.custom_template) { + prefix = pref.custom_template.replace(/\$\{(\w+)\}/g, (match, key) => find_value(values, key)) + ' — '; + } + + windows.forEach(async win => { + await browser.windows.update(win.id, { titlePreface: prefix }); + }); +}; + +/** + * Find a value from the variable list by its key in a case-insensitive fashion. + * @param {Object.} values - The current variable list. + * @param {String} key - A key to retrieve the value. + * @return {String} The value or an empty string if not found. + */ +const find_value = (values, key) => { + key = key.toLowerCase(); + + for (const [_key, value] of Object.entries(values)) { + if (_key.toLowerCase() === key) { + return value; + } + } + + return ''; +}; + +/** + * @todo Add the following Tools menu items once Bug 1272869 is solved. +browser.menus.create({ + contexts: ['tools_menu'], + title: browser.i18n.getMessage('copy_build_info'), + onclick: () => handle_command('copy_build_info'), +}); + +browser.menus.create({ + contexts: ['tools_menu'], + title: browser.i18n.getMessage('copy_extension_list'), + onclick: () => handle_command('copy_extension_list'), +}); + +browser.menus.create({ + contexts: ['tools_menu'], + type: 'separator', +}); + +browser.menus.create({ + contexts: ['tools_menu'], + title: browser.i18n.getMessage('insert_build_info'), + onclick: () => handle_command('insert_build_info'), +}); + +browser.menus.create({ + contexts: ['tools_menu'], + title: browser.i18n.getMessage('insert_extension_list'), + onclick: () => handle_command('insert_extension_list'), +}); + */ + +browser.menus.create({ + contexts: ['editable'], + title: browser.i18n.getMessage('insert_build_info_context'), + onclick: () => handle_command('insert_build_info'), +}); + +browser.menus.create({ + contexts: ['editable'], + title: browser.i18n.getMessage('insert_extension_list_context'), + onclick: () => handle_command('insert_extension_list'), +}); + +browser.storage.onChanged.addListener(async () => await update_titlebar()); +browser.windows.onCreated.addListener(async () => await update_titlebar()); +browser.windows.onRemoved.addListener(async () => await update_titlebar()); +browser.tabs.onCreated.addListener(async () => await update_titlebar()); +browser.tabs.onRemoved.addListener(async () => await update_titlebar()); diff --git a/extension/chrome.manifest b/extension/chrome.manifest deleted file mode 100644 index 0a94fc7..0000000 --- a/extension/chrome.manifest +++ /dev/null @@ -1,42 +0,0 @@ -content nightly chrome/content/ -skin nightly classic/1.0 chrome/skin/ - -locale nightly en-US chrome/locale/en-US/ -locale nightly ja chrome/locale/ja/ -locale nightly ja-JP-mac chrome/locale/ja-JP-mac/ -locale nightly pl chrome/locale/pl/ -locale nightly ru-RU chrome/locale/ru-RU/ -locale nightly sv-SE chrome/locale/sv-SE/ -locale nightly zh-CN chrome/locale/zh-CN/ - -resource nightly modules/ - -# about page -component {4cec494a-d33a-4ee7-83d6-461925b5d84b} components/aboutNightly.js -contract @mozilla.org/network/protocol/about;1?what=nightly {4cec494a-d33a-4ee7-83d6-461925b5d84b} - -# addon compatiblity component -component {126c18c5-386c-4c13-b59f-dc909e78aea0} components/nttAddonCompatibilityService.js -contract @mozilla.com/nightly/addoncompatibility;1 {126c18c5-386c-4c13-b59f-dc909e78aea0} - -# Shared chrome -override chrome://nightly/content/platform.js chrome://nightly/content/winPlatform.js os=winnt - -style chrome://browser/content/browser.xul chrome://nightly/skin/browser.css -style chrome://messenger/content/messenger.xul chrome://nightly/skin/browser.css -style chrome://navigator/content/navigator.xul chrome://nightly/skin/browser.css -style chrome://global/content/customizeToolbar.xul chrome://nightly/skin/browser.css - - -# Firefox chrome -overlay chrome://browser/content/browser.xul chrome://nightly/content/browserOverlay.xul application={ec8030f7-c20a-464f-9b0e-13a3a9e97384} - -# Thunderbird chrome -overlay chrome://messenger/content/messenger.xul chrome://nightly/content/messengerOverlay.xul application={3550f703-e582-4d05-9a08-453d09bdfdc6} - -# Suiterunner chrome -overlay chrome://navigator/content/navigator.xul chrome://nightly/content/suiteOverlay.xul application={92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a} - -# Songbird chrome -overlay chrome://songbird/content/xul/layoutBaseOverlay.xul chrome://nightly/content/songbirdOverlay.xul application=songbird@songbirdnest.com -override chrome://nightly/skin/aboutNightly/aboutNightly.css chrome://nightly/skin/aboutNightly/aboutNightly-sb.css application=songbird@songbirdnest.com diff --git a/extension/chrome/content/aboutNightly/aboutNightly.js b/extension/chrome/content/aboutNightly/aboutNightly.js deleted file mode 100644 index 4c60d38..0000000 --- a/extension/chrome/content/aboutNightly/aboutNightly.js +++ /dev/null @@ -1,98 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; - -const ADDON_ID = "{8620c15f-30dc-4dba-a131-7c5d20cf4a29}"; - - -function init() { - window.removeEventListener("load", init, false); - - try { - var { AddonManager: manager } = Cu.import("resource://gre/modules/AddonManager.jsm"); - } catch (e) { - var manager = ExtensionManager; - } - - manager.getAddonByID(ADDON_ID, fillContributorsCallback); -} - -function fillContributorsCallback(aAddon) { - appendToList("about", "about", [ aAddon.creator ], "label"); - appendToList("contributors", "contributorsList", aAddon.contributors, "li"); -} - -var ExtensionManager = { - getAddonByID: function (aID, aCallback) { - if (!aID || typeof aID !== "string") { - throw Components.Exception("aID must be a non-empty string", - Cr.NS_ERROR_INVALID_ARG); - } - - if (typeof aCallback !== "function") { - throw Components.Exception("aCallback must be a function", - Cr.NS_ERROR_INVALID_ARG); - } - - function EM_NS(aProperty) { - return "http://www.mozilla.org/2004/em-rdf#" + aProperty; - } - - var em = Cc['@mozilla.org/extensions/manager;1'] - .getService(Ci.nsIExtensionManager); - var rdfs = Cc["@mozilla.org/rdf/rdf-service;1"] - .getService(Ci.nsIRDFService); - var ds = em.datasource; - var extension = rdfs.GetResource("urn:mozilla:item:" + aID); - - var addon = { creator: {}, contributors: [] }; - - arc = rdfs.GetResource(EM_NS("creator")); - var creator = ds.GetTarget(extension, arc, true); - if (creator) { - addon.creator.name = creator.QueryInterface(Ci.nsIRDFLiteral).Value; - } - - arc = rdfs.GetResource(EM_NS("contributor")); - var contributors = ds.GetTargets(extension, arc, true); - if (contributors.hasMoreElements()) { - while (contributors.hasMoreElements()) { - addon.contributors.push({ - name: contributors.getNext().QueryInterface(Ci.nsIRDFLiteral).Value - }); - } - } - - aCallback(addon); - } -} - -function appendToList(aHeaderId, aNodeId, aItems, aEType) { - var header = document.getElementById(aHeaderId); - var node = document.getElementById(aNodeId); - - if (!aItems || aItems.length === 0) { - header.hidden = true; - return 0; - } - - aItems.forEach(function (aCurrentItem) { - var url = aCurrentItem.url; - var listElem = document.createElement(aEType); - var textContainer = listElem; - if (url) { - textContainer = document.createElement("a"); - listElem.appendChild(textContainer); - textContainer.href = url; - } - textContainer.textContent = aCurrentItem.name; - node.appendChild(listElem); - }); - - return aItems.length; -} - - -window.addEventListener("load", init, false); diff --git a/extension/chrome/content/aboutNightly/aboutNightly.xhtml b/extension/chrome/content/aboutNightly/aboutNightly.xhtml deleted file mode 100644 index 9b7dc39..0000000 --- a/extension/chrome/content/aboutNightly/aboutNightly.xhtml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - %htmlDTD; - - %brandDTD; - - %securityPrefsDTD; - - %aboutRightsDTD; -]> - - - - - - - About Nightly Test Tools - - - - - -

About Nightly Tester Tools

- -
- Author: -
- -
-

Contributors

- -
- -
-

Features

- - - -
- - - - - diff --git a/extension/chrome/content/brand/icon.png b/extension/chrome/content/brand/icon.png deleted file mode 100644 index 00886a6..0000000 Binary files a/extension/chrome/content/brand/icon.png and /dev/null differ diff --git a/extension/chrome/content/brand/logo.png b/extension/chrome/content/brand/logo.png deleted file mode 100644 index 18c58bb..0000000 Binary files a/extension/chrome/content/brand/logo.png and /dev/null differ diff --git a/extension/chrome/content/browser.js b/extension/chrome/content/browser.js deleted file mode 100644 index b79f8c9..0000000 --- a/extension/chrome/content/browser.js +++ /dev/null @@ -1,79 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var nightlyApp = { - -storedTitle: document.documentElement.getAttribute("titlemodifier"), - -get defaultTitle() { - var tabbrowser = document.getElementById("content"); - return tabbrowser.getWindowTitleForBrowser(tabbrowser.mCurrentBrowser); -}, - -get tabsCount() { - var tabbrowser = document.getElementById("content"); - return tabbrowser.visibleTabs ? tabbrowser.visibleTabs.length : tabbrowser.browsers.length; -}, -get tabTitle() { - var tabbrowser = document.getElementById("content"); - return tabbrowser.mCurrentBrowser.contentTitle; -}, - -init: function() -{ - var brandbundle = document.getElementById("bundle_brand"); - if (nightly.variables.name==null) - { - nightly.variables.name=brandbundle.getString("brandShortName"); - } - nightly.variables.brandname=brandbundle.getString("brandFullName"); - nightly.variables.defaulttitle=nightlyApp.storedTitle; - - var tabbrowser = document.getElementById("content"); - nightlyApp.oldUpdateTitlebar = tabbrowser.updateTitlebar; - - tabbrowser.updateTitlebar = nightly.updateTitlebar; - tabbrowser.addEventListener("DOMTitleChanged", nightly.updateTitlebar, false); -}, - -openURL: function(url) -{ - gBrowser.selectedTab = gBrowser.addTab(url); -}, - -openNotification: function(id, message, label, accessKey, callback) { - var action = { - label: label, - callback: callback, - accessKey: accessKey - }; - if (typeof PopupNotifications != "undefined") { - var options = { - timeout: Date.now() + 10000 - }; - - PopupNotifications.show(gBrowser.selectedBrowser, id, - message, "urlbar", action, null, options); - } else { - let nb = gBrowser.getNotificationBox(); - - nb.appendNotification( - message, id, - "chrome://nightly/content/brand/icon.png", - nb.PRIORITY_INFO_HIGH, [ action ]); - } -}, - -setCustomTitle: function(title) -{ - document.getElementById("content").ownerDocument.title = title; -}, - -setStandardTitle: function() -{ - var tabbrowser = document.getElementById("content"); - nightlyApp.oldUpdateTitlebar.call(tabbrowser); -}, - -} diff --git a/extension/chrome/content/browserOverlay.xul b/extension/chrome/content/browserOverlay.xul deleted file mode 100644 index 476403b..0000000 --- a/extension/chrome/content/browserOverlay.xul +++ /dev/null @@ -1,99 +0,0 @@ - - - - -%nightlyDTD; -]> - - - - - - - - + + + diff --git a/extension/menu.js b/extension/menu.js new file mode 100644 index 0000000..9086602 --- /dev/null +++ b/extension/menu.js @@ -0,0 +1,12 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +window.addEventListener('DOMContentLoaded', async event => { + localize_page(); +}); + +document.addEventListener('click', async event => { + await handle_command(event.target.dataset.command); + window.close(); +}); diff --git a/extension/modules/Logging.jsm b/extension/modules/Logging.jsm deleted file mode 100644 index 55eaf0a..0000000 --- a/extension/modules/Logging.jsm +++ /dev/null @@ -1,74 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -var EXPORTED_SYMBOLS = ["LOG", "WARN", "ERROR"]; - -const Cc = Components.classes; -const Ci = Components.interfaces; -const Cr = Components.results; - -var gLoggingEnabled = false; - -function logMessage(text, level) { - var caller = null; - try { - caller = Components.stack.caller.caller; - } - catch (e) { } - - var msg = Cc["@mozilla.org/scripterror;1"]. - createInstance(Ci.nsIScriptError); - if (caller) { - var filename = caller.filename; - var sourceLine = caller.sourceLine; - var lineNumber = caller.lineNumber; - } - else { - var filename = ""; - var sourceLine = ""; - var lineNumber = 0; - } - msg.init(text, filename, sourceLine, lineNumber, 0, - level, "XUL JavaScript"); - - var console = Cc["@mozilla.org/consoleservice;1"]. - getService(Ci.nsIConsoleService); - console.logMessage(msg); -} - -function ERROR(string) { - dump("NTT ERROR: " + string + "\n"); - logMessage("NTT: " + string, Ci.nsIScriptError.errorFlag); -} - -function WARN(string) { - dump("NTT WARN : " + string + "\n"); - logMessage("NTT: " + string, Ci.nsIScriptError.warningFlag); -} - -function LOG(string) { - if (gLoggingEnabled) { - dump("NTT LOG : " + string + "\n"); - - var caller = null; - try { - caller = Components.stack.caller; - } - catch (e) { } - - if (caller) - string += " (" + caller.filename + ":" + caller.lineNumber + ")"; - - var console = Cc["@mozilla.org/consoleservice;1"]. - getService(Ci.nsIConsoleService); - console.logStringMessage("NTT: " + string); - } -} - -var prefs = Cc["@mozilla.org/preferences-service;1"]. - getService(Ci.nsIPrefBranch); -try { - gLoggingEnabled = prefs.getBoolPref("nightly.logging"); -} -catch (e) { } diff --git a/extension/options.html b/extension/options.html new file mode 100644 index 0000000..e7ee92d --- /dev/null +++ b/extension/options.html @@ -0,0 +1,45 @@ + + + + + + + + +
+

+
+ + +
+
+ + +
+
+ + + + + + + + + + +
+
+
+ + + + diff --git a/extension/options.js b/extension/options.js new file mode 100644 index 0000000..41c58b4 --- /dev/null +++ b/extension/options.js @@ -0,0 +1,78 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const default_template = '(Build ${AppBuildID})'; +let enable_custom_title = false; +let custom_template = ''; +let $checkbox; +let $input; +let $tbody; + +/** + * Initialize the option view. + */ +const init_view = async () => { + $checkbox = document.querySelector('#enable_custom_title'); + $input = document.querySelector('#custom_template'); + $tbody = document.querySelector('#variable_tbody'); + + $checkbox.addEventListener('change', event => save_pref()); + $input.addEventListener('input', event => save_pref()); + + try { + const pref = await browser.storage.local.get(); + + $checkbox.checked = enable_custom_title = pref.enable_custom_title || false; + $input.value = custom_template = pref.custom_template || default_template; + } catch (ex) {} + + for (const [key, value] of Object.entries(await get_variable_values())) { + const $row = $tbody.insertRow(); + const $cell_key = $row.insertCell(); + const $cell_desc = $row.insertCell(); + const $cell_value = $row.insertCell(); + + $row.addEventListener('click', event => insert_or_remove_variable(key)); + + $cell_key.textContent = '${' + key + '}'; + $cell_desc.textContent = browser.i18n.getMessage(`variable_${key}`); + $cell_value.textContent = value || '(unknown)'; + } +}; + +/** + * Insert a variable into the custom template when a table row is clicked. If the template already contains the + * variable, remove it instead. + * @param {String} key - A variable name. + */ +const insert_or_remove_variable = key => { + const str = '${' + key + '}'; + + if ($input.value.includes(str)) { + $input.value = $input.value.replace(str, ''); + } else { + $input.value += ' ' + str; + } + + $input.value = $input.value.trim().replace(/\s{2,}/g, ' '); + + save_pref(); +}; + +/** + * Save the preference and update the window title bar in background. + */ +const save_pref = async () => { + enable_custom_title = $checkbox.checked; + custom_template = $input.value; + + try { + await browser.storage.local.set({ enable_custom_title, custom_template }); + } catch (ex) {} +}; + +window.addEventListener('DOMContentLoaded', async event => { + localize_page(); + init_view(); +}); diff --git a/extension/shared.js b/extension/shared.js new file mode 100644 index 0000000..5e2b706 --- /dev/null +++ b/extension/shared.js @@ -0,0 +1,113 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * Retrieve the current variable values from the runtime. + * @return {Object.} The values. + */ +const get_variable_values = async () => { + const browser_info = await browser.runtime.getBrowserInfo(); + const platform_info = await browser.runtime.getPlatformInfo(); + + return { + 'AppBuildID': browser_info.buildID, + // 'AppID', + // 'BrandName', + // 'Changeset', + // 'Compiler', + // 'DefaultTitle': (await browser.tabs.getCurrent()).title, + 'GeckoVersion': browser_info.version, + 'Locale': browser.i18n.getUILanguage(), + 'Name': browser_info.name, + 'OS': platform_info.os, + 'PlatformBuildID': browser_info.buildID, + 'PlatformVersion': browser_info.version, + 'Processor': platform_info.arch, + // 'Profile', + 'TabsCount': (await browser.tabs.query({})).length, + // 'TabTitle': (await browser.tabs.getCurrent()).title, + // 'Toolkit', + 'UserAgent': navigator.userAgent, + 'Vendor': browser_info.vendor, + 'Version': browser_info.version, + }; +}; + +/** + * Localize the current HTML page. Each localizable element must specify a message name with the `data-i18n` attribute. + */ +const localize_page = () => { + document.querySelectorAll('[data-i18n]').forEach($node => { + $node.textContent = browser.i18n.getMessage($node.dataset.i18n); + }); +}; + +/** + * Send a message to the content script. + * @param {String} command - A distinguishable command name. + * @param {*} value - Any value to be passed to content. + */ +const send_message = async (command, value) => { + const tabs = await browser.tabs.query({ active: true, currentWindow: true }); + + browser.tabs.sendMessage(tabs[0].id, { command, value }); +}; + +/** + * Copy a string to the system clipboard. + * @param {String} str - A string to be copied. + */ +const copy_to_clipboard = str => { + const $textbox = document.body.appendChild(document.createElement('textarea')); + + $textbox.value = str; + $textbox.select(); + document.execCommand('Copy'); + $textbox.remove(); +}; + +/** + * Insert a string into the focused textbox, either or