зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound. a=merge on a CLOSED TREE
This commit is contained in:
Коммит
a6f88b57a1
|
@ -40,6 +40,13 @@ widget/tests/.*
|
|||
xpcom/glue/tests/.*
|
||||
xpcom/tests/.*
|
||||
|
||||
# Generated by protobuf
|
||||
.*/.*.pb.h
|
||||
.*/.*.pb.cc
|
||||
|
||||
# Autogenerated file
|
||||
media/mp4parse-rust/mp4parse.h
|
||||
|
||||
# Generated from ./tools/rewriting/ThirdPartyPaths.txt
|
||||
# awk '{print ""$1".*"}' ./tools/rewriting/ThirdPartyPaths.txt
|
||||
browser/components/translation/cld2/.*
|
||||
|
@ -97,7 +104,7 @@ js/src/vtune/legacy/.*
|
|||
media/ffvpx/.*
|
||||
media/gmp-clearkey/0.1/openaes/.*
|
||||
media/kiss_fft/.*
|
||||
media/libav/.*
|
||||
media/libaom/.*
|
||||
media/libcubeb/.*
|
||||
media/libjpeg/.*
|
||||
media/libmkv/.*
|
||||
|
@ -115,6 +122,7 @@ media/libwebp/.*
|
|||
media/libyuv/.*
|
||||
media/mtransport/third_party/.*
|
||||
media/openmax_dl/.*
|
||||
media/openmax_il/.*
|
||||
media/webrtc/signaling/src/sdp/sipcc/.*
|
||||
media/webrtc/trunk/.*
|
||||
mfbt/decimal/.*
|
||||
|
@ -156,6 +164,7 @@ toolkit/components/url-classifier/protobuf/.*
|
|||
toolkit/crashreporter/google-breakpad/.*
|
||||
toolkit/recordreplay/udis86/.*
|
||||
tools/fuzzing/libfuzzer/.*
|
||||
tools/profiler/core/vtune/.*
|
||||
xpcom/build/mach_override.c
|
||||
xpcom/build/mach_override.h
|
||||
xpcom/io/crc32c.c
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <type_traits>
|
||||
|
||||
// clang-format off
|
||||
/******************************************************************************
|
||||
The following accessible states aren't translated, just ignored:
|
||||
STATE_READONLY: Supported indirectly via EXT_STATE_EDITABLE
|
||||
|
@ -36,6 +37,7 @@ The following ATK states are not supported:
|
|||
ATK_STATE_TRUNCATED: No clear use case. Indicates that an object's onscreen content is truncated,
|
||||
e.g. a text value in a spreadsheet cell. No IA2 state.
|
||||
******************************************************************************/
|
||||
// clang-format on
|
||||
|
||||
enum EStateMapEntryType {
|
||||
kMapDirectly,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
// clang-format off
|
||||
/**
|
||||
* Usage: declare the macro ROLE()with the following arguments:
|
||||
* ROLE(geckoRole, stringRole, atkRole, macRole, msaaRole, ia2Role, nameRule)
|
||||
|
@ -1629,3 +1630,4 @@ ROLE(FORM_LANDMARK,
|
|||
IA2_ROLE_FORM,
|
||||
java::SessionAccessibility::CLASSNAME_VIEW,
|
||||
eNoNameRule)
|
||||
// clang-format on
|
||||
|
|
|
@ -1518,7 +1518,9 @@ HyperTextAccessible::GetCaretRect(nsIWidget** aWidget)
|
|||
|
||||
LayoutDeviceIntRect caretRect = LayoutDeviceIntRect::FromUnknownRect(
|
||||
rect.ToOutsidePixels(frame->PresContext()->AppUnitsPerDevPixel()));
|
||||
// clang-format off
|
||||
// ((content screen origin) - (content offset in the widget)) = widget origin on the screen
|
||||
// clang-format on
|
||||
caretRect.MoveBy((*aWidget)->WidgetToScreenOffset() - (*aWidget)->GetClientOffset());
|
||||
|
||||
// Correct for character size, so that caret always matches the size of
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
/* clang-format off */
|
||||
/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* clang-format on */
|
||||
/* 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/. */
|
||||
|
|
|
@ -651,12 +651,14 @@ AccessibleWrap::get_accFocus(
|
|||
|
||||
VariantInit(pvarChild);
|
||||
|
||||
// clang-format off
|
||||
// VT_EMPTY: None. This object does not have the keyboard focus itself
|
||||
// and does not contain a child that has the keyboard focus.
|
||||
// VT_I4: lVal is CHILDID_SELF. The object itself has the keyboard focus.
|
||||
// VT_I4: lVal contains the child ID of the child element with the keyboard focus.
|
||||
// VT_DISPATCH: pdispVal member is the address of the IDispatch interface
|
||||
// for the child object with the keyboard focus.
|
||||
// clang-format on
|
||||
if (IsDefunct())
|
||||
return CO_E_OBJNOTCONNECTED;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++ final; tab-width: 2 final; indent-tabs-mode: nil final; c-basic-offset: 2 -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
module.exports = {
|
||||
// When adding items to this file please check for effects on sub-directories.
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
|
@ -15,6 +17,11 @@ module.exports = {
|
|||
"promise", // require("eslint-plugin-promise")
|
||||
"react" // require("eslint-plugin-react")
|
||||
],
|
||||
"settings": {
|
||||
"react": {
|
||||
"version": "16.2.0"
|
||||
}
|
||||
},
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:mozilla/recommended" // require("eslint-plugin-mozilla")
|
||||
|
|
|
@ -30,23 +30,4 @@ Name | Used for | Type | Example value
|
|||
}
|
||||
```
|
||||
|
||||
## Admin Interface
|
||||
|
||||
* Navigate to `about:newtab#asrouter`
|
||||
* See all available messages and message providers
|
||||
* Block, unblock or force show a specific message
|
||||
|
||||
## Snippet Preview
|
||||
|
||||
* Whitelist the provider host that will serve the messages
|
||||
* In `about:config`, `browser.newtab.activity-stream.asrouter.whitelistHosts` can contain a array of hosts
|
||||
* Example value `["gist.github.com", "gist.githubusercontent.com", "localhost:8000"]`
|
||||
* Errors are surfaced in the `Console` tab of the `Browser Toolbox` ([read how to enable](https://developer.mozilla.org/en-US/docs/Tools/Browser_Toolbox))
|
||||
* Navigate to `about:newtab?endpoint=<URL>`
|
||||
* Example `https://gist.githubusercontent.com/piatra/70234f08696c0a0509d7ba5568cd830f/raw/68370f34abc134142c64b6f0a9b9258a06de7aa3/messages.json`
|
||||
* URL should be from an endpoint that was just whitelisted
|
||||
* The snippet preview should imediately load
|
||||
* The endpoint must be HTTPS, the host must be whitelisted
|
||||
* Errors are surfaced in the `Console` tab of the `Browser Toolbox`
|
||||
|
||||
### [Snippet message format documentation](https://github.com/mozilla/activity-stream/blob/master/content-src/asrouter/schemas/message-format.md)
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
# Using ASRouter Devtools
|
||||
|
||||
## How to enable ASRouter devtools
|
||||
- In `about:config`, set `browser.newtabpage.activity-stream.asrouter.devtoolsEnabled` to `true`
|
||||
- Visit `about:newtab#asrouter` to see the devtools.
|
||||
|
||||
## Overview of ASRouter devtools
|
||||
|
||||
![Devtools image](./debugging-guide.png)
|
||||
|
||||
## How to enable/disable a provider
|
||||
|
||||
To enable a provider such as `snippets`, Look at the list of "Message Providers" at the top of the page. Make sure the checkbox is checked next to the provider you want to enable.
|
||||
|
||||
To disable it, uncheck the checkbox. You should see a red label indicating the provider is now disabled.
|
||||
|
||||
## How to see all messages from a provider
|
||||
|
||||
(Only available in Firefox 65+)
|
||||
|
||||
In order to see all active messages for a current provider such as `snippets`, use the drop down selector under the "Messages" section. Select the name of the provider you are interested in.
|
||||
|
||||
The messages on the page should now be filtered to include only the provider you selected.
|
||||
|
||||
## How to test telemetry pings
|
||||
|
||||
To test telemetry pings, complete the the following steps:
|
||||
|
||||
- In about:config, set:
|
||||
- `browser.newtabpage.activity-stream.telemetry` to `true`
|
||||
- `browser.ping-centre.log` to `true`
|
||||
- Open the Browser Toolbox devtools (Tools > Developer > Browser Toolbox) and switch to the console tab. Add a filter for for `activity-stream-router` to only display relevant pings:
|
||||
|
||||
![Devtools telemetry pong](./telemetry-screenshot.png)
|
||||
|
||||
You should now see pings show up as you view/interact with ASR messages/templates.
|
||||
|
||||
## Snippets debugging
|
||||
|
||||
### How to test legacy snippets
|
||||
|
||||
To make sure the legacy snippets system is still running properly, do the following:
|
||||
|
||||
- Load test data for legacy snippets. In about:config, set `browser.aboutHomeSnippets.updateUrl` to `https://snippets.allizom.org/%STARTPAGE_VERSION%/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/`
|
||||
- Disable ASR snippets
|
||||
- set up your ASR devtools (see steps above)
|
||||
- visit `about:newtab#asrouter`
|
||||
- Uncheck the checkbox next to snippets
|
||||
- Check `about:newtab` to make sure legacy snippets are loading
|
||||
- visit `about:newtab`
|
||||
- Type gSnippetsMap.clear() into the devtools console and refresh the page
|
||||
- Open the devtools again
|
||||
- Ensure you see the message “Legacy snippets: Successfully added snippets.”
|
||||
- Ensure you visually see snippets on the page
|
||||
|
||||
### How to view preview URLs
|
||||
|
||||
Follow these steps to view preview URLs (e.g. `about:newtab?endpoint=https://gist.githubusercontent.com/piatra/d193ca7e0f513cc19fc6a1d396c214f7/raw/8bcaf9548212e4c613577e839198cc14e7317630/newsletter_snippet.json`)
|
||||
|
||||
#### IMPORTANT NOTES
|
||||
- Links to URLs starting with `about:newtab` cannot be clicked on directly. They must be copy and pasted into the address bar.
|
||||
- Previews should only be tested in `Firefox 64` and later.
|
||||
- The endpoint must be HTTPS, the host must be whitelisted (see testing instructions below)
|
||||
- Errors are surfaced in the `Console` tab of the `Browser Toolbox`
|
||||
|
||||
#### Testing instructions
|
||||
- If your endpoint URL has a host name of `snippets-admin.mozilla.org`, you can paste the URL into the address bar view it without any further steps.
|
||||
- If your endpoint URL starts with some other host name, it must be **whitelisted**. Open the Browser Toolbox devtools (Tools > Developer > Browser Toolbox) and paste the following code (where `gist.githubusercontent.com` is the hostname of your endpoint URL):
|
||||
```js
|
||||
Services.prefs.setStringPref(
|
||||
"browser.newtab.activity-stream.asrouter.whitelistHosts",
|
||||
"[\"gist.githubusercontent.com\"]"
|
||||
);
|
||||
```
|
||||
- Restart the browser
|
||||
- You should now be able to paste the URL into the address bar and view it.
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 242 KiB |
Двоичные данные
browser/components/newtab/content-src/asrouter/docs/telemetry-screenshot.png
Normal file
Двоичные данные
browser/components/newtab/content-src/asrouter/docs/telemetry-screenshot.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 102 KiB |
|
@ -264,7 +264,7 @@ export class ASRouterAdmin extends React.PureComponent {
|
|||
|
||||
let label = "local";
|
||||
if (provider.type === "remote") {
|
||||
label = (<span>endpoint (<a className="providerUrl" target="_blank" href={info.url}>{info.url}</a>)</span>);
|
||||
label = (<span>endpoint (<a className="providerUrl" target="_blank" href={info.url} rel="noopener noreferrer">{info.url}</a>)</span>);
|
||||
} else if (provider.type === "remote-settings") {
|
||||
label = `remote settings (${provider.bucket})`;
|
||||
}
|
||||
|
@ -355,6 +355,13 @@ export class ASRouterAdmin extends React.PureComponent {
|
|||
render() {
|
||||
return (<div className="asrouter-admin outer-wrapper">
|
||||
<h1>AS Router Admin</h1>
|
||||
<p className="helpLink">
|
||||
<span className="icon icon-small-spacer icon-info" />
|
||||
{" "}
|
||||
<span>
|
||||
Need help using these tools? Check out our <a target="blank" href="https://github.com/mozilla/activity-stream/blob/master/content-src/asrouter/docs/debugging-docs.md">documentation</a>
|
||||
</span>
|
||||
</p>
|
||||
<h2>Targeting Utilities</h2>
|
||||
<button className="button" onClick={this.expireCache}>Expire Cache</button> (This expires the cache in ASR Targeting for bookmarks and top sites)
|
||||
<h2>Message Providers <button title="Restore all provider settings that ship with Firefox" className="button" onClick={this.resetPref}>Restore default prefs</button></h2>
|
||||
|
|
|
@ -108,4 +108,15 @@
|
|||
.errorState {
|
||||
border: 1px solid $red-60;
|
||||
}
|
||||
|
||||
.helpLink {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
background: $yellow-50;
|
||||
border-radius: 3px;
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1595,6 +1595,13 @@ main {
|
|||
font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace; }
|
||||
.asrouter-admin .errorState {
|
||||
border: 1px solid #D70022; }
|
||||
.asrouter-admin .helpLink {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
background: #FFE900;
|
||||
border-radius: 3px; }
|
||||
.asrouter-admin .helpLink a {
|
||||
text-decoration: underline; }
|
||||
|
||||
.pocket-logged-in-cta {
|
||||
font-size: 13px;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1598,6 +1598,13 @@ main {
|
|||
font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace; }
|
||||
.asrouter-admin .errorState {
|
||||
border: 1px solid #D70022; }
|
||||
.asrouter-admin .helpLink {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
background: #FFE900;
|
||||
border-radius: 3px; }
|
||||
.asrouter-admin .helpLink a {
|
||||
text-decoration: underline; }
|
||||
|
||||
.pocket-logged-in-cta {
|
||||
font-size: 13px;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1595,6 +1595,13 @@ main {
|
|||
font-family: "SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace; }
|
||||
.asrouter-admin .errorState {
|
||||
border: 1px solid #D70022; }
|
||||
.asrouter-admin .helpLink {
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
background: #FFE900;
|
||||
border-radius: 3px; }
|
||||
.asrouter-admin .helpLink a {
|
||||
text-decoration: underline; }
|
||||
|
||||
.pocket-logged-in-cta {
|
||||
font-size: 13px;
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -2565,7 +2565,7 @@ class ASRouterAdmin extends react__WEBPACK_IMPORTED_MODULE_2___default.a.PureCom
|
|||
"endpoint (",
|
||||
react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
|
||||
"a",
|
||||
{ className: "providerUrl", target: "_blank", href: info.url },
|
||||
{ className: "providerUrl", target: "_blank", href: info.url, rel: "noopener noreferrer" },
|
||||
info.url
|
||||
),
|
||||
")"
|
||||
|
@ -2767,6 +2767,22 @@ class ASRouterAdmin extends react__WEBPACK_IMPORTED_MODULE_2___default.a.PureCom
|
|||
null,
|
||||
"AS Router Admin"
|
||||
),
|
||||
react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
|
||||
"p",
|
||||
{ className: "helpLink" },
|
||||
react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement("span", { className: "icon icon-small-spacer icon-info" }),
|
||||
" ",
|
||||
react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
|
||||
"span",
|
||||
null,
|
||||
"Need help using these tools? Check out our ",
|
||||
react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
|
||||
"a",
|
||||
{ target: "blank", href: "https://github.com/mozilla/activity-stream/blob/master/content-src/asrouter/docs/debugging-docs.md" },
|
||||
"documentation"
|
||||
)
|
||||
)
|
||||
),
|
||||
react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(
|
||||
"h2",
|
||||
null,
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -145,6 +145,7 @@ pocket_read_more=المواضيع الشائعة:
|
|||
pocket_read_even_more=اعرض المزيد من الأخبار
|
||||
pocket_more_reccommendations=مقترحات أخرى
|
||||
pocket_learn_more=اطّلع على المزيد
|
||||
pocket_how_it_works=آلية العمل
|
||||
pocket_cta_button=نزِّل بوكِت
|
||||
pocket_cta_text=احفظ القصص التي تحبّها في بوكِت، وزوّد عقلك بمقالات رائعة.
|
||||
|
||||
|
|
|
@ -143,9 +143,9 @@ pocket_read_more=Beliebte Themen:
|
|||
# LOCALIZATION NOTE (pocket_read_even_more): This is shown as a link at the
|
||||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Weitere Nachrichten ansehen
|
||||
|
||||
pocket_more_reccommendations=Mehr Empfehlungen
|
||||
pocket_learn_more=Weitere Informationen
|
||||
pocket_how_it_works=Wie es funktioniert
|
||||
pocket_cta_button=Pocket holen
|
||||
pocket_cta_text=Speichern Sie Ihre Lieblingstexte in Pocket und gewinnen Sie gedankenreiche Einblicke durch faszinierende Texte.
|
||||
|
||||
|
@ -196,7 +196,6 @@ firstrun_form_header=E-Mail-Adresse eingeben
|
|||
firstrun_form_sub_header=um sich bei Firefox Sync anzumelden.
|
||||
|
||||
firstrun_email_input_placeholder=E-Mail
|
||||
|
||||
firstrun_invalid_input=Gültige E-Mail-Adresse erforderlich
|
||||
|
||||
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and
|
||||
|
@ -207,3 +206,6 @@ firstrun_privacy_notice=Datenschutzhinweis
|
|||
|
||||
firstrun_continue_to_login=Weiter
|
||||
firstrun_skip_login=Diesen Schritt überspringen
|
||||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Menü öffnen
|
||||
|
|
|
@ -144,6 +144,7 @@ pocket_read_more=Temas populares:
|
|||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Ver máis historias
|
||||
pocket_more_reccommendations=Máis recomendacións
|
||||
pocket_learn_more=Máis información
|
||||
pocket_how_it_works=Como funciona
|
||||
pocket_cta_button=Obter Pocket
|
||||
pocket_cta_text=Garde no Pocket as historias que lle gusten, e alimente a súa imaxinación con lecturas fascinantes.
|
||||
|
|
|
@ -58,7 +58,7 @@ menu_action_open_file=ფაილის გახსნა
|
|||
# LOCALIZATION NOTE (menu_action_copy_download_link, menu_action_go_to_download_page):
|
||||
# "Download" here, in both cases, is not a verb, it is a noun. As in, "Copy the
|
||||
# link that belongs to this downloaded item"
|
||||
menu_action_copy_download_link=ჩამოტვირთვის ბმულის დაკოპირება
|
||||
menu_action_copy_download_link=ჩამოტვირთვის ბმულის ასლი
|
||||
menu_action_go_to_download_page=გადასვლა ჩამოტვირთვის გვერდზე
|
||||
menu_action_remove_download=ისტორიიდან ამოშლა
|
||||
|
||||
|
|
|
@ -143,7 +143,9 @@ pocket_read_more=Tèmas populars :
|
|||
# LOCALIZATION NOTE (pocket_read_even_more): This is shown as a link at the
|
||||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Veire mai d’articles
|
||||
pocket_more_reccommendations=Mai de recomandacions
|
||||
pocket_learn_more=Ne saber mai
|
||||
pocket_cta_button=Installar Pocket
|
||||
|
||||
highlights_empty_state=Començatz de navegar e aquí vos mostrarem los melhors articles, vidèos e autras paginas qu’avètz visitadas o apondudas als marcapaginas.
|
||||
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
newtab_page_title=Tab mới
|
||||
newtab_page_title=Thẻ mới
|
||||
|
||||
header_top_sites=Trang web hàng đầu
|
||||
header_highlights=Nổi bật
|
||||
|
@ -9,9 +9,11 @@ header_recommended_by=Được đề nghị bởi {provider}
|
|||
# LOCALIZATION NOTE(context_menu_button_sr): This is for screen readers when
|
||||
# the context menu button is focused/active. Title is the label or hostname of
|
||||
# the site.
|
||||
context_menu_button_sr=Mở bảng chọn ngữ cảnh cho {title}
|
||||
|
||||
# LOCALIZATION NOTE(section_context_menu_button_sr): This is for screen readers when
|
||||
# the section edit context menu button is focused/active.
|
||||
section_context_menu_button_sr=Mở bảng chọn phần ngữ cảnh
|
||||
|
||||
# LOCALIZATION NOTE (type_label_*): These labels are associated to pages to give
|
||||
# context on how the element is related to the user, e.g. type indicates that
|
||||
|
@ -47,6 +49,7 @@ menu_action_archive_pocket=Lưu trữ trong Pocket
|
|||
# found in the context menu of an item that has been downloaded. The intention behind
|
||||
# "this action" is that it will show where the downloaded file exists on the file system
|
||||
# for each operating system.
|
||||
menu_action_show_file_mac_os=Hiển thị trong Finder
|
||||
menu_action_show_file_windows=Mở thư mục chứa
|
||||
menu_action_show_file_linux=Mở thư mục chứa
|
||||
menu_action_show_file_default=Hiện tập tin
|
||||
|
@ -91,14 +94,18 @@ prefs_home_description=Chọn nội dung mà bạn muốn thêm vào trang chủ
|
|||
# LOCALIZATION NOTE (prefs_section_rows_option): This is a semi-colon list of
|
||||
# plural forms used in a drop down of multiple row options (1 row, 2 rows).
|
||||
# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
prefs_section_rows_option={num} hàng
|
||||
prefs_search_header=Tìm kiếm web
|
||||
prefs_topsites_description=Những trang bạn truy cập nhiều nhất
|
||||
prefs_topstories_description2=Nội dung tuyệt vời từ trên web, được cá nhân hóa cho bạn
|
||||
prefs_topstories_options_sponsored_label=Bài viết quảng cáo
|
||||
prefs_topstories_sponsored_learn_more=Tìm hiểu thêm
|
||||
prefs_highlights_description=Một lựa chọn các trang web mà bạn đã lưu hoặc truy cập
|
||||
prefs_highlights_options_visited_label=Trang đã xem
|
||||
prefs_highlights_options_download_label=Tải xuống gần đây nhất
|
||||
prefs_highlights_options_pocket_label=Trang đã được lưu vào Pocket
|
||||
prefs_snippets_description=Cập nhật từ Mozilla và Firefox
|
||||
settings_pane_button_label=Tùy biến trang Tab mới
|
||||
settings_pane_button_label=Tùy biến trang Thẻ mới
|
||||
settings_pane_topsites_header=Các trang Web hàng đầu
|
||||
settings_pane_highlights_header=Nổi bật
|
||||
settings_pane_highlights_options_bookmarks=Trang đánh dấu
|
||||
|
@ -136,14 +143,17 @@ pocket_read_more=Các chủ đề phổ biến:
|
|||
# LOCALIZATION NOTE (pocket_read_even_more): This is shown as a link at the
|
||||
# end of the list of popular topic links.
|
||||
pocket_read_even_more=Xem nhiều câu chuyện hơn
|
||||
|
||||
pocket_more_reccommendations=Nhiều khuyến nghị hơn
|
||||
pocket_learn_more=Tìm hiểu thêm
|
||||
pocket_how_it_works=Nó hoạt động như thế nào
|
||||
pocket_cta_button=Nhận Pocket
|
||||
pocket_cta_text=Lưu những câu chuyện bạn yêu thích trong Pocket và vui vẻ khi đọc chúng.
|
||||
|
||||
highlights_empty_state=Bắt đầu duyệt web và chúng tôi sẽ hiển thị một số bài báo, video, và các trang khác mà bạn vừa truy cập hoặc đã đánh dấu tại đây.
|
||||
# LOCALIZATION NOTE (topstories_empty_state): When there are no recommendations,
|
||||
# in the space that would have shown a few stories, this is shown instead.
|
||||
# {provider} is replaced by the name of the content provider for this section.
|
||||
topstories_empty_state=Bạn đã bắt kịp. Kiểm tra lại sau để biết thêm các câu chuyện hàng đầu từ {provider}. Không muốn đợi? Chọn một chủ đề phổ biến để tìm thêm những câu chuyện tuyệt vời từ khắp nơi trên web.
|
||||
|
||||
# LOCALIZATION NOTE (manual_migration_explanation2): This message is shown to encourage users to
|
||||
# import their browser profile from another browser they might be using.
|
||||
|
@ -186,13 +196,16 @@ firstrun_form_header=Nhập email của bạn
|
|||
firstrun_form_sub_header=để tiếp tục với Trình đồng bộ Firefox
|
||||
|
||||
firstrun_email_input_placeholder=Email
|
||||
|
||||
firstrun_invalid_input=Yêu cầu email hợp lệ
|
||||
|
||||
# LOCALIZATION NOTE (firstrun_extra_legal_links): {terms} is equal to firstrun_terms_of_service, and
|
||||
# {privacy} is equal to firstrun_privacy_notice. {terms} and {privacy} are clickable links.
|
||||
firstrun_extra_legal_links=Bằng cách tiếp tục, bạn đồng ý với {terms} và {privacy}.
|
||||
firstrun_terms_of_service=Điều khoản dịch vụ
|
||||
firstrun_privacy_notice=Thông báo bảo mật
|
||||
|
||||
firstrun_continue_to_login=Tiếp tục
|
||||
firstrun_skip_login=Bỏ qua bước này
|
||||
|
||||
# LOCALIZATION NOTE (context_menu_title): Action tooltip to open a context menu
|
||||
context_menu_title=Mở bảng chọn
|
||||
|
|
|
@ -23,4 +23,5 @@ cd /mozilla-central && ./mach build \
|
|||
browser/components/enterprisepolicies/tests/browser/browser_policy_set_homepage.js \
|
||||
browser/components/preferences/in-content/tests/browser_search_subdialogs_within_preferences_1.js \
|
||||
&& ! grep -q TEST-UNEXPECTED test_run_log \
|
||||
&& ! ./mach test all_files_referenced | grep activity-stream
|
||||
&& ! ./mach test all_files_referenced | grep activity-stream \
|
||||
&& RUN_FIND_DUPES=1 ./mach package
|
||||
|
|
|
@ -123,6 +123,30 @@
|
|||
"integrity": "sha512-gqmspPZOMW3MIRb9HlrnbZHXI1/KHTOroBwN1NcLL6pWxzqzEKGvRTq0W/PxS45OtQGbaFikSQpkS5zbnsQm2w==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/polyfill": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.0.0.tgz",
|
||||
"integrity": "sha512-dnrMRkyyr74CRelJwvgnnSUDh2ge2NCTyHVwpOdvRMHtJUyxLtMAfhBN3s64pY41zdw0kgiLPh6S20eb1NcX6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-js": "^2.5.7",
|
||||
"regenerator-runtime": "^0.11.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "2.5.7",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
|
||||
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==",
|
||||
"dev": true
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
|
||||
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.1.2.tgz",
|
||||
|
@ -509,9 +533,9 @@
|
|||
}
|
||||
},
|
||||
"acorn": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz",
|
||||
"integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==",
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz",
|
||||
"integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==",
|
||||
"dev": true
|
||||
},
|
||||
"acorn-dynamic-import": {
|
||||
|
@ -521,8 +545,22 @@
|
|||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "5.7.3",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
|
||||
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"acorn-jsx": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz",
|
||||
"integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==",
|
||||
"dev": true
|
||||
},
|
||||
"after": {
|
||||
"version": "0.8.2",
|
||||
"resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
|
||||
|
@ -558,12 +596,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ajv-keywords": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz",
|
||||
"integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=",
|
||||
"dev": true
|
||||
},
|
||||
"amdefine": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
|
||||
|
@ -890,6 +922,32 @@
|
|||
"source-map": "^0.5.7"
|
||||
}
|
||||
},
|
||||
"babel-eslint": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz",
|
||||
"integrity": "sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"@babel/parser": "^7.0.0",
|
||||
"@babel/traverse": "^7.0.0",
|
||||
"@babel/types": "^7.0.0",
|
||||
"eslint-scope": "3.7.1",
|
||||
"eslint-visitor-keys": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-scope": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
|
||||
"integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esrecurse": "^4.1.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-generator": {
|
||||
"version": "6.26.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
|
||||
|
@ -1154,31 +1212,6 @@
|
|||
"babel-types": "^6.24.1"
|
||||
}
|
||||
},
|
||||
"babel-polyfill": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz",
|
||||
"integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-runtime": "^6.26.0",
|
||||
"core-js": "^2.5.0",
|
||||
"regenerator-runtime": "^0.10.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": {
|
||||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.5.tgz",
|
||||
"integrity": "sha1-sU3ek2xkDAV5prUMq8wTLdYSfjs=",
|
||||
"dev": true
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.10.5",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz",
|
||||
"integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-preset-flow": {
|
||||
"version": "6.23.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz",
|
||||
|
@ -1825,9 +1858,9 @@
|
|||
}
|
||||
},
|
||||
"chardet": {
|
||||
"version": "0.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
|
||||
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=",
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
|
||||
"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
|
||||
"dev": true
|
||||
},
|
||||
"check-error": {
|
||||
|
@ -3102,57 +3135,69 @@
|
|||
}
|
||||
},
|
||||
"eslint": {
|
||||
"version": "4.19.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz",
|
||||
"integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==",
|
||||
"version": "5.9.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-5.9.0.tgz",
|
||||
"integrity": "sha512-g4KWpPdqN0nth+goDNICNXGfJF7nNnepthp46CAlJoJtC5K/cLu3NgCM3AHu1CkJ5Hzt9V0Y0PBAO6Ay/gGb+w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^5.3.0",
|
||||
"babel-code-frame": "^6.22.0",
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"ajv": "^6.5.3",
|
||||
"chalk": "^2.1.0",
|
||||
"concat-stream": "^1.6.0",
|
||||
"cross-spawn": "^5.1.0",
|
||||
"debug": "^3.1.0",
|
||||
"cross-spawn": "^6.0.5",
|
||||
"debug": "^4.0.1",
|
||||
"doctrine": "^2.1.0",
|
||||
"eslint-scope": "^3.7.1",
|
||||
"eslint-scope": "^4.0.0",
|
||||
"eslint-utils": "^1.3.1",
|
||||
"eslint-visitor-keys": "^1.0.0",
|
||||
"espree": "^3.5.4",
|
||||
"esquery": "^1.0.0",
|
||||
"espree": "^4.0.0",
|
||||
"esquery": "^1.0.1",
|
||||
"esutils": "^2.0.2",
|
||||
"file-entry-cache": "^2.0.0",
|
||||
"functional-red-black-tree": "^1.0.1",
|
||||
"glob": "^7.1.2",
|
||||
"globals": "^11.0.1",
|
||||
"ignore": "^3.3.3",
|
||||
"globals": "^11.7.0",
|
||||
"ignore": "^4.0.6",
|
||||
"imurmurhash": "^0.1.4",
|
||||
"inquirer": "^3.0.6",
|
||||
"is-resolvable": "^1.0.0",
|
||||
"js-yaml": "^3.9.1",
|
||||
"inquirer": "^6.1.0",
|
||||
"is-resolvable": "^1.1.0",
|
||||
"js-yaml": "^3.12.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"levn": "^0.3.0",
|
||||
"lodash": "^4.17.4",
|
||||
"minimatch": "^3.0.2",
|
||||
"lodash": "^4.17.5",
|
||||
"minimatch": "^3.0.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.8.2",
|
||||
"path-is-inside": "^1.0.2",
|
||||
"pluralize": "^7.0.0",
|
||||
"progress": "^2.0.0",
|
||||
"regexpp": "^1.0.1",
|
||||
"regexpp": "^2.0.1",
|
||||
"require-uncached": "^1.0.3",
|
||||
"semver": "^5.3.0",
|
||||
"semver": "^5.5.1",
|
||||
"strip-ansi": "^4.0.0",
|
||||
"strip-json-comments": "~2.0.1",
|
||||
"table": "4.0.2",
|
||||
"text-table": "~0.2.0"
|
||||
"strip-json-comments": "^2.0.1",
|
||||
"table": "^5.0.2",
|
||||
"text-table": "^0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "5.5.3",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz",
|
||||
"integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==",
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.0.4.tgz",
|
||||
"integrity": "sha512-VY4i5EKSKkofY2I+6QLTbTTN/UvEQPCo6eiwzzSaSWfpaDhOmStMCMod6wmuPciNq+XS0faCglFu2lHZpdHUtg==",
|
||||
"dev": true
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.5.5",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz",
|
||||
"integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"ansi-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||
|
@ -3179,48 +3224,49 @@
|
|||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"cross-spawn": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
|
||||
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
"nice-try": "^1.0.4",
|
||||
"path-key": "^2.0.1",
|
||||
"semver": "^5.5.0",
|
||||
"shebang-command": "^1.2.0",
|
||||
"which": "^1.2.9"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
|
||||
"integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"espree": {
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
|
||||
"integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-4.1.0.tgz",
|
||||
"integrity": "sha512-I5BycZW6FCVIub93TeVY1s7vjhP9CY6cXCznIRfiig7nRviKZYdRnj/sHEWC6A7WE9RDWOFq9+7OsWSYz8qv2w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^5.5.0",
|
||||
"acorn-jsx": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn-jsx": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
|
||||
"integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^3.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
|
||||
"integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
"acorn": "^6.0.2",
|
||||
"acorn-jsx": "^5.0.0",
|
||||
"eslint-visitor-keys": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
|
||||
"dev": true
|
||||
},
|
||||
"globals": {
|
||||
"version": "11.5.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.5.0.tgz",
|
||||
"integrity": "sha512-hYyf+kI8dm3nORsiiXUQigOU62hDLfJ9G01uyGMxhc6BKsircrUhC4uJPQPUSuq2GrTmiiEt7ewxlMdBewfmKQ==",
|
||||
"version": "11.9.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz",
|
||||
"integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==",
|
||||
"dev": true
|
||||
},
|
||||
"has-flag": {
|
||||
|
@ -3229,6 +3275,46 @@
|
|||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
},
|
||||
"ignore": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
|
||||
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
|
||||
"dev": true
|
||||
},
|
||||
"is-resolvable": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
|
||||
"integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
|
||||
"integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.6.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
|
||||
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||
|
@ -3239,9 +3325,9 @@
|
|||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
|
@ -3260,9 +3346,9 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"resolve": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
|
||||
"integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
|
||||
"integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "^1.0.5"
|
||||
|
@ -3311,9 +3397,9 @@
|
|||
}
|
||||
},
|
||||
"eslint-plugin-import": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.11.0.tgz",
|
||||
"integrity": "sha1-Fa7qN6Z0mdhI6OmBgG1GJ7VQOBY=",
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.14.0.tgz",
|
||||
"integrity": "sha512-FpuRtniD/AY6sXByma2Wr0TXvXJ4nA/2/04VPlfpmUDPOpOY264x+ILiwnrk/k4RINgDAyFZByxqPUbSQ5YE7g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"contains-path": "^0.1.0",
|
||||
|
@ -3381,9 +3467,9 @@
|
|||
}
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.7.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.7.1.tgz",
|
||||
"integrity": "sha512-c7rwLofp8g1U+h1KNyHL/jicrKg1Ek4q+Lr33AL65uZTinUZHe30D5HlyN5V9NW0JX1D5dXQ4jqW5l7Sy/kGfw==",
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
|
||||
"integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"path-parse": "^1.0.5"
|
||||
|
@ -3407,9 +3493,9 @@
|
|||
}
|
||||
},
|
||||
"eslint-plugin-mozilla": {
|
||||
"version": "0.16.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mozilla/-/eslint-plugin-mozilla-0.16.0.tgz",
|
||||
"integrity": "sha512-8yYv9zGVa3qpnSk1aiG1nrNHW3GrYV/AJXSNm9RnfLg6tudOMVSXsTjfHsCzC2+i4pJBechpnL5SNKgTOZ9Mdw==",
|
||||
"version": "0.16.3",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-mozilla/-/eslint-plugin-mozilla-0.16.3.tgz",
|
||||
"integrity": "sha512-ZvseeV3flenYTZP/B6SUTnwmfMkW99o0FNm3DaM4ZlyahTGXHepmAEPLkwIvY5eKrcRmo8On+kNmUqelDmxwKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"htmlparser2": "3.9.2",
|
||||
|
@ -3418,39 +3504,57 @@
|
|||
}
|
||||
},
|
||||
"eslint-plugin-no-unsanitized": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-3.0.0.tgz",
|
||||
"integrity": "sha1-FEi1LN14cfF0PCkAEXuwh8/nuAY=",
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-3.0.2.tgz",
|
||||
"integrity": "sha512-JnwpoH8Sv4QOjrTDutENBHzSnyYtspdjtglYtqUtAHe6f6LLKqykJle+UwFPg23GGwt5hI3amS9CRDezW8GAww==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-plugin-promise": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz",
|
||||
"integrity": "sha512-2WO+ZFh7vxUKRfR0cOIMrWgYKdR6S1AlOezw6pC52B6oYpd5WFghN+QHxvrRdZMtbo8h3dfUZ2o1rWb0UPbKtg==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz",
|
||||
"integrity": "sha512-Si16O0+Hqz1gDHsys6RtFRrW7cCTB6P7p3OJmKp3Y3dxpQE2qwOA7d3xnV+0mBmrPoi0RBnxlCKvqu70te6wjg==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-plugin-react": {
|
||||
"version": "7.7.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz",
|
||||
"integrity": "sha512-KC7Snr4YsWZD5flu6A5c0AcIZidzW3Exbqp7OT67OaD2AppJtlBr/GuPrW/vaQM/yfZotEvKAdrxrO+v8vwYJA==",
|
||||
"version": "7.11.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.11.1.tgz",
|
||||
"integrity": "sha512-cVVyMadRyW7qsIUh3FHp3u6QHNhOgVrLQYdQEB1bPWBsgbNCHdFAeNMquBMCcZJu59eNthX053L70l7gRt4SCw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"doctrine": "^2.0.2",
|
||||
"has": "^1.0.1",
|
||||
"array-includes": "^3.0.3",
|
||||
"doctrine": "^2.1.0",
|
||||
"has": "^1.0.3",
|
||||
"jsx-ast-utils": "^2.0.1",
|
||||
"prop-types": "^15.6.0"
|
||||
"prop-types": "^15.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"has": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
|
||||
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"function-bind": "^1.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz",
|
||||
"integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz",
|
||||
"integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"esrecurse": "^4.1.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"eslint-utils": {
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
|
||||
"integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-visitor-keys": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
|
||||
|
@ -3458,12 +3562,12 @@
|
|||
"dev": true
|
||||
},
|
||||
"eslint-watch": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-watch/-/eslint-watch-3.1.4.tgz",
|
||||
"integrity": "sha512-UpEszJuz/FBG3usSJkCy1p4iWMWmXFyMiCBnnJ9l1wXtMpEg6+mjnWM1MbStY5/QhuHEvW4M3AAadjUVv6FrAQ==",
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-watch/-/eslint-watch-4.0.2.tgz",
|
||||
"integrity": "sha512-kbso5+pd6tIwmnTidQfEQ5nRydYw4+8I+8h19yIG/RWcRi8H4TCLlBHwAFBDAmLE4dTkPkctpQQSP8x1nMyYqw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-polyfill": "^6.20.0",
|
||||
"@babel/polyfill": "^7.0.0-beta.51",
|
||||
"bluebird": "^3.5.1",
|
||||
"chalk": "^2.1.0",
|
||||
"chokidar": "^2.0.0",
|
||||
|
@ -3555,32 +3659,41 @@
|
|||
}
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz",
|
||||
"integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz",
|
||||
"integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"anymatch": "^2.0.0",
|
||||
"async-each": "^1.0.0",
|
||||
"braces": "^2.3.0",
|
||||
"fsevents": "^1.1.2",
|
||||
"fsevents": "^1.2.2",
|
||||
"glob-parent": "^3.1.0",
|
||||
"inherits": "^2.0.1",
|
||||
"is-binary-path": "^1.0.0",
|
||||
"is-glob": "^4.0.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"normalize-path": "^2.1.1",
|
||||
"path-is-absolute": "^1.0.0",
|
||||
"readdirp": "^2.0.0",
|
||||
"upath": "^1.0.0"
|
||||
"upath": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
|
||||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.0.0"
|
||||
"ms": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"expand-brackets": {
|
||||
|
@ -3874,9 +3987,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"source-map-support": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.5.tgz",
|
||||
"integrity": "sha512-mR7/Nd5l1z6g99010shcXJiNEaf3fEtmLhRB/sBcQVJGodcHCULPp2y4Sfa43Kv2zq7T+Izmfp/WHCR6dYkQCA==",
|
||||
"version": "0.5.9",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz",
|
||||
"integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
|
@ -3893,9 +4006,9 @@
|
|||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
|
@ -3913,6 +4026,12 @@
|
|||
"acorn-jsx": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "5.7.3",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
|
||||
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
|
||||
"dev": true
|
||||
},
|
||||
"acorn-jsx": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
|
||||
|
@ -3979,22 +4098,6 @@
|
|||
"es5-ext": "~0.10.14"
|
||||
}
|
||||
},
|
||||
"event-stream": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.6.tgz",
|
||||
"integrity": "sha512-dGXNg4F/FgVzlApjzItL+7naHutA3fDqbV/zAZqDDlXTjiMnQmZKu+prImWKszeBM5UQeGvAl3u1wBiKeDh61g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"duplexer": "^0.1.1",
|
||||
"flatmap-stream": "^0.1.0",
|
||||
"from": "^0.1.7",
|
||||
"map-stream": "0.0.7",
|
||||
"pause-stream": "^0.0.11",
|
||||
"split": "^1.0.1",
|
||||
"stream-combiner": "^0.2.2",
|
||||
"through": "^2.3.8"
|
||||
}
|
||||
},
|
||||
"eventemitter3": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
|
||||
|
@ -4155,14 +4258,25 @@
|
|||
}
|
||||
},
|
||||
"external-editor": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz",
|
||||
"integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==",
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
|
||||
"integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chardet": "^0.4.0",
|
||||
"iconv-lite": "^0.4.17",
|
||||
"chardet": "^0.7.0",
|
||||
"iconv-lite": "^0.4.24",
|
||||
"tmp": "^0.0.33"
|
||||
},
|
||||
"dependencies": {
|
||||
"iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"extglob": {
|
||||
|
@ -4366,12 +4480,6 @@
|
|||
"write": "^0.2.1"
|
||||
}
|
||||
},
|
||||
"flatmap-stream": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/flatmap-stream/-/flatmap-stream-0.1.1.tgz",
|
||||
"integrity": "sha512-lAq4tLbm3sidmdCN8G3ExaxH7cUCtP5mgDvrYowsx84dcYkJJ4I28N7gkxA6+YlSXzaGLJYIDEi9WGfXzMiXdw==",
|
||||
"dev": true
|
||||
},
|
||||
"fluent": {
|
||||
"version": "0.6.4",
|
||||
"resolved": "https://registry.npmjs.org/fluent/-/fluent-0.6.4.tgz",
|
||||
|
@ -4463,12 +4571,6 @@
|
|||
"map-cache": "^0.2.2"
|
||||
}
|
||||
},
|
||||
"from": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz",
|
||||
"integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=",
|
||||
"dev": true
|
||||
},
|
||||
"from2": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
|
||||
|
@ -5955,22 +6057,21 @@
|
|||
"dev": true
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz",
|
||||
"integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==",
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.0.tgz",
|
||||
"integrity": "sha512-QIEQG4YyQ2UYZGDC4srMZ7BjHOmNk1lR2JQj5UknBapklm6WHA+VVH7N+sUdX3A7NeCfGF8o4X1S3Ao7nAcIeg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-escapes": "^3.0.0",
|
||||
"chalk": "^2.0.0",
|
||||
"cli-cursor": "^2.1.0",
|
||||
"cli-width": "^2.0.0",
|
||||
"external-editor": "^2.0.4",
|
||||
"external-editor": "^3.0.0",
|
||||
"figures": "^2.0.0",
|
||||
"lodash": "^4.3.0",
|
||||
"lodash": "^4.17.10",
|
||||
"mute-stream": "0.0.7",
|
||||
"run-async": "^2.2.0",
|
||||
"rx-lite": "^4.0.8",
|
||||
"rx-lite-aggregates": "^4.0.8",
|
||||
"rxjs": "^6.1.0",
|
||||
"string-width": "^2.1.0",
|
||||
"strip-ansi": "^4.0.0",
|
||||
"through": "^2.3.6"
|
||||
|
@ -6018,9 +6119,9 @@
|
|||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
|
@ -7861,12 +7962,6 @@
|
|||
"integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
|
||||
"dev": true
|
||||
},
|
||||
"map-stream": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz",
|
||||
"integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=",
|
||||
"dev": true
|
||||
},
|
||||
"map-visit": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
|
||||
|
@ -8462,17 +8557,17 @@
|
|||
}
|
||||
},
|
||||
"npm-run-all": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.3.tgz",
|
||||
"integrity": "sha512-aOG0N3Eo/WW+q6sUIdzcV2COS8VnTZCmdji0VQIAZF3b+a3YWb0AD0vFIyjKec18A7beLGbaQ5jFTNI2bPt9Cg==",
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
|
||||
"integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.0",
|
||||
"chalk": "^2.1.0",
|
||||
"cross-spawn": "^6.0.4",
|
||||
"ansi-styles": "^3.2.1",
|
||||
"chalk": "^2.4.1",
|
||||
"cross-spawn": "^6.0.5",
|
||||
"memorystream": "^0.3.1",
|
||||
"minimatch": "^3.0.4",
|
||||
"ps-tree": "^1.1.0",
|
||||
"pidtree": "^0.3.0",
|
||||
"read-pkg": "^3.0.0",
|
||||
"shell-quote": "^1.6.1",
|
||||
"string.prototype.padend": "^3.0.0"
|
||||
|
@ -9080,15 +9175,6 @@
|
|||
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
|
||||
"dev": true
|
||||
},
|
||||
"pause-stream": {
|
||||
"version": "0.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
|
||||
"integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"through": "~2.3"
|
||||
}
|
||||
},
|
||||
"pbkdf2": {
|
||||
"version": "3.0.17",
|
||||
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz",
|
||||
|
@ -9342,6 +9428,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"pidtree": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz",
|
||||
"integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==",
|
||||
"dev": true
|
||||
},
|
||||
"pify": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
|
||||
|
@ -9444,9 +9536,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"progress": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
|
||||
"integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz",
|
||||
"integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==",
|
||||
"dev": true
|
||||
},
|
||||
"promise": {
|
||||
|
@ -9487,15 +9579,6 @@
|
|||
"integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
|
||||
"dev": true
|
||||
},
|
||||
"ps-tree": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz",
|
||||
"integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"event-stream": "~3.3.0"
|
||||
}
|
||||
},
|
||||
"pseudomap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
|
||||
|
@ -9958,9 +10041,9 @@
|
|||
}
|
||||
},
|
||||
"regexpp": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz",
|
||||
"integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
|
||||
"integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
|
||||
"dev": true
|
||||
},
|
||||
"remove-trailing-separator": {
|
||||
|
@ -10189,19 +10272,13 @@
|
|||
"aproba": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"rx-lite": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz",
|
||||
"integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=",
|
||||
"dev": true
|
||||
},
|
||||
"rx-lite-aggregates": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz",
|
||||
"integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=",
|
||||
"rxjs": {
|
||||
"version": "6.3.3",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
|
||||
"integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"rx-lite": "*"
|
||||
"tslib": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
|
@ -11409,15 +11486,6 @@
|
|||
"integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=",
|
||||
"dev": true
|
||||
},
|
||||
"split": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
|
||||
"integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"through": "2"
|
||||
}
|
||||
},
|
||||
"split-string": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
|
||||
|
@ -11520,16 +11588,6 @@
|
|||
"readable-stream": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"stream-combiner": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz",
|
||||
"integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"duplexer": "~0.1.1",
|
||||
"through": "~2.3.4"
|
||||
}
|
||||
},
|
||||
"stream-each": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
|
||||
|
@ -11744,53 +11802,40 @@
|
|||
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
|
||||
},
|
||||
"table": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz",
|
||||
"integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/table/-/table-5.1.0.tgz",
|
||||
"integrity": "sha512-e542in22ZLhD/fOIuXs/8yDZ9W61ltF8daM88rkRNtgTIct+vI2fTnAyu/Db2TCfEcI8i7mjZz6meLq0nW7TYg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^5.2.3",
|
||||
"ajv-keywords": "^2.1.0",
|
||||
"chalk": "^2.1.0",
|
||||
"lodash": "^4.17.4",
|
||||
"ajv": "^6.5.3",
|
||||
"lodash": "^4.17.10",
|
||||
"slice-ansi": "1.0.0",
|
||||
"string-width": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"ajv": {
|
||||
"version": "6.5.5",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz",
|
||||
"integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
"fast-deep-equal": "^2.0.1",
|
||||
"fast-json-stable-stringify": "^2.0.0",
|
||||
"json-schema-traverse": "^0.4.1",
|
||||
"uri-js": "^4.2.2"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
|
||||
"integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"fast-deep-equal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
"json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@octokit/rest": "15.17.0",
|
||||
"acorn": "6.0.4",
|
||||
"babel-core": "6.26.3",
|
||||
"babel-eslint": "10.0.1",
|
||||
"babel-loader": "7.1.4",
|
||||
"babel-plugin-jsm-to-commonjs": "0.4.0",
|
||||
"babel-plugin-jsm-to-esmodules": "0.4.0",
|
||||
|
@ -33,14 +35,14 @@
|
|||
"cpx": "1.5.0",
|
||||
"enzyme": "3.7.0",
|
||||
"enzyme-adapter-react-16": "1.7.0",
|
||||
"eslint": "4.19.1",
|
||||
"eslint-plugin-import": "2.11.0",
|
||||
"eslint": "5.9.0",
|
||||
"eslint-plugin-import": "2.14.0",
|
||||
"eslint-plugin-json": "1.2.1",
|
||||
"eslint-plugin-mozilla": "0.16.0",
|
||||
"eslint-plugin-no-unsanitized": "3.0.0",
|
||||
"eslint-plugin-promise": "3.7.0",
|
||||
"eslint-plugin-react": "7.7.0",
|
||||
"eslint-watch": "3.1.4",
|
||||
"eslint-plugin-mozilla": "0.16.3",
|
||||
"eslint-plugin-no-unsanitized": "3.0.2",
|
||||
"eslint-plugin-promise": "4.0.1",
|
||||
"eslint-plugin-react": "7.11.1",
|
||||
"eslint-watch": "4.0.2",
|
||||
"husky": "1.1.3",
|
||||
"istanbul-instrumenter-loader": "3.0.1",
|
||||
"joi-browser": "13.4.0",
|
||||
|
@ -59,7 +61,7 @@
|
|||
"mock-raf": "1.0.1",
|
||||
"node-fetch": "2.2.1",
|
||||
"node-sass": "4.10.0",
|
||||
"npm-run-all": "4.1.3",
|
||||
"npm-run-all": "4.1.5",
|
||||
"pontoon-to-json": "2.0.0",
|
||||
"prop-types": "15.6.2",
|
||||
"raw-loader": "0.5.1",
|
||||
|
|
|
@ -75,7 +75,7 @@ window.gActivityStreamStrings = {
|
|||
"pocket_read_more": "المواضيع الشائعة:",
|
||||
"pocket_read_even_more": "اعرض المزيد من الأخبار",
|
||||
"pocket_more_reccommendations": "مقترحات أخرى",
|
||||
"pocket_how_it_works": "How it works",
|
||||
"pocket_how_it_works": "آلية العمل",
|
||||
"pocket_cta_button": "نزِّل بوكِت",
|
||||
"pocket_cta_text": "احفظ القصص التي تحبّها في بوكِت، وزوّد عقلك بمقالات رائعة.",
|
||||
"highlights_empty_state": "ابدأ التصفح وسنعرض أمامك بعض المقالات والفيديوهات والمواقع الأخرى التي زرتها حديثا أو أضفتها إلى العلامات هنا.",
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -75,7 +75,7 @@ window.gActivityStreamStrings = {
|
|||
"pocket_read_more": "Beliebte Themen:",
|
||||
"pocket_read_even_more": "Weitere Nachrichten ansehen",
|
||||
"pocket_more_reccommendations": "Mehr Empfehlungen",
|
||||
"pocket_how_it_works": "How it works",
|
||||
"pocket_how_it_works": "Wie es funktioniert",
|
||||
"pocket_cta_button": "Pocket holen",
|
||||
"pocket_cta_text": "Speichern Sie Ihre Lieblingstexte in Pocket und gewinnen Sie gedankenreiche Einblicke durch faszinierende Texte.",
|
||||
"highlights_empty_state": "Surfen Sie los und wir zeigen Ihnen hier einige der interessanten Artikel, Videos und anderen Seiten, die Sie kürzlich besucht oder als Lesezeichen gespeichert haben.",
|
||||
|
@ -107,6 +107,6 @@ window.gActivityStreamStrings = {
|
|||
"firstrun_privacy_notice": "Datenschutzhinweis",
|
||||
"firstrun_continue_to_login": "Weiter",
|
||||
"firstrun_skip_login": "Diesen Schritt überspringen",
|
||||
"context_menu_title": "Open menu",
|
||||
"context_menu_title": "Menü öffnen",
|
||||
"pocket_learn_more": "Weitere Informationen"
|
||||
};
|
||||
|
|
|
@ -107,5 +107,6 @@ window.gActivityStreamStrings = {
|
|||
"firstrun_privacy_notice": "Política de privacidade",
|
||||
"firstrun_continue_to_login": "Continuar",
|
||||
"firstrun_skip_login": "Ignorar este paso",
|
||||
"context_menu_title": "Abrir menú"
|
||||
"context_menu_title": "Abrir menú",
|
||||
"pocket_learn_more": "Máis información"
|
||||
};
|
||||
|
|
|
@ -29,7 +29,7 @@ window.gActivityStreamStrings = {
|
|||
"menu_action_show_file_linux": "შემცველი საქაღალდის გახსნა",
|
||||
"menu_action_show_file_default": "ფაილის ჩვენება",
|
||||
"menu_action_open_file": "ფაილის გახსნა",
|
||||
"menu_action_copy_download_link": "ჩამოტვირთვის ბმულის დაკოპირება",
|
||||
"menu_action_copy_download_link": "ჩამოტვირთვის ბმულის ასლი",
|
||||
"menu_action_go_to_download_page": "გადასვლა ჩამოტვირთვის გვერდზე",
|
||||
"menu_action_remove_download": "ისტორიიდან ამოშლა",
|
||||
"search_button": "ძიება",
|
||||
|
|
|
@ -74,9 +74,9 @@ window.gActivityStreamStrings = {
|
|||
"topsites_form_image_validation": "L’imatge a pas capitat de se cargar. Ensajatz una URL diferenta.",
|
||||
"pocket_read_more": "Tèmas populars :",
|
||||
"pocket_read_even_more": "Veire mai d’articles",
|
||||
"pocket_more_reccommendations": "More Recommendations",
|
||||
"pocket_more_reccommendations": "Mai de recomandacions",
|
||||
"pocket_how_it_works": "How it works",
|
||||
"pocket_cta_button": "Get Pocket",
|
||||
"pocket_cta_button": "Installar Pocket",
|
||||
"pocket_cta_text": "Save the stories you love in Pocket, and fuel your mind with fascinating reads.",
|
||||
"highlights_empty_state": "Començatz de navegar e aquí vos mostrarem los melhors articles, vidèos e autras paginas qu’avètz visitadas o apondudas als marcapaginas.",
|
||||
"topstories_empty_state": "You’ve caught up. Check back later for more top stories from {provider}. Can’t wait? Select a popular topic to find more great stories from around the web.",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
|
||||
<title>Tab mới</title>
|
||||
<title>Thẻ mới</title>
|
||||
<link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
|
||||
<link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
|
||||
<link rel="stylesheet" href="resource://activity-stream/css/activity-stream.css" />
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,11 +1,11 @@
|
|||
// Note - this is a generated vi file.
|
||||
window.gActivityStreamStrings = {
|
||||
"newtab_page_title": "Tab mới",
|
||||
"newtab_page_title": "Thẻ mới",
|
||||
"header_top_sites": "Trang web hàng đầu",
|
||||
"header_highlights": "Nổi bật",
|
||||
"header_recommended_by": "Được đề nghị bởi {provider}",
|
||||
"context_menu_button_sr": "Open context menu for {title}",
|
||||
"section_context_menu_button_sr": "Open the section context menu",
|
||||
"context_menu_button_sr": "Mở bảng chọn ngữ cảnh cho {title}",
|
||||
"section_context_menu_button_sr": "Mở bảng chọn phần ngữ cảnh",
|
||||
"type_label_visited": "Đã truy cập",
|
||||
"type_label_bookmarked": "Đã được đánh dấu",
|
||||
"type_label_recommended": "Xu hướng",
|
||||
|
@ -24,7 +24,7 @@ window.gActivityStreamStrings = {
|
|||
"menu_action_save_to_pocket": "Lưu vào Pocket",
|
||||
"menu_action_delete_pocket": "Xóa khỏi Pocket",
|
||||
"menu_action_archive_pocket": "Lưu trữ trong Pocket",
|
||||
"menu_action_show_file_mac_os": "Show in Finder",
|
||||
"menu_action_show_file_mac_os": "Hiển thị trong Finder",
|
||||
"menu_action_show_file_windows": "Mở thư mục chứa",
|
||||
"menu_action_show_file_linux": "Mở thư mục chứa",
|
||||
"menu_action_show_file_default": "Hiện tập tin",
|
||||
|
@ -40,18 +40,18 @@ window.gActivityStreamStrings = {
|
|||
"section_disclaimer_topstories_buttontext": "Ok, đã hiểu",
|
||||
"prefs_home_header": "Nội dung trang chủ của Firefox",
|
||||
"prefs_home_description": "Chọn nội dung mà bạn muốn thêm vào trang chủ của Firefox.",
|
||||
"prefs_section_rows_option": "{num} row;{num} rows",
|
||||
"prefs_section_rows_option": "{num} hàng",
|
||||
"prefs_search_header": "Tìm kiếm web",
|
||||
"prefs_topsites_description": "Những trang bạn truy cập nhiều nhất",
|
||||
"prefs_topstories_description2": "Great content from around the web, personalized for you",
|
||||
"prefs_topstories_options_sponsored_label": "Sponsored Stories",
|
||||
"prefs_topstories_description2": "Nội dung tuyệt vời từ trên web, được cá nhân hóa cho bạn",
|
||||
"prefs_topstories_options_sponsored_label": "Bài viết quảng cáo",
|
||||
"prefs_topstories_sponsored_learn_more": "Tìm hiểu thêm",
|
||||
"prefs_highlights_description": "Một lựa chọn các trang web mà bạn đã lưu hoặc truy cập",
|
||||
"prefs_highlights_options_visited_label": "Trang đã xem",
|
||||
"prefs_highlights_options_download_label": "Tải xuống gần đây nhất",
|
||||
"prefs_highlights_options_pocket_label": "Pages Saved to Pocket",
|
||||
"prefs_highlights_options_pocket_label": "Trang đã được lưu vào Pocket",
|
||||
"prefs_snippets_description": "Cập nhật từ Mozilla và Firefox",
|
||||
"settings_pane_button_label": "Tùy biến trang Tab mới",
|
||||
"settings_pane_button_label": "Tùy biến trang Thẻ mới",
|
||||
"settings_pane_topsites_header": "Các trang Web hàng đầu",
|
||||
"settings_pane_highlights_header": "Nổi bật",
|
||||
"settings_pane_highlights_options_bookmarks": "Trang đánh dấu",
|
||||
|
@ -75,11 +75,11 @@ window.gActivityStreamStrings = {
|
|||
"pocket_read_more": "Các chủ đề phổ biến:",
|
||||
"pocket_read_even_more": "Xem nhiều câu chuyện hơn",
|
||||
"pocket_more_reccommendations": "Nhiều khuyến nghị hơn",
|
||||
"pocket_how_it_works": "How it works",
|
||||
"pocket_cta_button": "Get Pocket",
|
||||
"pocket_cta_text": "Save the stories you love in Pocket, and fuel your mind with fascinating reads.",
|
||||
"pocket_how_it_works": "Nó hoạt động như thế nào",
|
||||
"pocket_cta_button": "Nhận Pocket",
|
||||
"pocket_cta_text": "Lưu những câu chuyện bạn yêu thích trong Pocket và vui vẻ khi đọc chúng.",
|
||||
"highlights_empty_state": "Bắt đầu duyệt web và chúng tôi sẽ hiển thị một số bài báo, video, và các trang khác mà bạn vừa truy cập hoặc đã đánh dấu tại đây.",
|
||||
"topstories_empty_state": "You’ve caught up. Check back later for more top stories from {provider}. Can’t wait? Select a popular topic to find more great stories from around the web.",
|
||||
"topstories_empty_state": "Bạn đã bắt kịp. Kiểm tra lại sau để biết thêm các câu chuyện hàng đầu từ {provider}. Không muốn đợi? Chọn một chủ đề phổ biến để tìm thêm những câu chuyện tuyệt vời từ khắp nơi trên web.",
|
||||
"manual_migration_explanation2": "Thử Firefox với trang đánh dấu, lịch sử và mật khẩu từ trình duyệt khác.",
|
||||
"manual_migration_cancel_button": "Không, cảm ơn",
|
||||
"manual_migration_import_button": "Nhập ngay bây giờ",
|
||||
|
@ -102,11 +102,11 @@ window.gActivityStreamStrings = {
|
|||
"firstrun_form_sub_header": "để tiếp tục với Trình đồng bộ Firefox",
|
||||
"firstrun_email_input_placeholder": "Email",
|
||||
"firstrun_invalid_input": "Yêu cầu email hợp lệ",
|
||||
"firstrun_extra_legal_links": "By proceeding, you agree to the {terms} and {privacy}.",
|
||||
"firstrun_extra_legal_links": "Bằng cách tiếp tục, bạn đồng ý với {terms} và {privacy}.",
|
||||
"firstrun_terms_of_service": "Điều khoản dịch vụ",
|
||||
"firstrun_privacy_notice": "Thông báo bảo mật",
|
||||
"firstrun_continue_to_login": "Tiếp tục",
|
||||
"firstrun_skip_login": "Bỏ qua bước này",
|
||||
"context_menu_title": "Open menu",
|
||||
"context_menu_title": "Mở bảng chọn",
|
||||
"pocket_learn_more": "Tìm hiểu thêm"
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' resource: chrome:; connect-src https:; img-src https: data: blob:; style-src 'unsafe-inline';">
|
||||
<title>Tab mới</title>
|
||||
<title>Thẻ mới</title>
|
||||
<link rel="icon" type="image/png" href="chrome://branding/content/icon32.png"/>
|
||||
<link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
|
||||
<link rel="stylesheet" href="resource://activity-stream/css/activity-stream.css" />
|
||||
|
|
|
@ -7,8 +7,7 @@
|
|||
const Services = require("Services");
|
||||
|
||||
const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
|
||||
const { createFactory } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
const { createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const { render, unmountComponentAtNode } =
|
||||
require("devtools/client/shared/vendor/react-dom");
|
||||
const Provider =
|
||||
|
@ -37,10 +36,9 @@ const {
|
|||
|
||||
loader.lazyRequireGetter(this, "adbAddon", "devtools/shared/adb/adb-addon", true);
|
||||
|
||||
const Router = createFactory(require("devtools/client/shared/vendor/react-router-dom").HashRouter);
|
||||
const App = createFactory(require("./src/components/App"));
|
||||
|
||||
const { PAGES, RUNTIMES } = require("./src/constants");
|
||||
|
||||
const AboutDebugging = {
|
||||
async init() {
|
||||
if (!Services.prefs.getBoolPref("devtools.enabled", true)) {
|
||||
|
@ -59,11 +57,22 @@ const AboutDebugging = {
|
|||
await l10n.init();
|
||||
|
||||
render(
|
||||
Provider({ store: this.store }, App({ fluentBundles: l10n.getBundles() })),
|
||||
Provider(
|
||||
{
|
||||
store: this.store,
|
||||
},
|
||||
Router(
|
||||
{},
|
||||
App(
|
||||
{
|
||||
fluentBundles: l10n.getBundles(),
|
||||
}
|
||||
)
|
||||
)
|
||||
),
|
||||
this.mount
|
||||
);
|
||||
|
||||
this.actions.selectPage(PAGES.THIS_FIREFOX, RUNTIMES.THIS_FIREFOX);
|
||||
this.actions.updateNetworkLocations(getNetworkLocations());
|
||||
|
||||
addNetworkLocationsObserver(this.onNetworkLocationsUpdated);
|
||||
|
@ -99,6 +108,9 @@ const AboutDebugging = {
|
|||
await this.actions.unwatchRuntime(currentRuntimeId);
|
||||
}
|
||||
|
||||
// Remove all client listeners.
|
||||
this.actions.removeRuntimeListeners();
|
||||
|
||||
removeNetworkLocationsObserver(this.onNetworkLocationsUpdated);
|
||||
removeUSBRuntimesObserver(this.onUSBRuntimesUpdated);
|
||||
disableUSBRuntimes();
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
|
||||
const { gDevToolsBrowser } = require("devtools/client/framework/devtools-browser");
|
||||
const { remoteClientManager } =
|
||||
require("devtools/client/shared/remote-debugging/remote-client-manager");
|
||||
|
||||
const { l10n } = require("../modules/l10n");
|
||||
|
||||
|
@ -44,9 +46,10 @@ function inspectDebugTarget(type, id) {
|
|||
case DEBUG_TARGETS.TAB: {
|
||||
// Open tab debugger in new window.
|
||||
if (runtimeType === RUNTIMES.NETWORK || runtimeType === RUNTIMES.USB) {
|
||||
const { host, port } = runtimeDetails.transportDetails;
|
||||
window.open(`about:devtools-toolbox?type=tab&id=${id}` +
|
||||
`&host=${host}&port=${port}`);
|
||||
// Pass the remote id from the client manager so that about:devtools-toolbox can
|
||||
// retrieve the connected client directly.
|
||||
const remoteId = remoteClientManager.getRemoteId(runtime.id, runtime.type);
|
||||
window.open(`about:devtools-toolbox?type=tab&id=${id}&remoteId=${remoteId}`);
|
||||
} else if (runtimeType === RUNTIMES.THIS_FIREFOX) {
|
||||
window.open(`about:devtools-toolbox?type=tab&id=${id}`);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ const { isSupportedDebugTarget } = require("../modules/debug-target-support");
|
|||
|
||||
const { createClientForRuntime } = require("../modules/runtime-client-factory");
|
||||
|
||||
const { remoteClientManager } =
|
||||
require("devtools/client/shared/remote-debugging/remote-client-manager");
|
||||
|
||||
const {
|
||||
CONNECT_RUNTIME_FAILURE,
|
||||
CONNECT_RUNTIME_START,
|
||||
|
@ -68,7 +71,7 @@ function connectRuntime(id) {
|
|||
dispatch({ type: CONNECT_RUNTIME_START });
|
||||
try {
|
||||
const runtime = findRuntimeById(id, getState().runtimes);
|
||||
const { clientWrapper, transportDetails } = await createClientForRuntime(runtime);
|
||||
const clientWrapper = await createClientForRuntime(runtime);
|
||||
const info = await getRuntimeInfo(runtime, clientWrapper);
|
||||
|
||||
const promptPrefName = RUNTIME_PREFERENCE.CONNECTION_PROMPT;
|
||||
|
@ -77,7 +80,6 @@ function connectRuntime(id) {
|
|||
clientWrapper,
|
||||
connectionPromptEnabled,
|
||||
info,
|
||||
transportDetails,
|
||||
};
|
||||
|
||||
if (runtime.type === RUNTIMES.USB) {
|
||||
|
@ -215,6 +217,7 @@ function updateUSBRuntimes(runtimes) {
|
|||
// Current runtime can not be retrieved after USB_RUNTIMES_UPDATED action, since
|
||||
// that updates runtime state. So, before that we fire selectPage action so that to
|
||||
// transact unwatchRuntime correctly.
|
||||
|
||||
await dispatch(Actions.selectPage(RUNTIMES.THIS_FIREFOX, RUNTIMES.THIS_FIREFOX));
|
||||
}
|
||||
|
||||
|
@ -228,12 +231,38 @@ function updateUSBRuntimes(runtimes) {
|
|||
}
|
||||
|
||||
dispatch({ type: USB_RUNTIMES_UPDATED, runtimes });
|
||||
|
||||
for (const runtime of getState().runtimes.usbRuntimes) {
|
||||
const isConnected = !!runtime.runtimeDetails;
|
||||
const hasConnectedClient = remoteClientManager.hasClient(runtime.id, runtime.type);
|
||||
if (!isConnected && hasConnectedClient) {
|
||||
await dispatch(connectRuntime(runtime.id));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all the listeners added on client objects. Since those objects are persisted
|
||||
* regardless of the about:debugging lifecycle, all the added events should be removed
|
||||
* before leaving about:debugging.
|
||||
*/
|
||||
function removeRuntimeListeners() {
|
||||
return (dispatch, getState) => {
|
||||
const { usbRuntimes } = getState().runtimes;
|
||||
for (const runtime of usbRuntimes) {
|
||||
if (runtime.runtimeDetails) {
|
||||
const { clientWrapper } = runtime.runtimeDetails;
|
||||
clientWrapper.removeListener("closed", onUSBDebuggerClientClosed);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
connectRuntime,
|
||||
disconnectRuntime,
|
||||
removeRuntimeListeners,
|
||||
unwatchRuntime,
|
||||
updateConnectionPromptSetting,
|
||||
updateUSBRuntimes,
|
||||
|
|
|
@ -15,7 +15,7 @@ const {
|
|||
DEBUG_TARGET_COLLAPSIBILITY_UPDATED,
|
||||
NETWORK_LOCATIONS_UPDATED,
|
||||
PAGE_SELECTED,
|
||||
PAGES,
|
||||
PAGE_TYPES,
|
||||
USB_RUNTIMES_SCAN_START,
|
||||
USB_RUNTIMES_SCAN_SUCCESS,
|
||||
} = require("../constants");
|
||||
|
@ -26,32 +26,35 @@ const { refreshUSBRuntimes } = require("../modules/usb-runtimes");
|
|||
|
||||
const Actions = require("./index");
|
||||
|
||||
// XXX: Isolating the code here, because it feels wrong to rely solely on the page "not"
|
||||
// being CONNECT to decide what to do. Should we have a page "type" on top of page "id"?
|
||||
function _isRuntimePage(page) {
|
||||
return page && page !== PAGES.CONNECT;
|
||||
}
|
||||
|
||||
function selectPage(page, runtimeId) {
|
||||
return async (dispatch, getState) => {
|
||||
const isSamePage = (oldPage, newPage) => {
|
||||
if (newPage === PAGE_TYPES.RUNTIME && oldPage === PAGE_TYPES.RUNTIME) {
|
||||
return runtimeId === getState().runtimes.selectedRuntimeId;
|
||||
}
|
||||
return newPage === oldPage;
|
||||
};
|
||||
|
||||
const currentPage = getState().ui.selectedPage;
|
||||
// Nothing to dispatch if the page is the same as the current page.
|
||||
if (page === currentPage) {
|
||||
// Nothing to dispatch if the page is the same as the current page, or
|
||||
// if we are not providing any page.
|
||||
// Note: maybe we should have a PAGE_SELECTED_FAILURE action for proper logging
|
||||
if (!page || isSamePage(currentPage, page)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop watching current runtime, if currently on a DEVICE or THIS_FIREFOX page.
|
||||
if (_isRuntimePage(currentPage)) {
|
||||
// Stop watching current runtime, if currently on a RUNTIME page.
|
||||
if (currentPage === PAGE_TYPES.RUNTIME) {
|
||||
const currentRuntimeId = getState().runtimes.selectedRuntimeId;
|
||||
await dispatch(Actions.unwatchRuntime(currentRuntimeId));
|
||||
}
|
||||
|
||||
// Start watching current runtime, if moving to a DEVICE or THIS_FIREFOX page.
|
||||
if (_isRuntimePage(page)) {
|
||||
// Start watching current runtime, if moving to a RUNTIME page.
|
||||
if (page === PAGE_TYPES.RUNTIME) {
|
||||
await dispatch(Actions.watchRuntime(runtimeId));
|
||||
}
|
||||
|
||||
dispatch({ type: PAGE_SELECTED, page });
|
||||
dispatch({ type: PAGE_SELECTED, page, runtimeId });
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,13 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
|||
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
|
||||
const LocalizationProvider = createFactory(FluentReact.LocalizationProvider);
|
||||
|
||||
const { PAGES } = require("../constants");
|
||||
const Route = createFactory(require("devtools/client/shared/vendor/react-router-dom").Route);
|
||||
const Switch = createFactory(require("devtools/client/shared/vendor/react-router-dom").Switch);
|
||||
const Redirect = createFactory(require("devtools/client/shared/vendor/react-router-dom").Redirect);
|
||||
const { withRouter } = require("devtools/client/shared/vendor/react-router-dom");
|
||||
|
||||
const Types = require("../types/index");
|
||||
const { RUNTIMES } = require("../constants");
|
||||
|
||||
const ConnectPage = createFactory(require("./connect/ConnectPage"));
|
||||
const RuntimePage = createFactory(require("./RuntimePage"));
|
||||
|
@ -33,39 +38,94 @@ class App extends PureComponent {
|
|||
networkLocations: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
networkRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
|
||||
selectedPage: PropTypes.string,
|
||||
selectedRuntime: PropTypes.string,
|
||||
usbRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
|
||||
wifiEnabled: PropTypes.bool.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
getSelectedPageComponent() {
|
||||
renderConnect() {
|
||||
const {
|
||||
adbAddonStatus,
|
||||
dispatch,
|
||||
networkEnabled,
|
||||
networkLocations,
|
||||
selectedPage,
|
||||
wifiEnabled,
|
||||
} = this.props;
|
||||
|
||||
if (!selectedPage) {
|
||||
// No page selected.
|
||||
return null;
|
||||
return ConnectPage({
|
||||
adbAddonStatus,
|
||||
dispatch,
|
||||
networkEnabled,
|
||||
networkLocations,
|
||||
wifiEnabled,
|
||||
});
|
||||
}
|
||||
|
||||
// The `match` object here is passed automatically by the Route object.
|
||||
// We are using it to read the route path.
|
||||
// See react-router docs:
|
||||
// https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/match.md
|
||||
renderRuntime({ match }) {
|
||||
// Redirect to This Firefox in these cases:
|
||||
// - If the runtimepage for a device is the first page shown (since we can't
|
||||
// keep connections open between page reloads).
|
||||
// - If no runtimeId is given.
|
||||
// - If runtime is not found in the runtimes list (this is handled later)
|
||||
const isDeviceFirstPage =
|
||||
!this.props.selectedPage &&
|
||||
match.params.runtimeId !== RUNTIMES.THIS_FIREFOX;
|
||||
if (!match.params.runtimeId || isDeviceFirstPage) {
|
||||
return Redirect({ to: `/runtime/${RUNTIMES.THIS_FIREFOX}` });
|
||||
}
|
||||
|
||||
switch (selectedPage) {
|
||||
case PAGES.CONNECT:
|
||||
return ConnectPage({
|
||||
adbAddonStatus,
|
||||
dispatch,
|
||||
networkEnabled,
|
||||
networkLocations,
|
||||
wifiEnabled,
|
||||
});
|
||||
default:
|
||||
// All pages except for the CONNECT page are RUNTIME pages.
|
||||
return RuntimePage({ dispatch });
|
||||
const isRuntimeAvailable = id => {
|
||||
const runtimes = this.props.usbRuntimes;
|
||||
return !!runtimes.find(x => x.id === id);
|
||||
};
|
||||
|
||||
const { dispatch } = this.props;
|
||||
|
||||
let runtimeId = match.params.runtimeId || RUNTIMES.THIS_FIREFOX;
|
||||
if (match.params.runtimeId !== RUNTIMES.THIS_FIREFOX) {
|
||||
const rawId = decodeURIComponent(match.params.runtimeId);
|
||||
if (isRuntimeAvailable(rawId)) {
|
||||
runtimeId = rawId;
|
||||
} else {
|
||||
// Also redirect to "This Firefox" if runtime is not found
|
||||
return Redirect({ to: `/runtime/${RUNTIMES.THIS_FIREFOX}` });
|
||||
}
|
||||
}
|
||||
|
||||
// we need to pass a key so the component updates when we want to showcase
|
||||
// a different runtime
|
||||
return RuntimePage({ dispatch, key: runtimeId, runtimeId });
|
||||
}
|
||||
|
||||
renderRoutes() {
|
||||
return Switch(
|
||||
{},
|
||||
Route({
|
||||
path: "/connect",
|
||||
render: () => this.renderConnect(),
|
||||
}),
|
||||
Route({
|
||||
path: "/runtime/:runtimeId",
|
||||
render: routeProps => this.renderRuntime(routeProps),
|
||||
}),
|
||||
Route({
|
||||
path: "/",
|
||||
exact: true,
|
||||
// will redirect to This Firefox
|
||||
render: routeProps => this.renderRuntime(routeProps),
|
||||
}),
|
||||
// default route when there's no match
|
||||
// TODO: maybe we'd like to do something else than a redirect. See:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1509897
|
||||
Route({
|
||||
render: () => Redirect({ to: "/"}),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -76,6 +136,7 @@ class App extends PureComponent {
|
|||
isScanningUsb,
|
||||
networkRuntimes,
|
||||
selectedPage,
|
||||
selectedRuntime,
|
||||
usbRuntimes,
|
||||
} = this.props;
|
||||
|
||||
|
@ -83,21 +144,17 @@ class App extends PureComponent {
|
|||
{ messages: fluentBundles },
|
||||
dom.div(
|
||||
{ className: "app" },
|
||||
Sidebar(
|
||||
{
|
||||
adbAddonStatus,
|
||||
className: "app__sidebar",
|
||||
dispatch,
|
||||
isScanningUsb,
|
||||
networkRuntimes,
|
||||
selectedPage,
|
||||
usbRuntimes,
|
||||
}
|
||||
),
|
||||
dom.main(
|
||||
{ className: "app__content" },
|
||||
this.getSelectedPageComponent()
|
||||
)
|
||||
Sidebar({
|
||||
adbAddonStatus,
|
||||
className: "app__sidebar",
|
||||
dispatch,
|
||||
isScanningUsb,
|
||||
networkRuntimes,
|
||||
selectedPage,
|
||||
selectedRuntime,
|
||||
usbRuntimes,
|
||||
}),
|
||||
dom.main({ className: "app__content" }, this.renderRoutes())
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -111,6 +168,7 @@ const mapStateToProps = state => {
|
|||
networkLocations: state.ui.networkLocations,
|
||||
networkRuntimes: state.runtimes.networkRuntimes,
|
||||
selectedPage: state.ui.selectedPage,
|
||||
selectedRuntime: state.ui.selectedRuntime,
|
||||
usbRuntimes: state.runtimes.usbRuntimes,
|
||||
wifiEnabled: state.ui.wifiEnabled,
|
||||
};
|
||||
|
@ -120,4 +178,4 @@ const mapDispatchToProps = dispatch => ({
|
|||
dispatch,
|
||||
});
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
module.exports = withRouter(connect(mapStateToProps, mapDispatchToProps)(App));
|
||||
|
|
|
@ -24,7 +24,9 @@ const TemporaryExtensionInstaller =
|
|||
createFactory(require("./debugtarget/TemporaryExtensionInstaller"));
|
||||
const WorkerDetail = createFactory(require("./debugtarget/WorkerDetail"));
|
||||
|
||||
const { DEBUG_TARGET_PANE } = require("../constants");
|
||||
const Actions = require("../actions/index");
|
||||
const { DEBUG_TARGET_PANE, PAGE_TYPES } = require("../constants");
|
||||
|
||||
const {
|
||||
getCurrentConnectionPromptSetting,
|
||||
getCurrentRuntimeInfo,
|
||||
|
@ -39,6 +41,7 @@ class RuntimePage extends PureComponent {
|
|||
dispatch: PropTypes.func.isRequired,
|
||||
installedExtensions: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
otherWorkers: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
runtimeId: PropTypes.string.isRequired,
|
||||
runtimeInfo: PropTypes.object,
|
||||
serviceWorkers: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
sharedWorkers: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
|
@ -47,6 +50,13 @@ class RuntimePage extends PureComponent {
|
|||
};
|
||||
}
|
||||
|
||||
// TODO: avoid the use of this method
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1508688
|
||||
componentWillMount() {
|
||||
const { dispatch, runtimeId } = this.props;
|
||||
dispatch(Actions.selectPage(PAGE_TYPES.RUNTIME, runtimeId));
|
||||
}
|
||||
|
||||
renderConnectionPromptSetting() {
|
||||
const { connectionPromptEnabled, dispatch } = this.props;
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ const ConnectSteps = createFactory(require("./ConnectSteps"));
|
|||
const NetworkLocationsForm = createFactory(require("./NetworkLocationsForm"));
|
||||
const NetworkLocationsList = createFactory(require("./NetworkLocationsList"));
|
||||
|
||||
const { PREFERENCES } = require("../../constants");
|
||||
const { PREFERENCES, PAGE_TYPES } = require("../../constants");
|
||||
|
||||
const USB_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg";
|
||||
const WIFI_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg";
|
||||
|
@ -43,6 +43,12 @@ class ConnectPage extends PureComponent {
|
|||
};
|
||||
}
|
||||
|
||||
// TODO: avoid the use of this method
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1508688
|
||||
componentWillMount() {
|
||||
this.props.dispatch(Actions.selectPage(PAGE_TYPES.CONNECT));
|
||||
}
|
||||
|
||||
renderWifi() {
|
||||
const { getString, wifiEnabled } = this.props;
|
||||
|
||||
|
@ -56,27 +62,28 @@ class ConnectPage extends PureComponent {
|
|||
icon: WIFI_ICON_SRC,
|
||||
title: "Via WiFi",
|
||||
},
|
||||
wifiEnabled ?
|
||||
ConnectSteps({
|
||||
steps: [
|
||||
getString("about-debugging-connect-wifi-step-same-network"),
|
||||
getString("about-debugging-connect-wifi-step-open-firefox"),
|
||||
getString("about-debugging-connect-wifi-step-open-options"),
|
||||
getString("about-debugging-connect-wifi-step-enable-debug"),
|
||||
],
|
||||
}) :
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-connect-wifi-disabled",
|
||||
$pref: PREFERENCES.WIFI_ENABLED,
|
||||
},
|
||||
dom.div(
|
||||
wifiEnabled
|
||||
? ConnectSteps(
|
||||
{
|
||||
className: "connect-page__disabled-section",
|
||||
steps: [
|
||||
getString("about-debugging-connect-wifi-step-same-network"),
|
||||
getString("about-debugging-connect-wifi-step-open-firefox"),
|
||||
getString("about-debugging-connect-wifi-step-open-options"),
|
||||
getString("about-debugging-connect-wifi-step-enable-debug"),
|
||||
],
|
||||
})
|
||||
: Localized(
|
||||
{
|
||||
id: "about-debugging-connect-wifi-disabled",
|
||||
$pref: PREFERENCES.WIFI_ENABLED,
|
||||
},
|
||||
"about-debugging-connect-wifi-disabled"
|
||||
dom.div(
|
||||
{
|
||||
className: "connect-page__disabled-section",
|
||||
},
|
||||
"about-debugging-connect-wifi-disabled"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -121,8 +128,9 @@ class ConnectPage extends PureComponent {
|
|||
},
|
||||
dom.button(
|
||||
{
|
||||
className: "default-button connect-page__usb__toggle-button " +
|
||||
"js-connect-usb-toggle-button",
|
||||
className:
|
||||
"default-button connect-page__usb__toggle-button " +
|
||||
"js-connect-usb-toggle-button",
|
||||
disabled,
|
||||
onClick: () => this.onToggleUSBClick(),
|
||||
},
|
||||
|
@ -144,15 +152,17 @@ class ConnectPage extends PureComponent {
|
|||
icon: USB_ICON_SRC,
|
||||
title: "Via USB",
|
||||
},
|
||||
(isAddonInstalled ?
|
||||
ConnectSteps({
|
||||
steps: [
|
||||
getString("about-debugging-connect-usb-step-enable-dev-menu"),
|
||||
getString("about-debugging-connect-usb-step-enable-debug"),
|
||||
getString("about-debugging-connect-usb-step-plug-device"),
|
||||
],
|
||||
}) :
|
||||
Localized(
|
||||
isAddonInstalled
|
||||
? ConnectSteps(
|
||||
{
|
||||
steps: [
|
||||
getString("about-debugging-connect-usb-step-enable-dev-menu"),
|
||||
getString("about-debugging-connect-usb-step-enable-debug"),
|
||||
getString("about-debugging-connect-usb-step-plug-device"),
|
||||
],
|
||||
}
|
||||
)
|
||||
: Localized(
|
||||
{
|
||||
id: "about-debugging-connect-usb-disabled",
|
||||
},
|
||||
|
@ -161,10 +171,9 @@ class ConnectPage extends PureComponent {
|
|||
className: "js-connect-usb-disabled-message",
|
||||
},
|
||||
"Enabling this will download and add the required Android USB debugging " +
|
||||
"components to Firefox."
|
||||
"components to Firefox."
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
this.renderUsbToggleButton()
|
||||
)
|
||||
);
|
||||
|
@ -184,30 +193,29 @@ class ConnectPage extends PureComponent {
|
|||
icon: GLOBE_ICON_SRC,
|
||||
title: "Via Network Location",
|
||||
},
|
||||
...(
|
||||
networkEnabled ?
|
||||
[
|
||||
NetworkLocationsList({ dispatch, networkLocations }),
|
||||
dom.hr({ className: "separator separator--breathe" }),
|
||||
NetworkLocationsForm({ dispatch }),
|
||||
] : [
|
||||
// We are using an array for this single element because of the spread
|
||||
// operator (...). The spread operator avoids React warnings about missing
|
||||
// keys.
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-connect-network-disabled",
|
||||
$pref: PREFERENCES.NETWORK_ENABLED,
|
||||
},
|
||||
dom.div(
|
||||
{
|
||||
className: "connect-page__disabled-section",
|
||||
},
|
||||
"about-debugging-connect-network-disabled"
|
||||
)
|
||||
),
|
||||
...(networkEnabled
|
||||
? [
|
||||
NetworkLocationsList({ dispatch, networkLocations }),
|
||||
dom.hr({ className: "separator separator--breathe" }),
|
||||
NetworkLocationsForm({ dispatch }),
|
||||
]
|
||||
)
|
||||
: [
|
||||
// We are using an array for this single element because of the spread
|
||||
// operator (...). The spread operator avoids React warnings about missing
|
||||
// keys.
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-connect-network-disabled",
|
||||
$pref: PREFERENCES.NETWORK_ENABLED,
|
||||
},
|
||||
dom.div(
|
||||
{
|
||||
className: "connect-page__disabled-section",
|
||||
},
|
||||
"about-debugging-connect-network-disabled"
|
||||
)
|
||||
),
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -230,7 +238,7 @@ class ConnectPage extends PureComponent {
|
|||
),
|
||||
this.renderWifi(),
|
||||
this.renderUsb(),
|
||||
this.renderNetwork(),
|
||||
this.renderNetwork()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,3 +9,7 @@
|
|||
.debug-target-pane__icon--collapsed {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.debug-target-pane__title {
|
||||
cursor: pointer;
|
||||
}
|
|
@ -50,8 +50,8 @@ class DebugTargetPane extends PureComponent {
|
|||
},
|
||||
dom.a(
|
||||
{
|
||||
className: "undecorated-link js-debug-target-pane-title",
|
||||
href: "#",
|
||||
className: "undecorated-link debug-target-pane__title " +
|
||||
"js-debug-target-pane-title",
|
||||
onClick: e => this.toggleCollapsibility(),
|
||||
},
|
||||
dom.h2(
|
||||
|
|
|
@ -11,7 +11,7 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
|||
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
|
||||
const Localized = createFactory(FluentReact.Localized);
|
||||
|
||||
const { PAGES, RUNTIMES } = require("../../constants");
|
||||
const { PAGE_TYPES, RUNTIMES } = require("../../constants");
|
||||
const Types = require("../../types/index");
|
||||
loader.lazyRequireGetter(this, "ADB_ADDON_STATES", "devtools/shared/adb/adb-addon", true);
|
||||
|
||||
|
@ -33,6 +33,7 @@ class Sidebar extends PureComponent {
|
|||
isScanningUsb: PropTypes.bool.isRequired,
|
||||
networkRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
|
||||
selectedPage: PropTypes.string,
|
||||
selectedRuntime: PropTypes.string,
|
||||
usbRuntimes: PropTypes.arrayOf(Types.runtime).isRequired,
|
||||
};
|
||||
}
|
||||
|
@ -57,7 +58,6 @@ class Sidebar extends PureComponent {
|
|||
return SidebarItem(
|
||||
{
|
||||
isSelected: false,
|
||||
selectable: false,
|
||||
},
|
||||
Localized(
|
||||
{
|
||||
|
@ -88,20 +88,21 @@ class Sidebar extends PureComponent {
|
|||
}
|
||||
|
||||
renderSidebarItems(icon, runtimes) {
|
||||
const { dispatch, selectedPage } = this.props;
|
||||
const { dispatch, selectedPage, selectedRuntime } = this.props;
|
||||
|
||||
return runtimes.map(runtime => {
|
||||
const pageId = runtime.type + "-" + runtime.id;
|
||||
const keyId = `${runtime.type}-${runtime.id}`;
|
||||
const runtimeHasDetails = !!runtime.runtimeDetails;
|
||||
const isSelected = selectedPage === PAGE_TYPES.RUNTIME &&
|
||||
runtime.id === selectedRuntime;
|
||||
|
||||
return SidebarRuntimeItem({
|
||||
id: pageId,
|
||||
deviceName: runtime.extra.deviceName,
|
||||
dispatch,
|
||||
icon,
|
||||
key: keyId,
|
||||
isConnected: runtimeHasDetails,
|
||||
isSelected: selectedPage === pageId,
|
||||
key: pageId,
|
||||
isSelected,
|
||||
name: runtime.name,
|
||||
runtimeId: runtime.id,
|
||||
});
|
||||
|
@ -109,7 +110,7 @@ class Sidebar extends PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { dispatch, selectedPage, isScanningUsb } = this.props;
|
||||
const { dispatch, selectedPage, selectedRuntime, isScanningUsb } = this.props;
|
||||
|
||||
return dom.aside(
|
||||
{
|
||||
|
@ -120,28 +121,29 @@ class Sidebar extends PureComponent {
|
|||
Localized(
|
||||
{ id: "about-debugging-sidebar-this-firefox", attrs: { name: true } },
|
||||
SidebarFixedItem({
|
||||
id: PAGES.THIS_FIREFOX,
|
||||
dispatch,
|
||||
icon: FIREFOX_ICON,
|
||||
isSelected: PAGES.THIS_FIREFOX === selectedPage,
|
||||
isSelected: PAGE_TYPES.RUNTIME === selectedPage &&
|
||||
selectedRuntime === RUNTIMES.THIS_FIREFOX,
|
||||
key: RUNTIMES.THIS_FIREFOX,
|
||||
name: "This Firefox",
|
||||
runtimeId: RUNTIMES.THIS_FIREFOX,
|
||||
to: `/runtime/${RUNTIMES.THIS_FIREFOX}`,
|
||||
})
|
||||
),
|
||||
Localized(
|
||||
{ id: "about-debugging-sidebar-connect", attrs: { name: true } },
|
||||
SidebarFixedItem({
|
||||
id: PAGES.CONNECT,
|
||||
dispatch,
|
||||
icon: CONNECT_ICON,
|
||||
isSelected: PAGES.CONNECT === selectedPage,
|
||||
isSelected: PAGE_TYPES.CONNECT === selectedPage,
|
||||
key: PAGE_TYPES.CONNECT,
|
||||
name: "Connect",
|
||||
to: "/connect",
|
||||
})
|
||||
),
|
||||
SidebarItem(
|
||||
{
|
||||
isSelected: false,
|
||||
selectable: false,
|
||||
key: "separator-0",
|
||||
},
|
||||
dom.hr({ className: "separator" }),
|
||||
this.renderAdbAddonStatus(),
|
||||
|
@ -151,7 +153,7 @@ class Sidebar extends PureComponent {
|
|||
{
|
||||
className: "sidebar-item--breathe sidebar__refresh-usb",
|
||||
isSelected: false,
|
||||
selectable: false,
|
||||
key: "refresh-devices",
|
||||
},
|
||||
RefreshDevicesButton({
|
||||
dispatch,
|
||||
|
|
|
@ -10,40 +10,31 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
|||
|
||||
const SidebarItem = createFactory(require("./SidebarItem"));
|
||||
|
||||
const Actions = require("../../actions/index");
|
||||
|
||||
/**
|
||||
* This component displays a fixed item in the Sidebar component.
|
||||
*/
|
||||
class SidebarFixedItem extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
icon: PropTypes.string.isRequired,
|
||||
id: PropTypes.string.isRequired,
|
||||
isSelected: PropTypes.bool.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
runtimeId: PropTypes.string,
|
||||
to: PropTypes.string,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
dispatch,
|
||||
id,
|
||||
icon,
|
||||
isSelected,
|
||||
name,
|
||||
runtimeId,
|
||||
to,
|
||||
} = this.props;
|
||||
|
||||
return SidebarItem(
|
||||
{
|
||||
isSelected,
|
||||
selectable: true,
|
||||
onSelect: () => {
|
||||
dispatch(Actions.selectPage(id, runtimeId));
|
||||
},
|
||||
to,
|
||||
},
|
||||
dom.div(
|
||||
{
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const Link = createFactory(require("devtools/client/shared/vendor/react-router-dom").Link);
|
||||
|
||||
/**
|
||||
* This component is used as a wrapper by items in the sidebar.
|
||||
|
@ -17,34 +18,18 @@ class SidebarItem extends PureComponent {
|
|||
children: PropTypes.node.isRequired,
|
||||
className: PropTypes.string,
|
||||
isSelected: PropTypes.bool.isRequired,
|
||||
selectable: PropTypes.bool.isRequired,
|
||||
// only require `onSelect` function when `selectable` is true
|
||||
onSelect: (props, propName, componentName) => {
|
||||
const isFn = props[propName] && typeof props[propName] === "function";
|
||||
if (props.selectable && !isFn) {
|
||||
return new Error(`Missing ${propName} function supplied to ${componentName}. ` +
|
||||
"(you must set this prop when selectable is true)");
|
||||
}
|
||||
return null; // for eslint (consistent-return rule)
|
||||
},
|
||||
to: PropTypes.string,
|
||||
};
|
||||
}
|
||||
|
||||
// temporary handler until a router is in place
|
||||
onItemClick(evt) {
|
||||
evt.preventDefault();
|
||||
this.props.onSelect();
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
const { children, selectable } = this.props;
|
||||
const { children, to } = this.props;
|
||||
|
||||
if (selectable) {
|
||||
return dom.a(
|
||||
if (to) {
|
||||
return Link(
|
||||
{
|
||||
className: "sidebar-item__link js-sidebar-link",
|
||||
href: "#", // to be changed with a path when a router is in place
|
||||
onClick: (evt) => this.onItemClick(evt),
|
||||
to,
|
||||
},
|
||||
children
|
||||
);
|
||||
|
@ -54,7 +39,7 @@ class SidebarItem extends PureComponent {
|
|||
}
|
||||
|
||||
render() {
|
||||
const {className, isSelected, selectable } = this.props;
|
||||
const {className, isSelected, to } = this.props;
|
||||
|
||||
return dom.li(
|
||||
{
|
||||
|
@ -64,7 +49,7 @@ class SidebarItem extends PureComponent {
|
|||
" sidebar-item--selected js-sidebar-item-selected" :
|
||||
""
|
||||
) +
|
||||
(selectable ? " sidebar-item--selectable" : ""),
|
||||
(to ? " sidebar-item--selectable" : ""),
|
||||
},
|
||||
this.renderContent()
|
||||
);
|
||||
|
|
|
@ -20,7 +20,6 @@ const Actions = require("../../actions/index");
|
|||
class SidebarRuntimeItem extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
id: PropTypes.string.isRequired,
|
||||
deviceName: PropTypes.string,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
// Provided by wrapping the component with FluentReact.withLocalization.
|
||||
|
@ -76,10 +75,8 @@ class SidebarRuntimeItem extends PureComponent {
|
|||
render() {
|
||||
const {
|
||||
deviceName,
|
||||
dispatch,
|
||||
getString,
|
||||
icon,
|
||||
id,
|
||||
isConnected,
|
||||
isSelected,
|
||||
name,
|
||||
|
@ -93,10 +90,7 @@ class SidebarRuntimeItem extends PureComponent {
|
|||
return SidebarItem(
|
||||
{
|
||||
isSelected,
|
||||
selectable: isConnected,
|
||||
onSelect: () => {
|
||||
dispatch(Actions.selectPage(id, runtimeId));
|
||||
},
|
||||
to: isConnected ? `/runtime/${encodeURIComponent(runtimeId)}` : null,
|
||||
},
|
||||
dom.div(
|
||||
{
|
||||
|
|
|
@ -59,8 +59,8 @@ const DEBUG_TARGET_PANE = {
|
|||
TEMPORARY_EXTENSION: "temporaryExtension",
|
||||
};
|
||||
|
||||
const PAGES = {
|
||||
THIS_FIREFOX: "this-firefox",
|
||||
const PAGE_TYPES = {
|
||||
RUNTIME: "runtime",
|
||||
CONNECT: "connect",
|
||||
};
|
||||
|
||||
|
@ -104,7 +104,7 @@ const USB_STATES = {
|
|||
module.exports = Object.assign({}, {
|
||||
DEBUG_TARGETS,
|
||||
DEBUG_TARGET_PANE,
|
||||
PAGES,
|
||||
PAGE_TYPES,
|
||||
PREFERENCES,
|
||||
RUNTIME_PREFERENCE,
|
||||
RUNTIMES,
|
||||
|
|
|
@ -8,6 +8,8 @@ const { ADB } = require("devtools/shared/adb/adb");
|
|||
const { DebuggerClient } = require("devtools/shared/client/debugger-client");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const { ClientWrapper } = require("./client-wrapper");
|
||||
const { remoteClientManager } =
|
||||
require("devtools/client/shared/remote-debugging/remote-client-manager");
|
||||
|
||||
const { RUNTIMES } = require("../constants");
|
||||
|
||||
|
@ -16,15 +18,14 @@ async function createLocalClient() {
|
|||
DebuggerServer.registerAllActors();
|
||||
const client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
await client.connect();
|
||||
return { clientWrapper: new ClientWrapper(client) };
|
||||
return new ClientWrapper(client);
|
||||
}
|
||||
|
||||
async function createNetworkClient(host, port) {
|
||||
const transportDetails = { host, port };
|
||||
const transport = await DebuggerClient.socketConnect(transportDetails);
|
||||
const transport = await DebuggerClient.socketConnect({ host, port });
|
||||
const client = new DebuggerClient(transport);
|
||||
await client.connect();
|
||||
return { clientWrapper: new ClientWrapper(client), transportDetails };
|
||||
return new ClientWrapper(client);
|
||||
}
|
||||
|
||||
async function createUSBClient(socketPath) {
|
||||
|
@ -33,10 +34,13 @@ async function createUSBClient(socketPath) {
|
|||
}
|
||||
|
||||
async function createClientForRuntime(runtime) {
|
||||
const { extra, type } = runtime;
|
||||
const { extra, id, type } = runtime;
|
||||
|
||||
if (type === RUNTIMES.THIS_FIREFOX) {
|
||||
return createLocalClient();
|
||||
} else if (remoteClientManager.hasClient(id, type)) {
|
||||
const client = remoteClientManager.getClient(id, type);
|
||||
return new ClientWrapper(client);
|
||||
} else if (type === RUNTIMES.NETWORK) {
|
||||
const { host, port } = extra.connectionParameters;
|
||||
return createNetworkClient(host, port);
|
||||
|
|
|
@ -19,6 +19,9 @@ const {
|
|||
findRuntimeById,
|
||||
} = require("../modules/runtimes-state-helper");
|
||||
|
||||
const { remoteClientManager } =
|
||||
require("devtools/client/shared/remote-debugging/remote-client-manager");
|
||||
|
||||
// Map between known runtime types and nodes in the runtimes state.
|
||||
const TYPE_TO_RUNTIMES_KEY = {
|
||||
[RUNTIMES.THIS_FIREFOX]: "thisFirefoxRuntimes",
|
||||
|
@ -70,12 +73,14 @@ function _updateRuntimeById(runtimeId, updatedRuntime, state) {
|
|||
function runtimesReducer(state = RuntimesState(), action) {
|
||||
switch (action.type) {
|
||||
case CONNECT_RUNTIME_SUCCESS: {
|
||||
const { id, runtimeDetails } = action.runtime;
|
||||
const { id, runtimeDetails, type } = action.runtime;
|
||||
remoteClientManager.setClient(id, type, runtimeDetails.clientWrapper.client);
|
||||
return _updateRuntimeById(id, { runtimeDetails }, state);
|
||||
}
|
||||
|
||||
case DISCONNECT_RUNTIME_SUCCESS: {
|
||||
const { id } = action.runtime;
|
||||
const { id, type } = action.runtime;
|
||||
remoteClientManager.removeClient(id, type);
|
||||
return _updateRuntimeById(id, { runtimeDetails: null }, state);
|
||||
}
|
||||
|
||||
|
@ -112,8 +117,8 @@ function runtimesReducer(state = RuntimesState(), action) {
|
|||
const { runtimes } = action;
|
||||
const usbRuntimes = runtimes.map(runtime => {
|
||||
const existingRuntime = findRuntimeById(runtime.id, state);
|
||||
const existingRuntimeDetails =
|
||||
existingRuntime ? existingRuntime.runtimeDetails : null;
|
||||
const existingRuntimeDetails = existingRuntime ?
|
||||
existingRuntime.runtimeDetails : null;
|
||||
|
||||
return {
|
||||
id: runtime.id,
|
||||
|
|
|
@ -22,6 +22,7 @@ function UiState(locations = [], debugTargetCollapsibilities = {},
|
|||
networkEnabled,
|
||||
networkLocations: locations,
|
||||
selectedPage: null,
|
||||
selectedRuntime: null,
|
||||
showSystemAddons,
|
||||
wifiEnabled,
|
||||
};
|
||||
|
@ -47,8 +48,9 @@ function uiReducer(state = UiState(), action) {
|
|||
}
|
||||
|
||||
case PAGE_SELECTED: {
|
||||
const { page } = action;
|
||||
return Object.assign({}, state, { selectedPage: page });
|
||||
const { page, runtimeId } = action;
|
||||
return Object.assign({}, state,
|
||||
{ selectedPage: page, selectedRuntime: runtimeId });
|
||||
}
|
||||
|
||||
case USB_RUNTIMES_SCAN_START: {
|
||||
|
|
|
@ -22,14 +22,6 @@ const runtimeInfo = {
|
|||
version: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
const runtimeTransportDetails = {
|
||||
// host name of tcp connection to debugger server
|
||||
host: PropTypes.string.isRequired,
|
||||
|
||||
// port number of tcp connection to debugger server
|
||||
port: PropTypes.number.isRequired,
|
||||
};
|
||||
|
||||
const runtimeDetails = {
|
||||
// ClientWrapper built using a DebuggerClient for the runtime
|
||||
clientWrapper: PropTypes.instanceOf(ClientWrapper).isRequired,
|
||||
|
@ -39,10 +31,6 @@ const runtimeDetails = {
|
|||
|
||||
// runtime information
|
||||
info: PropTypes.shape(runtimeInfo).isRequired,
|
||||
|
||||
// tcp connection information,
|
||||
// unavailable on this-firefox runtime
|
||||
transportDetails: PropTypes.shape(runtimeTransportDetails),
|
||||
};
|
||||
|
||||
const networkRuntimeConnectionParameter = {
|
||||
|
|
|
@ -27,6 +27,8 @@ skip-if = (os == 'linux' && bits == 32) # ADB start() fails on linux 32, see Bug
|
|||
[browser_aboutdebugging_debug-target-pane_empty.js]
|
||||
[browser_aboutdebugging_debug-target-pane_usb_runtime.js]
|
||||
[browser_aboutdebugging_navigate.js]
|
||||
[browser_aboutdebugging_persist_connection.js]
|
||||
[browser_aboutdebugging_routes.js]
|
||||
[browser_aboutdebugging_sidebar_network_runtimes.js]
|
||||
[browser_aboutdebugging_sidebar_usb_runtime.js]
|
||||
[browser_aboutdebugging_sidebar_usb_runtime_connect.js]
|
||||
|
|
|
@ -24,7 +24,8 @@ add_task(async function() {
|
|||
});
|
||||
usbMocks.emitUpdate();
|
||||
|
||||
await connectToRuntime(RUNTIME_DEVICE_NAME, RUNTIME_APP_NAME, document);
|
||||
await connectToRuntime(RUNTIME_DEVICE_NAME, document);
|
||||
await selectRuntime(RUNTIME_DEVICE_NAME, RUNTIME_APP_NAME, document);
|
||||
|
||||
const extensionPane = getDebugTargetPane("Extensions", document);
|
||||
info("Check an empty target pane message is displayed");
|
||||
|
|
|
@ -13,31 +13,39 @@ add_task(async function() {
|
|||
const { document, tab } = await openAboutDebugging();
|
||||
|
||||
for (const { title } of TARGET_PANES) {
|
||||
const debugTargetPaneEl = getDebugTargetPane(title, document);
|
||||
|
||||
info("Check whether this pane is collapsed after clicking the title");
|
||||
await toggleCollapsibility(debugTargetPaneEl);
|
||||
assertCollapsibility(debugTargetPaneEl, title, true);
|
||||
await toggleCollapsibility(getDebugTargetPane(title, document));
|
||||
assertDebugTargetCollapsed(getDebugTargetPane(title, document), title);
|
||||
|
||||
info("Check whether this pane is expanded after clicking the title again");
|
||||
await toggleCollapsibility(debugTargetPaneEl);
|
||||
assertCollapsibility(debugTargetPaneEl, title, false);
|
||||
await toggleCollapsibility(getDebugTargetPane(title, document));
|
||||
await assertDebugTargetExpanded(getDebugTargetPane(title, document), title);
|
||||
}
|
||||
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
function assertCollapsibility(debugTargetPaneEl, title, shouldCollapsed) {
|
||||
info("Check height of list");
|
||||
const listEl = debugTargetPaneEl.querySelector(".js-debug-target-list");
|
||||
const assertHeight = shouldCollapsed ? is : isnot;
|
||||
assertHeight(listEl.clientHeight, 0, "Height of list element should correct");
|
||||
async function assertDebugTargetCollapsed(paneEl, title) {
|
||||
info("Check debug target is collapsed");
|
||||
|
||||
info("Check content of title");
|
||||
const titleEl = debugTargetPaneEl.querySelector(".js-debug-target-pane-title");
|
||||
// check list height
|
||||
const listEl = paneEl.querySelector(".js-debug-target-list");
|
||||
is(listEl.clientHeight, 0, "Height of list element is zero");
|
||||
// check title
|
||||
const titleEl = paneEl.querySelector(".js-debug-target-pane-title");
|
||||
const expectedTitle =
|
||||
shouldCollapsed
|
||||
? `${ title } (${ listEl.querySelectorAll(".js-debug-target-item").length })`
|
||||
: title;
|
||||
is(titleEl.textContent, expectedTitle, "Title should correct");
|
||||
`${ title } (${ listEl.querySelectorAll(".js-debug-target-item").length })`;
|
||||
is(titleEl.textContent, expectedTitle, "Collapsed title is correct");
|
||||
}
|
||||
|
||||
async function assertDebugTargetExpanded(paneEl, title) {
|
||||
info("Check debug target is expanded");
|
||||
|
||||
// check list height
|
||||
const listEl = paneEl.querySelector(".js-debug-target-list");
|
||||
await waitUntil(() => listEl.clientHeight > 0);
|
||||
ok(true, "Height of list element is greater than zero");
|
||||
// check title
|
||||
const titleEl = paneEl.querySelector(".js-debug-target-pane-title");
|
||||
is(titleEl.textContent, title, "Expanded title is correct");
|
||||
}
|
||||
|
|
|
@ -26,7 +26,8 @@ add_task(async function() {
|
|||
});
|
||||
usbMocks.emitUpdate();
|
||||
|
||||
await connectToRuntime(RUNTIME_DEVICE_NAME, RUNTIME_APP_NAME, document);
|
||||
await connectToRuntime(RUNTIME_DEVICE_NAME, document);
|
||||
await selectRuntime(RUNTIME_DEVICE_NAME, RUNTIME_APP_NAME, document);
|
||||
|
||||
const SUPPORTED_TARGET_PANES = [
|
||||
"Extensions",
|
||||
|
|
|
@ -40,7 +40,9 @@ add_task(async function() {
|
|||
|
||||
info("Wait until Connect page is displayed");
|
||||
await waitUntil(() => document.querySelector(".js-connect-page"));
|
||||
ok(isSidebarItemSelected(connectSidebarItem), "Connect sidebar item is selected");
|
||||
// we need to wait here because the sidebar isn't updated after mounting the page
|
||||
info("Wait until Connect sidebar item is selected");
|
||||
await waitUntil(() => isSidebarItemSelected(connectSidebarItem));
|
||||
ok(!document.querySelector(".js-runtime-page"), "Runtime page no longer rendered");
|
||||
|
||||
info("Open a new tab which should be listed when we go back to This Firefox");
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const RUNTIME_ID = "test-runtime-id";
|
||||
const RUNTIME_DEVICE_NAME = "test device name";
|
||||
const RUNTIME_APP_NAME = "TestApp";
|
||||
|
||||
/* import-globals-from mocks/head-usb-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "mocks/head-usb-mocks.js", this);
|
||||
|
||||
// Test that remote runtime connections are persisted across about:debugging reloads.
|
||||
add_task(async function() {
|
||||
const usbMocks = new UsbMocks();
|
||||
usbMocks.enableMocks();
|
||||
registerCleanupFunction(() => usbMocks.disableMocks());
|
||||
|
||||
let { document, tab } = await openAboutDebugging();
|
||||
|
||||
const usbClient = usbMocks.createRuntime(RUNTIME_ID, {
|
||||
name: RUNTIME_APP_NAME,
|
||||
deviceName: RUNTIME_DEVICE_NAME,
|
||||
});
|
||||
usbMocks.emitUpdate();
|
||||
|
||||
await connectToRuntime(RUNTIME_DEVICE_NAME, document);
|
||||
await selectRuntime(RUNTIME_DEVICE_NAME, RUNTIME_APP_NAME, document);
|
||||
|
||||
info("Reload about:debugging");
|
||||
document = await reloadAboutDebugging(tab);
|
||||
usbMocks.emitUpdate();
|
||||
|
||||
info("Wait until the remote runtime appears as connected");
|
||||
await waitUntil(() => {
|
||||
const sidebarItem = findSidebarItemByText(RUNTIME_DEVICE_NAME, document);
|
||||
return sidebarItem && !sidebarItem.querySelector(".js-connect-button");
|
||||
});
|
||||
|
||||
// Remove the runtime without emitting an update.
|
||||
// This is what happens today when we simply close Firefox for Android.
|
||||
info("Remove the runtime from the list of USB runtimes");
|
||||
usbMocks.removeRuntime(RUNTIME_ID);
|
||||
|
||||
info("Emit 'closed' on the client and wait for the sidebar item to disappear");
|
||||
usbClient._eventEmitter.emit("closed");
|
||||
await waitUntil(() => !findSidebarItemByText(RUNTIME_DEVICE_NAME, document));
|
||||
|
||||
info("Remove the tab");
|
||||
await removeTab(tab);
|
||||
});
|
|
@ -0,0 +1,78 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from mocks/head-usb-mocks.js */
|
||||
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "mocks/head-usb-mocks.js", this);
|
||||
|
||||
/**
|
||||
* Test that the initial route is /runtime/this-firefox
|
||||
*/
|
||||
add_task(async function() {
|
||||
info("Check root route redirects to 'This Firefox'");
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
is(document.location.hash, "#/runtime/this-firefox");
|
||||
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that the routes in about:debugging show the proper views
|
||||
*/
|
||||
add_task(async function() {
|
||||
// enable USB devices mocks
|
||||
const usbMocks = new UsbMocks();
|
||||
usbMocks.enableMocks();
|
||||
registerCleanupFunction(() => usbMocks.disableMocks());
|
||||
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
|
||||
info("Check 'This Firefox' route");
|
||||
document.location.hash = "#/runtime/this-firefox";
|
||||
await waitUntil(() => document.querySelector(".js-runtime-page"));
|
||||
const infoLabel = document.querySelector(".js-runtime-info").textContent;
|
||||
// NOTE: when using USB Mocks, we see only "Firefox" as the device name
|
||||
ok(infoLabel.includes("Firefox"), "Runtime is displayed as Firefox");
|
||||
ok(!infoLabel.includes(" on "), "Runtime is not associated to any device");
|
||||
|
||||
info("Check 'Connect' page");
|
||||
document.location.hash = "#/connect";
|
||||
await waitUntil(() => document.querySelector(".js-connect-page"));
|
||||
ok(true, "Connect page has been shown");
|
||||
|
||||
info("Check 'USB device runtime' page");
|
||||
// connect to a mocked USB runtime
|
||||
usbMocks.createRuntime("1337id", {
|
||||
deviceName: "Fancy Phone",
|
||||
name: "Lorem ipsum",
|
||||
});
|
||||
usbMocks.emitUpdate();
|
||||
await connectToRuntime("Fancy Phone", document);
|
||||
// navigate to it via URL
|
||||
document.location.hash = "#/runtime/1337id";
|
||||
await waitUntil(() => document.querySelector(".js-runtime-page"));
|
||||
const runtimeLabel = document.querySelector(".js-runtime-info").textContent;
|
||||
ok(runtimeLabel.includes("Lorem ipsum"), "Runtime is displayed with the mocked name");
|
||||
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Test that an invalid route redirects to / (currently This Firefox page)
|
||||
*/
|
||||
add_task(async function() {
|
||||
info("Check an invalid route redirects to root");
|
||||
const { document, tab } = await openAboutDebugging();
|
||||
|
||||
info("Waiting for a non-runtime page to load");
|
||||
document.location.hash = "#/connect";
|
||||
await waitUntil(() => document.querySelector(".js-connect-page"));
|
||||
|
||||
info("Update hash & wait for a redirect to root ('This Firefox')");
|
||||
document.location.hash = "#/lorem-ipsum";
|
||||
await waitUntil(() => document.querySelector(".js-runtime-page"));
|
||||
is(document.location.hash, "#/runtime/this-firefox", "Redirected to root");
|
||||
|
||||
await removeTab(tab);
|
||||
});
|
|
@ -28,7 +28,8 @@ add_task(async function() {
|
|||
});
|
||||
usbMocks.emitUpdate();
|
||||
|
||||
await connectToRuntime(RUNTIME_DEVICE_NAME, RUNTIME_APP_NAME, document);
|
||||
await connectToRuntime(RUNTIME_DEVICE_NAME, document);
|
||||
await selectRuntime(RUNTIME_DEVICE_NAME, RUNTIME_APP_NAME, document);
|
||||
|
||||
info("Create a second runtime and click on Refresh Devices");
|
||||
usbMocks.createRuntime(OTHER_RUNTIME_ID, {
|
||||
|
|
|
@ -59,7 +59,7 @@ function setupThisFirefoxMock() {
|
|||
runtimeClientFactoryMock.createClientForRuntime = runtime => {
|
||||
const { RUNTIMES } = require("devtools/client/aboutdebugging-new/src/constants");
|
||||
if (runtime.id === RUNTIMES.THIS_FIREFOX) {
|
||||
return { clientWrapper: thisFirefoxClient };
|
||||
return thisFirefoxClient;
|
||||
}
|
||||
throw new Error("Unexpected runtime id " + runtime.id);
|
||||
};
|
||||
|
|
|
@ -23,7 +23,7 @@ add_task(async function() {
|
|||
runtimeClientFactoryMock.createClientForRuntime = runtime => {
|
||||
const { RUNTIMES } = require("devtools/client/aboutdebugging-new/src/constants");
|
||||
if (runtime.id === RUNTIMES.THIS_FIREFOX) {
|
||||
return { clientWrapper: thisFirefoxClient };
|
||||
return thisFirefoxClient;
|
||||
}
|
||||
throw new Error("Unexpected runtime id " + runtime.id);
|
||||
};
|
||||
|
|
|
@ -33,8 +33,14 @@ const TARGET_PANES = [
|
|||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function getDebugTargetPane(title, document) {
|
||||
// removes the suffix "(<NUMBER>)" in debug target pane's title, if needed
|
||||
const sanitizeTitle = (x) => {
|
||||
return x.replace(/\s+\(\d+\)$/, "");
|
||||
};
|
||||
|
||||
const targetTitle = sanitizeTitle(title);
|
||||
for (const titleEl of document.querySelectorAll(".js-debug-target-pane-title")) {
|
||||
if (titleEl.textContent !== title) {
|
||||
if (sanitizeTitle(titleEl.textContent) !== targetTitle) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,10 @@ registerCleanupFunction(async function() {
|
|||
}
|
||||
const { ADB } = require("devtools/shared/adb/adb");
|
||||
await ADB.kill();
|
||||
|
||||
const { remoteClientManager } =
|
||||
require("devtools/client/shared/remote-debugging/remote-client-manager");
|
||||
await remoteClientManager.removeAllClients();
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -46,19 +50,37 @@ async function openAboutDebugging(page, win) {
|
|||
await enableNewAboutDebugging();
|
||||
|
||||
info("opening about:debugging");
|
||||
|
||||
const tab = await addTab("about:debugging", { window: win });
|
||||
const browser = tab.linkedBrowser;
|
||||
const document = browser.contentDocument;
|
||||
const window = browser.contentWindow;
|
||||
const { AboutDebugging } = window;
|
||||
await waitForInitialDispatch(window);
|
||||
|
||||
await Promise.all([
|
||||
return { tab, document, window };
|
||||
}
|
||||
|
||||
async function reloadAboutDebugging(tab) {
|
||||
info("reload about:debugging");
|
||||
|
||||
await refreshTab(tab);
|
||||
const browser = tab.linkedBrowser;
|
||||
const document = browser.contentDocument;
|
||||
const window = browser.contentWindow;
|
||||
await waitForInitialDispatch(window);
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
function waitForInitialDispatch(win) {
|
||||
info("wait for the initial about debugging actions to be dispatched");
|
||||
|
||||
const { AboutDebugging } = win;
|
||||
return Promise.all([
|
||||
waitForDispatch(AboutDebugging.store, "REQUEST_EXTENSIONS_SUCCESS"),
|
||||
waitForDispatch(AboutDebugging.store, "REQUEST_TABS_SUCCESS"),
|
||||
waitForDispatch(AboutDebugging.store, "REQUEST_WORKERS_SUCCESS"),
|
||||
]);
|
||||
|
||||
return { tab, document, window };
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,7 +162,7 @@ function findSidebarItemByText(text, document) {
|
|||
});
|
||||
}
|
||||
|
||||
async function connectToRuntime(deviceName, appName, document) {
|
||||
async function connectToRuntime(deviceName, document) {
|
||||
info(`Wait until the sidebar item for ${deviceName} appears`);
|
||||
await waitUntil(() => findSidebarItemByText(deviceName, document));
|
||||
const sidebarItem = findSidebarItemByText(deviceName, document);
|
||||
|
@ -150,11 +172,14 @@ async function connectToRuntime(deviceName, appName, document) {
|
|||
info("Click on the connect button and wait until it disappears");
|
||||
connectButton.click();
|
||||
await waitUntil(() => !sidebarItem.querySelector(".js-connect-button"));
|
||||
}
|
||||
|
||||
async function selectRuntime(deviceName, name, document) {
|
||||
const sidebarItem = findSidebarItemByText(deviceName, document);
|
||||
sidebarItem.querySelector(".js-sidebar-link").click();
|
||||
|
||||
await waitUntil(() => {
|
||||
const runtimeInfo = document.querySelector(".js-runtime-info");
|
||||
return runtimeInfo.textContent.includes(appName);
|
||||
return runtimeInfo.textContent.includes(name);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -35,6 +35,19 @@ function createClientMock() {
|
|||
removeListener: (evt, listener) => {
|
||||
eventEmitter.off(evt, listener);
|
||||
},
|
||||
|
||||
client: {
|
||||
addOneTimeListener: (evt, listener) => {
|
||||
eventEmitter.once(evt, listener);
|
||||
},
|
||||
addListener: (evt, listener) => {
|
||||
eventEmitter.on(evt, listener);
|
||||
},
|
||||
removeListener: (evt, listener) => {
|
||||
eventEmitter.off(evt, listener);
|
||||
},
|
||||
},
|
||||
|
||||
// no-op
|
||||
close: () => {},
|
||||
// no-op
|
||||
|
|
|
@ -28,6 +28,12 @@ class UsbMocks {
|
|||
return this._runtimes;
|
||||
};
|
||||
|
||||
// refreshUSBRuntimes normally starts scan, which should ultimately fire the
|
||||
// "runtime-list-updated" event.
|
||||
this.usbRuntimesMock.refreshUSBRuntimes = () => {
|
||||
this.emitUpdate();
|
||||
};
|
||||
|
||||
// Prepare a fake observer to be able to emit events from this mock.
|
||||
this._observerMock = addObserverMock(this.usbRuntimesMock);
|
||||
|
||||
|
@ -35,7 +41,7 @@ class UsbMocks {
|
|||
this.runtimeClientFactoryMock = createRuntimeClientFactoryMock();
|
||||
this._clients = {};
|
||||
this.runtimeClientFactoryMock.createClientForRuntime = runtime => {
|
||||
return { clientWrapper: this._clients[runtime.id] };
|
||||
return this._clients[runtime.id];
|
||||
};
|
||||
|
||||
// Add a client for THIS_FIREFOX, since about:debugging will start on the This Firefox
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
const { TargetFactory } = require("devtools/client/framework/target");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const { DebuggerClient } = require("devtools/shared/client/debugger-client");
|
||||
const { remoteClientManager } =
|
||||
require("devtools/client/shared/remote-debugging/remote-client-manager");
|
||||
|
||||
/**
|
||||
* Construct a Target for a given URL object having various query parameters:
|
||||
|
@ -39,9 +41,14 @@ const { DebuggerClient } = require("devtools/shared/client/debugger-client");
|
|||
*/
|
||||
exports.targetFromURL = async function targetFromURL(url) {
|
||||
const client = await clientFromURL(url);
|
||||
await client.connect();
|
||||
|
||||
const params = url.searchParams;
|
||||
|
||||
// Clients retrieved from the remote-client-manager are already connected.
|
||||
if (!params.get("remoteId")) {
|
||||
// Connect any other client.
|
||||
await client.connect();
|
||||
}
|
||||
|
||||
const type = params.get("type");
|
||||
if (!type) {
|
||||
throw new Error("targetFromURL, missing type parameter");
|
||||
|
@ -116,6 +123,8 @@ exports.targetFromURL = async function targetFromURL(url) {
|
|||
* {String} The hostname or IP address to connect to.
|
||||
* port:
|
||||
* {Number} The TCP port to connect to, to use with `host` argument.
|
||||
* remoteId:
|
||||
* {String} Remote client id, for runtimes from the remote-client-manager
|
||||
* ws:
|
||||
* {Boolean} If true, connect via websocket instead of regular TCP connection.
|
||||
*
|
||||
|
@ -125,6 +134,13 @@ exports.targetFromURL = async function targetFromURL(url) {
|
|||
*/
|
||||
async function clientFromURL(url) {
|
||||
const params = url.searchParams;
|
||||
|
||||
// If a remote id was provided we should already have a connected client available.
|
||||
const remoteId = params.get("remoteId");
|
||||
if (remoteId) {
|
||||
return remoteClientManager.getClientByRemoteId(remoteId);
|
||||
}
|
||||
|
||||
const host = params.get("host");
|
||||
const port = params.get("port");
|
||||
const webSocket = !!params.get("ws");
|
||||
|
|
|
@ -13,6 +13,7 @@ TEST_HARNESS_FILES.xpcshell.devtools.client.shared.test += [
|
|||
DIRS += [
|
||||
'components',
|
||||
'redux',
|
||||
'remote-debugging',
|
||||
'source-map',
|
||||
'vendor',
|
||||
'webpack',
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
DevToolsModules(
|
||||
'Devices.jsm'
|
||||
'remote-client-manager.js',
|
||||
)
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('DevTools', 'about:debugging')
|
|
@ -0,0 +1,98 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* This class is designed to be a singleton shared by all DevTools to get access to
|
||||
* existing clients created for remote debugging.
|
||||
*/
|
||||
class RemoteClientManager {
|
||||
constructor() {
|
||||
this._clients = new Map();
|
||||
this._onClientClosed = this._onClientClosed.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a remote client that is already connected.
|
||||
*
|
||||
* @param {String} id
|
||||
* Remote runtime id (see devtools/client/aboutdebugging-new/src/types).
|
||||
* @param {String} type
|
||||
* Remote runtime type (see devtools/client/aboutdebugging-new/src/types).
|
||||
* @param {DebuggerClient} client
|
||||
*/
|
||||
setClient(id, type, client) {
|
||||
const key = this._getKey(id, type);
|
||||
this._clients.set(key, client);
|
||||
client.addOneTimeListener("closed", this._onClientClosed);
|
||||
}
|
||||
|
||||
// See JSDoc for id, type from setClient.
|
||||
hasClient(id, type) {
|
||||
return this._clients.has(this._getKey(id, type));
|
||||
}
|
||||
|
||||
// See JSDoc for id, type from setClient.
|
||||
getClient(id, type) {
|
||||
return this._clients.get(this._getKey(id, type));
|
||||
}
|
||||
|
||||
// See JSDoc for id, type from setClient.
|
||||
removeClient(id, type) {
|
||||
const key = this._getKey(id, type);
|
||||
this._removeClientByKey(key);
|
||||
}
|
||||
|
||||
removeAllClients() {
|
||||
const keys = [...this._clients.keys()];
|
||||
for (const key of keys) {
|
||||
this._removeClientByKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a unique, url-safe key based on a runtime id and type.
|
||||
*/
|
||||
getRemoteId(id, type) {
|
||||
return encodeURIComponent(this._getKey(id, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a managed client for a remote id. The remote id should have been generated
|
||||
* using getRemoteId.
|
||||
*/
|
||||
getClientByRemoteId(remoteId) {
|
||||
const key = decodeURIComponent(remoteId);
|
||||
return this._clients.get(key);
|
||||
}
|
||||
|
||||
_getKey(id, type) {
|
||||
return id + "-" + type;
|
||||
}
|
||||
|
||||
_removeClientByKey(key) {
|
||||
const client = this._clients.get(key);
|
||||
if (client) {
|
||||
client.removeListener("closed", this._onClientClosed);
|
||||
this._clients.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup all closed clients when a "closed" notification is received from a client.
|
||||
*/
|
||||
_onClientClosed() {
|
||||
const closedClientKeys = [...this._clients.keys()].filter(key => {
|
||||
return this._clients.get(key)._closed;
|
||||
});
|
||||
|
||||
for (const key of closedClientKeys) {
|
||||
this._removeClientByKey(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expose a singleton of RemoteClientManager.
|
||||
exports.remoteClientManager = new RemoteClientManager();
|
|
@ -0,0 +1,23 @@
|
|||
[//]: # (
|
||||
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/.
|
||||
)
|
||||
|
||||
Follow this steps to upgrade the `react-router-dom` library:
|
||||
|
||||
1. Clone the repository (note: this is a monorepository, it includes other libraries too):
|
||||
`git clone git@github.com:ReactTraining/react-router.git`
|
||||
|
||||
2. Install build dependencies:
|
||||
`cd react-router`
|
||||
`npm install`
|
||||
|
||||
3. Run a build :
|
||||
`npm run build`
|
||||
|
||||
4. Grab the UMD build of `react-router-dom`, which is located in `packages/react-router-dom/umd/react-router-dom.js` and copy it into Firefox source tree.
|
||||
|
||||
5. Edit `react-router-dom.js` and change `require('react')` for `require('devtools/client/shared/vendor/react')`
|
||||
|
||||
6. Update the version below:
|
||||
|
||||
The current version is 4.3.1
|
|
@ -21,6 +21,7 @@ DevToolsModules(
|
|||
'react-dom.js',
|
||||
'react-prop-types.js',
|
||||
'react-redux.js',
|
||||
'react-router-dom.js',
|
||||
'react-test-renderer-shallow.js',
|
||||
'react.js',
|
||||
'redux.js',
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -8,7 +8,8 @@ const Services = require("Services");
|
|||
const {AppManager} = require("devtools/client/webide/modules/app-manager");
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const {RuntimeScanners, WiFiScanner} = require("devtools/client/webide/modules/runtimes");
|
||||
const {Devices} = require("resource://devtools/shared/apps/Devices.jsm");
|
||||
const { adbAddon, ADB_ADDON_STATES } = require("devtools/shared/adb/adb-addon");
|
||||
|
||||
const Strings = Services.strings.createBundle("chrome://devtools/locale/webide.properties");
|
||||
|
||||
var RuntimeList;
|
||||
|
@ -141,7 +142,7 @@ RuntimeList.prototype = {
|
|||
noADBExtensionNode.textContent =
|
||||
Strings.formatStringFromName("runtimePanel_noadbextension", ["ADB Extension"], 1);
|
||||
|
||||
if (Devices.adbExtensionInstalled) {
|
||||
if (adbAddon.status === ADB_ADDON_STATES.INSTALLED) {
|
||||
noADBExtensionNode.setAttribute("hidden", "true");
|
||||
} else {
|
||||
noADBExtensionNode.removeAttribute("hidden");
|
||||
|
@ -153,7 +154,7 @@ RuntimeList.prototype = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (runtimeList.usb.length === 0 && Devices.adbExtensionInstalled) {
|
||||
if (runtimeList.usb.length === 0 && adbAddon.status === ADB_ADDON_STATES.INSTALLED) {
|
||||
noUSBNode.removeAttribute("hidden");
|
||||
} else {
|
||||
noUSBNode.setAttribute("hidden", "true");
|
||||
|
|
|
@ -21,15 +21,18 @@
|
|||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const {Devices} = ChromeUtils.import("resource://devtools/shared/apps/Devices.jsm", {});
|
||||
const { adbAddon, ADB_ADDON_STATES } = require("devtools/shared/adb/adb-addon");
|
||||
function isAdbAddonInstalled() {
|
||||
return adbAddon.status === ADB_ADDON_STATES.INSTALLED;
|
||||
}
|
||||
|
||||
function uninstallADBFromUI(doc) {
|
||||
return new Promise((resolve, reject) => {
|
||||
Devices.on("addon-status-updated", function onUpdate() {
|
||||
adbAddon.on("update", function onUpdate() {
|
||||
nextTick().then(() => {
|
||||
const li = doc.querySelector('[status="uninstalled"][addon="adb"]');
|
||||
if (li) {
|
||||
Devices.off("addon-status-updated", onUpdate);
|
||||
adbAddon.off("update", onUpdate);
|
||||
resolve();
|
||||
} else {
|
||||
reject("Can't find item");
|
||||
|
@ -42,16 +45,16 @@
|
|||
}
|
||||
|
||||
(async function() {
|
||||
ok(!Devices.adbExtensionInstalled, "ADB extension not installed");
|
||||
ok(!isAdbAddonInstalled(), "ADB extension not installed");
|
||||
|
||||
const win = await openWebIDE(true);
|
||||
|
||||
// ADB is installed asynchronously after starting WebIDE.
|
||||
while (!Devices.adbExtensionInstalled) {
|
||||
await Devices.once("addon-status-updated");
|
||||
while (!isAdbAddonInstalled()) {
|
||||
await adbAddon.once("update");
|
||||
}
|
||||
|
||||
ok(Devices.adbExtensionInstalled, "ADB extension has been auto-installed");
|
||||
ok(isAdbAddonInstalled(), "ADB extension has been auto-installed");
|
||||
|
||||
await nextTick();
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* 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/. */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* 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/. */
|
||||
|
|
|
@ -10,24 +10,44 @@ const { ADB } = require("devtools/shared/adb/adb");
|
|||
* A Device instance is created and registered with the Devices module whenever
|
||||
* ADB notices a new device is connected.
|
||||
*/
|
||||
function Device(id) {
|
||||
this.id = id;
|
||||
class AdbDevice {
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
async getModel() {
|
||||
if (this._model) {
|
||||
return this._model;
|
||||
}
|
||||
const model = await ADB.shell("getprop ro.product.model");
|
||||
this._model = model.trim();
|
||||
return this._model;
|
||||
}
|
||||
|
||||
// This method is not using any information from the instance, but in theory getting
|
||||
// runtime socket paths (as well as model) should be device specific. So we should use
|
||||
// information available on the instance when implementing multi device support.
|
||||
// See Bug 1507126.
|
||||
async getRuntimeSocketPaths() {
|
||||
// A matching entry looks like:
|
||||
// 00000000: 00000002 00000000 00010000 0001 01 6551588
|
||||
// /data/data/org.mozilla.fennec/firefox-debugger-socket
|
||||
const query = "cat /proc/net/unix";
|
||||
const rawSocketInfo = await ADB.shell(query);
|
||||
|
||||
// Filter to lines with "firefox-debugger-socket"
|
||||
let socketInfos = rawSocketInfo.split(/\r?\n/);
|
||||
socketInfos = socketInfos.filter(l => l.includes("firefox-debugger-socket"));
|
||||
|
||||
// It's possible to have multiple lines with the same path, so de-dupe them
|
||||
const socketPaths = new Set();
|
||||
for (const socketInfo of socketInfos) {
|
||||
const socketPath = socketInfo.split(" ").pop();
|
||||
socketPaths.add(socketPath);
|
||||
}
|
||||
|
||||
return socketPaths;
|
||||
}
|
||||
}
|
||||
|
||||
Device.prototype = {
|
||||
type: "adb",
|
||||
|
||||
shell: ADB.shell.bind(ADB),
|
||||
|
||||
getModel() {
|
||||
if (this._modelPromise) {
|
||||
return this._modelPromise;
|
||||
}
|
||||
this._modelPromise = this.shell("getprop ro.product.model")
|
||||
.then(model => model.trim());
|
||||
return this._modelPromise;
|
||||
},
|
||||
// push, pull were removed in Bug 1481691.
|
||||
};
|
||||
|
||||
module.exports = Device;
|
||||
module.exports = AdbDevice;
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { adbAddon, ADB_ADDON_STATES } = require("devtools/shared/adb/adb-addon");
|
||||
|
||||
/**
|
||||
* Shared registry that will hold all the detected devices from ADB.
|
||||
* Extends EventEmitter and emits the following events:
|
||||
* - "register": a new device has been registered
|
||||
* - "unregister": a device has been unregistered
|
||||
*/
|
||||
class AdbDevicesRegistry extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
// Internal object to store the discovered adb devices.
|
||||
this._devices = {};
|
||||
|
||||
// When the addon is uninstalled, the repository should be emptied.
|
||||
// TODO: This should also be done when ADB is stopped.
|
||||
this._onAdbAddonUpdate = this._onAdbAddonUpdate.bind(this);
|
||||
adbAddon.on("update", this._onAdbAddonUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a device (Device class defined in from adb-device.js) for the provided name.
|
||||
*
|
||||
* @param {String} name
|
||||
* Name of the device.
|
||||
* @param {AdbDevice} device
|
||||
* The device to register.
|
||||
*/
|
||||
register(name, device) {
|
||||
this._devices[name] = device;
|
||||
this.emit("register");
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a device previously registered under the provided name.
|
||||
*
|
||||
* @param {String} name
|
||||
* Name of the device.
|
||||
*/
|
||||
unregister(name) {
|
||||
delete this._devices[name];
|
||||
this.emit("unregister");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterable containing the name of all the available devices, sorted by name.
|
||||
*/
|
||||
available() {
|
||||
return Object.keys(this._devices).sort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a device previously registered under the provided name.
|
||||
*
|
||||
* @param {String} name
|
||||
* Name of the device.
|
||||
*/
|
||||
getByName(name) {
|
||||
return this._devices[name];
|
||||
}
|
||||
|
||||
_onAdbAddonUpdate() {
|
||||
const installed = adbAddon.status === ADB_ADDON_STATES.INSTALLED;
|
||||
if (!installed) {
|
||||
for (const name in this._devices) {
|
||||
this.unregister(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.adbDevicesRegistry = new AdbDevicesRegistry();
|
|
@ -0,0 +1,73 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { RuntimeTypes } = require("devtools/client/webide/modules/runtime-types");
|
||||
const { ADB } = require("devtools/shared/adb/adb");
|
||||
|
||||
class AdbRuntime {
|
||||
constructor(adbDevice, model, socketPath) {
|
||||
this.type = RuntimeTypes.USB;
|
||||
|
||||
this._adbDevice = adbDevice;
|
||||
this._model = model;
|
||||
this._socketPath = socketPath;
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._adbDevice.id + "|" + this._socketPath;
|
||||
}
|
||||
|
||||
get deviceName() {
|
||||
return this._model || this._adbDevice.id;
|
||||
}
|
||||
|
||||
get shortName() {
|
||||
return `Firefox ${this._channel()}`;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return `Firefox ${this._channel()} on Android (${this.deviceName})`;
|
||||
}
|
||||
|
||||
connect(connection) {
|
||||
return ADB.prepareTCPConnection(this._socketPath).then(port => {
|
||||
connection.host = "localhost";
|
||||
connection.port = port;
|
||||
connection.connect();
|
||||
});
|
||||
}
|
||||
|
||||
_channel() {
|
||||
const packageName = this._packageName();
|
||||
|
||||
switch (packageName) {
|
||||
case "org.mozilla.firefox":
|
||||
return "";
|
||||
case "org.mozilla.firefox_beta":
|
||||
return "Beta";
|
||||
case "org.mozilla.fennec":
|
||||
case "org.mozilla.fennec_aurora":
|
||||
// This package name is now the one for Firefox Nightly distributed
|
||||
// through the Google Play Store since "dawn project"
|
||||
// cf. https://bugzilla.mozilla.org/show_bug.cgi?id=1357351#c8
|
||||
return "Nightly";
|
||||
default:
|
||||
return "Custom";
|
||||
}
|
||||
}
|
||||
|
||||
_packageName() {
|
||||
// If using abstract socket address, it is "@org.mozilla.firefox/..."
|
||||
// If using path base socket, it is "/data/data/<package>...""
|
||||
// Until Fennec 62 only supports path based UNIX domain socket, but
|
||||
// Fennec 63+ supports both path based and abstract socket.
|
||||
return this._socketPath.startsWith("@") ?
|
||||
this._socketPath.substr(1).split("/")[0] :
|
||||
this._socketPath.split("/")[3];
|
||||
}
|
||||
}
|
||||
|
||||
exports.AdbRuntime = AdbRuntime;
|
|
@ -5,12 +5,12 @@
|
|||
"use strict";
|
||||
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { Devices } = require("devtools/shared/apps/Devices.jsm");
|
||||
const { dumpn } = require("devtools/shared/DevToolsUtils");
|
||||
const { RuntimeTypes } =
|
||||
require("devtools/client/webide/modules/runtime-types");
|
||||
const { ADB } = require("devtools/shared/adb/adb");
|
||||
loader.lazyRequireGetter(this, "Device", "devtools/shared/adb/adb-device");
|
||||
const { adbDevicesRegistry } = require("devtools/shared/adb/adb-devices-registry");
|
||||
const { AdbRuntime } = require("devtools/shared/adb/adb-runtime");
|
||||
|
||||
loader.lazyRequireGetter(this, "AdbDevice", "devtools/shared/adb/adb-device");
|
||||
|
||||
class ADBScanner extends EventEmitter {
|
||||
constructor() {
|
||||
|
@ -26,9 +26,8 @@ class ADBScanner extends EventEmitter {
|
|||
EventEmitter.on(ADB, "device-connected", this._onDeviceConnected);
|
||||
EventEmitter.on(ADB, "device-disconnected", this._onDeviceDisconnected);
|
||||
|
||||
Devices.on("register", this._updateRuntimes);
|
||||
Devices.on("unregister", this._updateRuntimes);
|
||||
Devices.on("addon-status-updated", this._updateRuntimes);
|
||||
adbDevicesRegistry.on("register", this._updateRuntimes);
|
||||
adbDevicesRegistry.on("unregister", this._updateRuntimes);
|
||||
|
||||
ADB.start().then(() => {
|
||||
ADB.trackDevices();
|
||||
|
@ -39,9 +38,9 @@ class ADBScanner extends EventEmitter {
|
|||
disable() {
|
||||
EventEmitter.off(ADB, "device-connected", this._onDeviceConnected);
|
||||
EventEmitter.off(ADB, "device-disconnected", this._onDeviceDisconnected);
|
||||
Devices.off("register", this._updateRuntimes);
|
||||
Devices.off("unregister", this._updateRuntimes);
|
||||
Devices.off("addon-status-updated", this._updateRuntimes);
|
||||
adbDevicesRegistry.off("register", this._updateRuntimes);
|
||||
adbDevicesRegistry.off("unregister", this._updateRuntimes);
|
||||
this._updateRuntimes();
|
||||
}
|
||||
|
||||
_emitUpdated() {
|
||||
|
@ -49,12 +48,12 @@ class ADBScanner extends EventEmitter {
|
|||
}
|
||||
|
||||
_onDeviceConnected(deviceId) {
|
||||
const device = new Device(deviceId);
|
||||
Devices.register(deviceId, device);
|
||||
const device = new AdbDevice(deviceId);
|
||||
adbDevicesRegistry.register(deviceId, device);
|
||||
}
|
||||
|
||||
_onDeviceDisconnected(deviceId) {
|
||||
Devices.unregister(deviceId);
|
||||
adbDevicesRegistry.unregister(deviceId);
|
||||
}
|
||||
|
||||
_updateRuntimes() {
|
||||
|
@ -63,8 +62,8 @@ class ADBScanner extends EventEmitter {
|
|||
}
|
||||
this._runtimes = [];
|
||||
const promises = [];
|
||||
for (const id of Devices.available()) {
|
||||
const device = Devices.getByName(id);
|
||||
for (const id of adbDevicesRegistry.available()) {
|
||||
const device = adbDevicesRegistry.getByName(id);
|
||||
promises.push(this._detectRuntimes(device));
|
||||
}
|
||||
this._updatingPromise = Promise.all(promises);
|
||||
|
@ -77,11 +76,14 @@ class ADBScanner extends EventEmitter {
|
|||
return this._updatingPromise;
|
||||
}
|
||||
|
||||
async _detectRuntimes(device) {
|
||||
const model = await device.getModel();
|
||||
const detectedRuntimes =
|
||||
await FirefoxOnAndroidRuntime.detect(device, model);
|
||||
this._runtimes.push(...detectedRuntimes);
|
||||
async _detectRuntimes(adbDevice) {
|
||||
const model = await adbDevice.getModel();
|
||||
const socketPaths = await adbDevice.getRuntimeSocketPaths();
|
||||
for (const socketPath of socketPaths) {
|
||||
const runtime = new AdbRuntime(adbDevice, model, socketPath);
|
||||
dumpn("Found " + runtime.name);
|
||||
this._runtimes.push(runtime);
|
||||
}
|
||||
}
|
||||
|
||||
scan() {
|
||||
|
@ -93,103 +95,4 @@ class ADBScanner extends EventEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
function Runtime(device, model, socketPath) {
|
||||
this.device = device;
|
||||
this._model = model;
|
||||
this._socketPath = socketPath;
|
||||
}
|
||||
|
||||
Runtime.prototype = {
|
||||
type: RuntimeTypes.USB,
|
||||
connect(connection) {
|
||||
return ADB.prepareTCPConnection(this._socketPath).then(port => {
|
||||
connection.host = "localhost";
|
||||
connection.port = port;
|
||||
connection.connect();
|
||||
});
|
||||
},
|
||||
get id() {
|
||||
return this.device.id + "|" + this._socketPath;
|
||||
},
|
||||
};
|
||||
|
||||
function FirefoxOnAndroidRuntime(device, model, socketPath) {
|
||||
Runtime.call(this, device, model, socketPath);
|
||||
}
|
||||
|
||||
// This requires Unix socket support from Firefox for Android (35+)
|
||||
FirefoxOnAndroidRuntime.detect = async function(device, model) {
|
||||
const runtimes = [];
|
||||
// A matching entry looks like:
|
||||
// 00000000: 00000002 00000000 00010000 0001 01 6551588
|
||||
// /data/data/org.mozilla.fennec/firefox-debugger-socket
|
||||
const query = "cat /proc/net/unix";
|
||||
const rawSocketInfo = await device.shell(query);
|
||||
let socketInfos = rawSocketInfo.split(/\r?\n/);
|
||||
// Filter to lines with "firefox-debugger-socket"
|
||||
socketInfos = socketInfos.filter(l => l.includes("firefox-debugger-socket"));
|
||||
// It's possible to have multiple lines with the same path, so de-dupe them
|
||||
const socketPaths = new Set();
|
||||
for (const socketInfo of socketInfos) {
|
||||
const socketPath = socketInfo.split(" ").pop();
|
||||
socketPaths.add(socketPath);
|
||||
}
|
||||
for (const socketPath of socketPaths) {
|
||||
const runtime = new FirefoxOnAndroidRuntime(device, model, socketPath);
|
||||
dumpn("Found " + runtime.name);
|
||||
runtimes.push(runtime);
|
||||
}
|
||||
return runtimes;
|
||||
};
|
||||
|
||||
FirefoxOnAndroidRuntime.prototype = Object.create(Runtime.prototype);
|
||||
|
||||
FirefoxOnAndroidRuntime.prototype._channel = function() {
|
||||
const packageName = this._packageName();
|
||||
|
||||
switch (packageName) {
|
||||
case "org.mozilla.firefox":
|
||||
return "";
|
||||
case "org.mozilla.firefox_beta":
|
||||
return "Beta";
|
||||
case "org.mozilla.fennec":
|
||||
case "org.mozilla.fennec_aurora":
|
||||
// This package name is now the one for Firefox Nightly distributed
|
||||
// through the Google Play Store since "dawn project"
|
||||
// cf. https://bugzilla.mozilla.org/show_bug.cgi?id=1357351#c8
|
||||
return "Nightly";
|
||||
default:
|
||||
return "Custom";
|
||||
}
|
||||
};
|
||||
|
||||
FirefoxOnAndroidRuntime.prototype._packageName = function() {
|
||||
// If using abstract socket address, it is "@org.mozilla.firefox/..."
|
||||
// If using path base socket, it is "/data/data/<package>...""
|
||||
// Until Fennec 62 only supports path based UNIX domain socket, but
|
||||
// Fennec 63+ supports both path based and abstract socket.
|
||||
return this._socketPath.startsWith("@") ?
|
||||
this._socketPath.substr(1).split("/")[0] :
|
||||
this._socketPath.split("/")[3];
|
||||
};
|
||||
|
||||
Object.defineProperty(FirefoxOnAndroidRuntime.prototype, "shortName", {
|
||||
get() {
|
||||
return `Firefox ${this._channel()}`;
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(FirefoxOnAndroidRuntime.prototype, "deviceName", {
|
||||
get() {
|
||||
return this._model || this.device.id;
|
||||
},
|
||||
});
|
||||
|
||||
Object.defineProperty(FirefoxOnAndroidRuntime.prototype, "name", {
|
||||
get() {
|
||||
const channel = this._channel();
|
||||
return "Firefox " + channel + " on Android (" + this.deviceName + ")";
|
||||
},
|
||||
});
|
||||
|
||||
exports.ADBScanner = ADBScanner;
|
||||
|
|
|
@ -89,7 +89,6 @@ const ADB = {
|
|||
|
||||
const isAdbRunning = await check();
|
||||
if (isAdbRunning) {
|
||||
this.didRunInitially = false;
|
||||
dumpn("Found ADB process running, not restarting");
|
||||
onSuccessfulStart();
|
||||
return;
|
||||
|
|
|
@ -7,7 +7,9 @@ DevToolsModules(
|
|||
'adb-binary.js',
|
||||
'adb-client.js',
|
||||
'adb-device.js',
|
||||
'adb-devices-registry.js',
|
||||
'adb-running-checker.js',
|
||||
'adb-runtime.js',
|
||||
'adb-scanner.js',
|
||||
'adb-socket.js',
|
||||
'adb.js',
|
||||
|
|
|
@ -175,13 +175,24 @@ add_task({
|
|||
|
||||
await extension.startup();
|
||||
|
||||
// Call start() once and call stop() afterwards.
|
||||
await ADB.start();
|
||||
ok(ADB.ready);
|
||||
|
||||
ok(await check(), "adb is now running");
|
||||
|
||||
await ADB.stop();
|
||||
ok(!ADB.ready);
|
||||
ok(!(await check()), "adb is no longer running");
|
||||
|
||||
// Call start() twice and call stop() afterwards.
|
||||
await ADB.start();
|
||||
await ADB.start();
|
||||
ok(ADB.ready);
|
||||
ok(await check(), "adb is now running");
|
||||
|
||||
await ADB.stop();
|
||||
ok(!ADB.ready);
|
||||
ok(!(await check()), "adb is no longer running");
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
|
|
@ -1,64 +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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const { adbAddon, ADB_ADDON_STATES } = require("devtools/shared/adb/adb-addon");
|
||||
|
||||
/* exported EXPORTED_SYMBOLS */
|
||||
|
||||
const EXPORTED_SYMBOLS = ["Devices"];
|
||||
|
||||
var addonInstalled = adbAddon.status === ADB_ADDON_STATES.INSTALLED;
|
||||
|
||||
const Devices = {
|
||||
_devices: {},
|
||||
|
||||
get adbExtensionInstalled() {
|
||||
return addonInstalled;
|
||||
},
|
||||
set adbExtensionInstalled(v) {
|
||||
addonInstalled = v;
|
||||
if (!addonInstalled) {
|
||||
for (const name in this._devices) {
|
||||
this.unregister(name);
|
||||
}
|
||||
}
|
||||
this.emit("addon-status-updated", v);
|
||||
},
|
||||
|
||||
register: function(name, device) {
|
||||
this._devices[name] = device;
|
||||
this.emit("register");
|
||||
},
|
||||
|
||||
unregister: function(name) {
|
||||
delete this._devices[name];
|
||||
this.emit("unregister");
|
||||
},
|
||||
|
||||
available: function() {
|
||||
return Object.keys(this._devices).sort();
|
||||
},
|
||||
|
||||
getByName: function(name) {
|
||||
return this._devices[name];
|
||||
},
|
||||
|
||||
updateAdbAddonStatus: function() {
|
||||
this.adbExtensionInstalled = adbAddon.status === ADB_ADDON_STATES.INSTALLED;
|
||||
},
|
||||
};
|
||||
|
||||
Object.defineProperty(this, "Devices", {
|
||||
value: Devices,
|
||||
enumerable: true,
|
||||
writable: false,
|
||||
});
|
||||
|
||||
EventEmitter.decorate(Devices);
|
||||
|
||||
adbAddon.on("update", () => Devices.updateAdbAddonStatus());
|
|
@ -27,8 +27,12 @@ function eventSource(proto) {
|
|||
* Called when the event is fired. If the same listener
|
||||
* is added more than once, it will be called once per
|
||||
* addListener call.
|
||||
* @param key function (optional)
|
||||
* Key to use for removeListener, defaults to the listener. Used by helper method
|
||||
* addOneTimeListener, which creates a custom listener. Use the original listener
|
||||
* as key to allow to remove oneTimeListeners.
|
||||
*/
|
||||
proto.addListener = function(name, listener) {
|
||||
proto.addListener = function(name, listener, key = listener) {
|
||||
if (typeof listener != "function") {
|
||||
throw TypeError("Listeners must be functions.");
|
||||
}
|
||||
|
@ -37,7 +41,7 @@ function eventSource(proto) {
|
|||
this._listeners = {};
|
||||
}
|
||||
|
||||
this._getListeners(name).push(listener);
|
||||
this._getListeners(name).push({ key, callback: listener });
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -53,14 +57,14 @@ function eventSource(proto) {
|
|||
*/
|
||||
proto.addOneTimeListener = function(name, listener) {
|
||||
return new Promise(resolve => {
|
||||
const l = (eventName, ...rest) => {
|
||||
this.removeListener(name, l);
|
||||
const oneTimeListener = (eventName, ...rest) => {
|
||||
this.removeListener(name, listener);
|
||||
if (listener) {
|
||||
listener(eventName, ...rest);
|
||||
}
|
||||
resolve(rest[0]);
|
||||
};
|
||||
this.addListener(name, l);
|
||||
this.addListener(name, oneTimeListener, listener);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -83,7 +87,7 @@ function eventSource(proto) {
|
|||
this._listeners[name] = [];
|
||||
} else {
|
||||
this._listeners[name] =
|
||||
this._listeners[name].filter(l => l != listener);
|
||||
this._listeners[name].filter(l => l.key != listener);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -121,7 +125,7 @@ function eventSource(proto) {
|
|||
|
||||
for (const listener of listeners) {
|
||||
try {
|
||||
listener.apply(null, arguments);
|
||||
listener.callback.apply(null, arguments);
|
||||
} catch (e) {
|
||||
// Prevent a bad listener from interfering with the others.
|
||||
DevToolsUtils.reportException("notify event '" + name + "'", e);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* 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/. */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* 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/. */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* 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/. */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* 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/. */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* 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/. */
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче