зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1398239 - Add prerendering capability, Highlights diversity and bug fixes to Activity Stream r=Mardak
MozReview-Commit-ID: DqKGqHeT0nS --HG-- extra : rebase_source : 668d1b838b94d197e9631dcb78ce186ce62cefb2
This commit is contained in:
Родитель
be1493b6fc
Коммит
60824fdfe2
|
@ -87,6 +87,10 @@ var whitelist = [
|
|||
{file: "resource://app/modules/NewTabSearchProvider.jsm"},
|
||||
{file: "resource://app/modules/NewTabWebChannel.jsm"},
|
||||
|
||||
// browser/extensions/activity-stream/data/content/activity-stream-prerendered.html
|
||||
// This will used when Bug 1397875 lands
|
||||
{file: "resource://activity-stream/data/content/activity-stream-prerendered.html"},
|
||||
|
||||
// layout/mathml/nsMathMLChar.cpp
|
||||
{file: "resource://gre/res/fonts/mathfontSTIXGeneral.properties"},
|
||||
{file: "resource://gre/res/fonts/mathfontUnicode.properties"},
|
||||
|
|
|
@ -95,14 +95,9 @@ function promiseStateChangeURI() {
|
|||
|
||||
function promiseContentSearchReady(browser) {
|
||||
return ContentTask.spawn(browser, {}, async function(args) {
|
||||
return new Promise(resolve => {
|
||||
content.addEventListener("ContentSearchService", function listener(aEvent) {
|
||||
if (aEvent.detail.type == "State") {
|
||||
content.removeEventListener("ContentSearchService", listener);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
await ContentTaskUtils.waitForCondition(() => content.wrappedJSObject.gContentSearchController &&
|
||||
content.wrappedJSObject.gContentSearchController.defaultEngine
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ for (const type of [
|
|||
"NEW_TAB_INIT",
|
||||
"NEW_TAB_INITIAL_STATE",
|
||||
"NEW_TAB_LOAD",
|
||||
"NEW_TAB_STATE_REQUEST",
|
||||
"NEW_TAB_UNLOAD",
|
||||
"OPEN_LINK",
|
||||
"OPEN_NEW_WINDOW",
|
||||
|
|
|
@ -1,26 +1,28 @@
|
|||
/* globals Services */
|
||||
"use strict";
|
||||
|
||||
let usablePerfObj;
|
||||
|
||||
let Cu;
|
||||
const isRunningInChrome = typeof Window === "undefined";
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (isRunningInChrome) {
|
||||
Cu = Components.utils;
|
||||
} else {
|
||||
Cu = {import() {}};
|
||||
if (typeof Components !== "undefined" && Components.utils) {
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
}
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
let usablePerfObj;
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (isRunningInChrome) {
|
||||
/* istanbul ignore else */
|
||||
if (typeof Services !== "undefined") {
|
||||
// Borrow the high-resolution timer from the hidden window....
|
||||
usablePerfObj = Services.appShell.hiddenDOMWindow.performance;
|
||||
} else { // we must be running in content space
|
||||
} else if (typeof performance !== "undefined") {
|
||||
// we must be running in content space
|
||||
usablePerfObj = performance;
|
||||
} else {
|
||||
// This is a dummy object so this file doesn't crash in the node prerendering
|
||||
// task.
|
||||
usablePerfObj = {
|
||||
now() {},
|
||||
mark() {}
|
||||
};
|
||||
}
|
||||
|
||||
this._PerfService = function _PerfService(options) {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
const prefConfig = {
|
||||
// Prefs listed with "invalidates: true" will prevent the prerendered version
|
||||
// of AS from being used if their value is something other than what is listed
|
||||
// here. This is required because some preferences cause the page layout to be
|
||||
// too different for the prerendered version to be used. Unfortunately, this
|
||||
// will result in users who have modified some of their preferences not being
|
||||
// able to get the benefits of prerendering.
|
||||
"migrationExpired": {value: true},
|
||||
"showTopSites": {
|
||||
value: true,
|
||||
invalidates: true
|
||||
},
|
||||
"showSearch": {
|
||||
value: true,
|
||||
invalidates: true
|
||||
},
|
||||
"topSitesCount": {value: 6},
|
||||
"feeds.section.topstories": {
|
||||
value: true,
|
||||
invalidates: true
|
||||
}
|
||||
};
|
||||
|
||||
this.PrerenderData = {
|
||||
invalidatingPrefs: Object.keys(prefConfig).filter(key => prefConfig[key].invalidates),
|
||||
initialPrefs: Object.keys(prefConfig).reduce((obj, key) => {
|
||||
obj[key] = prefConfig[key].value;
|
||||
return obj;
|
||||
}, {}), // This creates an object of the form {prefName: value}
|
||||
initialSections: [
|
||||
{
|
||||
enabled: true,
|
||||
icon: "pocket",
|
||||
id: "topstories",
|
||||
order: 1,
|
||||
title: {id: "header_recommended_by", values: {provider: "Pocket"}},
|
||||
topics: [{}]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["PrerenderData"];
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
const {actionTypes: at} = Components.utils.import("resource://activity-stream/common/Actions.jsm", {});
|
||||
|
||||
// Locales that should be displayed RTL
|
||||
const RTL_LIST = ["ar", "he", "fa", "ur"];
|
||||
|
||||
const TOP_SITES_DEFAULT_LENGTH = 6;
|
||||
const TOP_SITES_SHOWMORE_LENGTH = 12;
|
||||
|
||||
|
@ -16,6 +19,8 @@ const INITIAL_STATE = {
|
|||
locale: "",
|
||||
// Localized strings with defaults
|
||||
strings: null,
|
||||
// The text direction for the locale
|
||||
textDirection: "",
|
||||
// The version of the system-addon
|
||||
version: null
|
||||
},
|
||||
|
@ -48,7 +53,8 @@ function App(prevState = INITIAL_STATE.App, action) {
|
|||
let {locale, strings} = action.data;
|
||||
return Object.assign({}, prevState, {
|
||||
locale,
|
||||
strings
|
||||
strings,
|
||||
textDirection: RTL_LIST.indexOf(locale.split("-")[0]) >= 0 ? "rtl" : "ltr"
|
||||
});
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
// Note - this is a generated file.
|
||||
window.gActivityStreamPrerenderedState = {
|
||||
"TopSites": {
|
||||
"initialized": false,
|
||||
"rows": []
|
||||
},
|
||||
"App": {
|
||||
"initialized": false,
|
||||
"locale": "en-PRERENDER",
|
||||
"strings": {
|
||||
"newtab_page_title": " ",
|
||||
"default_label_loading": " ",
|
||||
"header_top_sites": " ",
|
||||
"header_stories": " ",
|
||||
"header_highlights": " ",
|
||||
"header_visit_again": " ",
|
||||
"header_bookmarks": " ",
|
||||
"header_recommended_by": " ",
|
||||
"header_bookmarks_placeholder": " ",
|
||||
"header_stories_from": " ",
|
||||
"type_label_visited": " ",
|
||||
"type_label_bookmarked": " ",
|
||||
"type_label_synced": " ",
|
||||
"type_label_recommended": " ",
|
||||
"type_label_open": " ",
|
||||
"type_label_topic": " ",
|
||||
"type_label_now": " ",
|
||||
"menu_action_bookmark": " ",
|
||||
"menu_action_remove_bookmark": " ",
|
||||
"menu_action_copy_address": " ",
|
||||
"menu_action_email_link": " ",
|
||||
"menu_action_open_new_window": " ",
|
||||
"menu_action_open_private_window": " ",
|
||||
"menu_action_dismiss": " ",
|
||||
"menu_action_delete": " ",
|
||||
"menu_action_pin": " ",
|
||||
"menu_action_unpin": " ",
|
||||
"confirm_history_delete_p1": " ",
|
||||
"confirm_history_delete_notice_p2": " ",
|
||||
"menu_action_save_to_pocket": " ",
|
||||
"search_for_something_with": " ",
|
||||
"search_button": " ",
|
||||
"search_header": " ",
|
||||
"search_web_placeholder": "Search the Web",
|
||||
"search_settings": " ",
|
||||
"section_info_option": " ",
|
||||
"section_info_send_feedback": " ",
|
||||
"section_info_privacy_notice": " ",
|
||||
"welcome_title": " ",
|
||||
"welcome_body": " ",
|
||||
"welcome_label": " ",
|
||||
"time_label_less_than_minute": " ",
|
||||
"time_label_minute": " ",
|
||||
"time_label_hour": " ",
|
||||
"time_label_day": " ",
|
||||
"settings_pane_button_label": " ",
|
||||
"settings_pane_header": " ",
|
||||
"settings_pane_body2": " ",
|
||||
"settings_pane_search_header": " ",
|
||||
"settings_pane_search_body": " ",
|
||||
"settings_pane_topsites_header": " ",
|
||||
"settings_pane_topsites_body": " ",
|
||||
"settings_pane_topsites_options_showmore": " ",
|
||||
"settings_pane_bookmarks_header": " ",
|
||||
"settings_pane_bookmarks_body": " ",
|
||||
"settings_pane_visit_again_header": " ",
|
||||
"settings_pane_visit_again_body": " ",
|
||||
"settings_pane_highlights_header": " ",
|
||||
"settings_pane_highlights_body2": " ",
|
||||
"settings_pane_highlights_options_bookmarks": " ",
|
||||
"settings_pane_highlights_options_visited": " ",
|
||||
"settings_pane_snippets_header": " ",
|
||||
"settings_pane_snippets_body": " ",
|
||||
"settings_pane_done_button": " ",
|
||||
"edit_topsites_button_text": " ",
|
||||
"edit_topsites_button_label": " ",
|
||||
"edit_topsites_showmore_button": " ",
|
||||
"edit_topsites_showless_button": " ",
|
||||
"edit_topsites_done_button": " ",
|
||||
"edit_topsites_pin_button": " ",
|
||||
"edit_topsites_unpin_button": " ",
|
||||
"edit_topsites_edit_button": " ",
|
||||
"edit_topsites_dismiss_button": " ",
|
||||
"edit_topsites_add_button": " ",
|
||||
"topsites_form_add_header": " ",
|
||||
"topsites_form_edit_header": " ",
|
||||
"topsites_form_title_placeholder": " ",
|
||||
"topsites_form_url_placeholder": " ",
|
||||
"topsites_form_add_button": " ",
|
||||
"topsites_form_save_button": " ",
|
||||
"topsites_form_cancel_button": " ",
|
||||
"topsites_form_url_validation": " ",
|
||||
"pocket_read_more": " ",
|
||||
"pocket_read_even_more": " ",
|
||||
"pocket_feedback_header": " ",
|
||||
"pocket_description": " ",
|
||||
"highlights_empty_state": " ",
|
||||
"topstories_empty_state": " ",
|
||||
"manual_migration_explanation2": " ",
|
||||
"manual_migration_cancel_button": " ",
|
||||
"manual_migration_import_button": " "
|
||||
},
|
||||
"textDirection": "ltr",
|
||||
"version": null
|
||||
},
|
||||
"Snippets": {
|
||||
"initialized": false
|
||||
},
|
||||
"Prefs": {
|
||||
"initialized": true,
|
||||
"values": {
|
||||
"migrationExpired": true,
|
||||
"showTopSites": true,
|
||||
"showSearch": true,
|
||||
"topSitesCount": 6,
|
||||
"feeds.section.topstories": true
|
||||
}
|
||||
},
|
||||
"Dialog": {
|
||||
"visible": false,
|
||||
"data": {}
|
||||
},
|
||||
"Sections": [
|
||||
{
|
||||
"title": {
|
||||
"id": "header_recommended_by",
|
||||
"values": {
|
||||
"provider": "Pocket"
|
||||
}
|
||||
},
|
||||
"rows": [],
|
||||
"order": 1,
|
||||
"enabled": true,
|
||||
"icon": "pocket",
|
||||
"id": "topstories",
|
||||
"topics": [
|
||||
{}
|
||||
],
|
||||
"initialized": false
|
||||
}
|
||||
]
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
<!doctype html>
|
||||
<html lang="" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Security-Policy-Report-Only" content="script-src 'unsafe-inline'; img-src http: https: data: blob:; style-src 'unsafe-inline'; child-src 'none'; object-src 'none'; report-uri https://tiles.services.mozilla.com/v4/links/activity-stream/csp">
|
||||
<title></title>
|
||||
<link rel="icon" type="image/png" id="favicon" href="chrome://branding/content/icon32.png"/>
|
||||
<link rel="stylesheet" href="chrome://browser/content/contentSearchUI.css" />
|
||||
<link rel="stylesheet" href="resource://activity-stream/data/content/activity-stream.css" />
|
||||
</head>
|
||||
<body class="activity-stream">
|
||||
<div id="root"><div class="outer-wrapper" data-reactroot="" data-reactid="1" data-react-checksum="57168132"><main data-reactid="2"><div class="search-wrapper" data-reactid="3"><label for="newtab-search-text" class="search-label" data-reactid="4"><span class="sr-only" data-reactid="5"><span data-reactid="6">Search the Web</span></span></label><input type="search" id="newtab-search-text" maxlength="256" placeholder="Search the Web" title="Search the Web" data-reactid="7"/><button id="searchSubmit" class="search-button" title=" " data-reactid="8"><span class="sr-only" data-reactid="9"><span data-reactid="10"> </span></span></button></div><section class="top-sites" data-reactid="11"><h3 class="section-title" data-reactid="12"><span class="icon icon-small-spacer icon-topsites" data-reactid="13"></span><span data-reactid="14"> </span></h3><ul class="top-sites-list" data-reactid="15"><li class="top-site-outer placeholder" data-reactid="16"><a data-reactid="17"><div class="tile" aria-hidden="true" data-reactid="18"><span class="letter-fallback" data-reactid="19"></span><div class="screenshot" style="background-image:none;" data-reactid="20"></div></div><div class="title " data-reactid="21"><span dir="auto" data-reactid="22"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="23"><a data-reactid="24"><div class="tile" aria-hidden="true" data-reactid="25"><span class="letter-fallback" data-reactid="26"></span><div class="screenshot" style="background-image:none;" data-reactid="27"></div></div><div class="title " data-reactid="28"><span dir="auto" data-reactid="29"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="30"><a data-reactid="31"><div class="tile" aria-hidden="true" data-reactid="32"><span class="letter-fallback" data-reactid="33"></span><div class="screenshot" style="background-image:none;" data-reactid="34"></div></div><div class="title " data-reactid="35"><span dir="auto" data-reactid="36"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="37"><a data-reactid="38"><div class="tile" aria-hidden="true" data-reactid="39"><span class="letter-fallback" data-reactid="40"></span><div class="screenshot" style="background-image:none;" data-reactid="41"></div></div><div class="title " data-reactid="42"><span dir="auto" data-reactid="43"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="44"><a data-reactid="45"><div class="tile" aria-hidden="true" data-reactid="46"><span class="letter-fallback" data-reactid="47"></span><div class="screenshot" style="background-image:none;" data-reactid="48"></div></div><div class="title " data-reactid="49"><span dir="auto" data-reactid="50"></span></div></a></li><li class="top-site-outer placeholder" data-reactid="51"><a data-reactid="52"><div class="tile" aria-hidden="true" data-reactid="53"><span class="letter-fallback" data-reactid="54"></span><div class="screenshot" style="background-image:none;" data-reactid="55"></div></div><div class="title " data-reactid="56"><span dir="auto" data-reactid="57"></span></div></a></li></ul></section><div class="sections-list" data-reactid="58"><section data-reactid="59"><div class="section-top-bar" data-reactid="60"><h3 class="section-title" data-reactid="61"><span class="icon icon-small-spacer icon-pocket" data-reactid="62"></span><span data-reactid="63"> </span></h3></div><ul class="section-list" style="padding:0;" data-reactid="64"><li class="card-outer placeholder" data-reactid="65"><a data-reactid="66"><div class="card" data-reactid="67"><div class="card-details no-image" data-reactid="68"><div class="card-text no-image no-host-name no-context" data-reactid="69"><h4 class="card-title" dir="auto" data-reactid="70"></h4><p class="card-description" dir="auto" data-reactid="71"></p></div></div></div></a></li><li class="card-outer placeholder" data-reactid="72"><a data-reactid="73"><div class="card" data-reactid="74"><div class="card-details no-image" data-reactid="75"><div class="card-text no-image no-host-name no-context" data-reactid="76"><h4 class="card-title" dir="auto" data-reactid="77"></h4><p class="card-description" dir="auto" data-reactid="78"></p></div></div></div></a></li><li class="card-outer placeholder" data-reactid="79"><a data-reactid="80"><div class="card" data-reactid="81"><div class="card-details no-image" data-reactid="82"><div class="card-text no-image no-host-name no-context" data-reactid="83"><h4 class="card-title" dir="auto" data-reactid="84"></h4><p class="card-description" dir="auto" data-reactid="85"></p></div></div></div></a></li></ul><div class="topic" data-reactid="86"><span data-reactid="87"><span data-reactid="88"> </span></span><ul data-reactid="89"><li data-reactid="90"><a class="topic-link" data-reactid="91"></a></li></ul></div></section></div><!-- react-empty: 92 --></main></div></div>
|
||||
<div id="snippets-container">
|
||||
<div id="snippets"></div>
|
||||
</div>
|
||||
<script src="resource://activity-stream/data/content/activity-stream-initial-state.js"></script>
|
||||
<script src="chrome://browser/content/contentSearchUI.js"></script>
|
||||
<script src="resource://activity-stream/vendor/react.js"></script>
|
||||
<script src="resource://activity-stream/vendor/react-dom.js"></script>
|
||||
<script src="resource://activity-stream/vendor/react-intl.js"></script>
|
||||
<script src="resource://activity-stream/vendor/redux.js"></script>
|
||||
<script src="resource://activity-stream/vendor/react-redux.js"></script>
|
||||
<script src="resource://activity-stream/data/content/activity-stream.bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -64,7 +64,9 @@ input {
|
|||
.icon.icon-historyItem {
|
||||
background-image: url("assets/glyph-historyItem-16.svg"); }
|
||||
.icon.icon-trending {
|
||||
background-image: url("assets/glyph-trending-16.svg"); }
|
||||
background-image: url("assets/glyph-trending-16.svg");
|
||||
transform: translateY(2px);
|
||||
/* trending bolt is visually top heavy */ }
|
||||
.icon.icon-now {
|
||||
background-image: url("chrome://browser/skin/history.svg"); }
|
||||
.icon.icon-topsites {
|
||||
|
@ -317,17 +319,26 @@ main {
|
|||
opacity: 0; }
|
||||
.top-sites-list .top-site-outer .screenshot.active {
|
||||
opacity: 1; }
|
||||
.top-sites-list .top-site-outer .tippy-top-icon {
|
||||
.top-sites-list .top-site-outer .top-site-icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
|
||||
background-position: center center;
|
||||
background-size: 96px;
|
||||
background-repeat: no-repeat; }
|
||||
background-repeat: no-repeat;
|
||||
background-color: #F9F9FA; }
|
||||
.top-sites-list .top-site-outer .rich-icon {
|
||||
top: 0;
|
||||
offset-inline-start: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-size: 96px; }
|
||||
.top-sites-list .top-site-outer .default-icon {
|
||||
z-index: 1;
|
||||
top: -6px;
|
||||
offset-inline-start: -6px;
|
||||
height: 42px;
|
||||
width: 42px;
|
||||
background-size: 32px; }
|
||||
.top-sites-list .top-site-outer .title {
|
||||
font: message-box;
|
||||
height: 30px;
|
||||
|
@ -1017,11 +1028,10 @@ main {
|
|||
display: flex; }
|
||||
.card-outer .card-context-icon {
|
||||
fill: rgba(12, 12, 13, 0.6);
|
||||
font-size: 13px;
|
||||
margin-inline-end: 6px;
|
||||
display: block; }
|
||||
margin-inline-end: 6px; }
|
||||
.card-outer .card-context-label {
|
||||
flex-grow: 1;
|
||||
line-height: 16px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!doctype html>
|
||||
<html lang="en-us" dir="ltr">
|
||||
<html lang="" dir="ltr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Security-Policy-Report-Only" content="script-src 'unsafe-inline'; img-src http: https: data: blob:; style-src 'unsafe-inline'; child-src 'none'; object-src 'none'; report-uri https://tiles.services.mozilla.com/v4/links/activity-stream/csp">
|
||||
|
|
|
@ -232,9 +232,11 @@
|
|||
"settings_pane_visit_again_header": "Təkrar ziyarət et",
|
||||
"settings_pane_visit_again_body": "Firefox tarixçənizdən yadda saxlamaq və ya geri qayıtmaq istəyə biləcəyiniz hissələri göstərəcək.",
|
||||
"settings_pane_highlights_header": "Seçilmişlər",
|
||||
"settings_pane_highlights_body2": "Son ziyarət etdiyiniz və ya əlfəcinlədiyiniz maraqlı məzmunlara rahat qayıdın.",
|
||||
"settings_pane_highlights_options_bookmarks": "Əlfəcinlər",
|
||||
"settings_pane_highlights_options_visited": "Baxılmış Saytlar",
|
||||
"settings_pane_snippets_header": "Hissələr",
|
||||
"settings_pane_snippets_body": "Mozilladan Firefox, internet mədəniyyəti və digər yeniliklər haqqında qısa bildirişlər oxuyun.",
|
||||
"settings_pane_done_button": "Oldu",
|
||||
"edit_topsites_button_text": "Redaktə et",
|
||||
"edit_topsites_button_label": "Qabaqcıl Saytlar bölümünüzü fərdiləşdirin",
|
||||
|
@ -257,6 +259,8 @@
|
|||
"pocket_read_more": "Məşhur Mövzular:",
|
||||
"pocket_read_even_more": "Daha çox hekayə gör",
|
||||
"pocket_feedback_header": "25 milyon nəfərin dəstəyi ilə internetin ən yaxşıları.",
|
||||
"pocket_description": "Mozilla ailəsinin yeni üzvü olan Pocket ilə yüksək keyfiyyətli məzmunları kəşf edin.",
|
||||
"highlights_empty_state": "İnternetdə gəzməyə başlayın, burada ziyarət edəcəyiniz və ya əlfəcinləyəcəyiniz məqalə, video və digər səhifələri göstərəcəyik.",
|
||||
"topstories_empty_state": "Hamısını oxudunuz. Yeni {provider} məqalələri üçün daha sonra təkrar yoxlayın. Gözləyə bilmirsiz? Məşhur mövzu seçərək internetdən daha çox gözəl məqalələr tapın.",
|
||||
"manual_migration_explanation2": "Firefox səyyahını digər səyyahlardan olan əlfəcin, tarixçə və parollar ilə yoxlayın.",
|
||||
"manual_migration_cancel_button": "Xeyr, Təşəkkürlər",
|
||||
|
@ -414,9 +418,11 @@
|
|||
"settings_pane_visit_again_header": "Посещаване",
|
||||
"settings_pane_visit_again_body": "Firefox ще ви показва части от вашата история на разглеждане, към която бихте желали да се върнете или запомните.",
|
||||
"settings_pane_highlights_header": "Акценти",
|
||||
"settings_pane_highlights_body2": "Намерете интересните неща, които скоро сте посетили или отметнали.",
|
||||
"settings_pane_highlights_options_bookmarks": "Отметки",
|
||||
"settings_pane_highlights_options_visited": "Посетени страници",
|
||||
"settings_pane_snippets_header": "Изрезки",
|
||||
"settings_pane_snippets_body": "Четете кратки и радостни новини от Mozilla относно Firefox, интернет-културата и случайни мемета.",
|
||||
"settings_pane_done_button": "Готово",
|
||||
"edit_topsites_button_text": "Редактиране",
|
||||
"edit_topsites_button_label": "Настройки на най-посещаваните",
|
||||
|
@ -440,6 +446,7 @@
|
|||
"pocket_read_even_more": "Повече статии",
|
||||
"pocket_feedback_header": "Най-доброто от интернет, подбрано от над 25 милиона души.",
|
||||
"pocket_description": "Открийте висококачествено съдържание, което иначе може да пропуснете, с помощта на Pocket, вече част от Mozilla.",
|
||||
"highlights_empty_state": "Разглеждайте и тук ще ви покажем някои от най-добрите статии, видео и други страници, които сте посетили или отметнали наскоро.",
|
||||
"topstories_empty_state": "Разгледахте всичко. Проверете по-късно за повече истории от {provider}. Нямате търпение? Изберете популярна тема, за да откриете повече истории из цялата Мрежа.",
|
||||
"manual_migration_explanation2": "Опитайте Firefox с отметките, историята и паролите от друг четец.",
|
||||
"manual_migration_cancel_button": "Не, благодаря",
|
||||
|
@ -1055,10 +1062,10 @@
|
|||
"menu_action_email_link": "Link per E-Mail versenden…",
|
||||
"menu_action_open_new_window": "In neuem Fenster öffnen",
|
||||
"menu_action_open_private_window": "In neuem privaten Fenster öffnen",
|
||||
"menu_action_dismiss": "Schließen",
|
||||
"menu_action_dismiss": "Entfernen",
|
||||
"menu_action_delete": "Aus Chronik löschen",
|
||||
"menu_action_pin": "Anheften",
|
||||
"menu_action_unpin": "Lösen",
|
||||
"menu_action_unpin": "Ablösen",
|
||||
"confirm_history_delete_p1": "Soll wirklich jede Instanz dieser Seite aus Ihrer Chronik gelöscht werden?",
|
||||
"confirm_history_delete_notice_p2": "Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
"menu_action_save_to_pocket": "Bei Pocket speichern",
|
||||
|
@ -1077,8 +1084,8 @@
|
|||
"time_label_minute": "{number} m",
|
||||
"time_label_hour": "{number} h",
|
||||
"time_label_day": "{number} t",
|
||||
"settings_pane_button_label": "Neuer-Tab-Seite anpassen",
|
||||
"settings_pane_header": "Einstellungen zum neuen Tab",
|
||||
"settings_pane_button_label": "Einstellungen für neue Tabs anpassen",
|
||||
"settings_pane_header": "Einstellungen für neue Tabs",
|
||||
"settings_pane_body2": "Wählen Sie aus, was auf dieser Seite angezeigt wird.",
|
||||
"settings_pane_search_header": "Suche",
|
||||
"settings_pane_search_body": "Suchen Sie aus einem neuen Tab im Internet.",
|
||||
|
@ -1108,8 +1115,8 @@
|
|||
"edit_topsites_add_button": "Hinzufügen",
|
||||
"topsites_form_add_header": "Neue meistbesuchte Seite",
|
||||
"topsites_form_edit_header": "Meistbesuchte Seite bearbeiten",
|
||||
"topsites_form_title_placeholder": "Titel eingeben",
|
||||
"topsites_form_url_placeholder": "Eine URL eingeben oder einfügen",
|
||||
"topsites_form_title_placeholder": "Name eingeben",
|
||||
"topsites_form_url_placeholder": "Eine Adresse eingeben oder einfügen",
|
||||
"topsites_form_add_button": "Hinzufügen",
|
||||
"topsites_form_save_button": "Speichern",
|
||||
"topsites_form_cancel_button": "Abbrechen",
|
||||
|
@ -1119,7 +1126,7 @@
|
|||
"pocket_feedback_header": "Das Beste aus dem Web, zusammengetragen von 25 Millionen Menschen.",
|
||||
"pocket_description": "Entdecken Sie qualitativ hochwertige Inhalte mithilfe von Pocket (jetzt Teil von von Mozilla), die Sie ansonsten verpassen würden.",
|
||||
"highlights_empty_state": "Surfen Sie los und wir zeigen Ihnen hier tolle Artikel, Videos und andere Seiten, die Sie kürzlich besucht oder als Lesezeichen gespeichert haben.",
|
||||
"topstories_empty_state": "Jetzt kennen Sie die Neuigkeiten. Schauen Sie später wieder vorbei, um neue Informationen von {provider} zu erhalten. Können sie nicht warten? Wählen Sie ein beliebtes Thema und lesen Sie weitere interessante Geschichten aus dem Internet.",
|
||||
"topstories_empty_state": "Jetzt kennen Sie die Neuigkeiten. Schauen Sie später wieder vorbei, um neue Informationen von {provider} zu erhalten. Können Sie nicht warten? Wählen Sie ein beliebtes Thema und lesen Sie weitere interessante Geschichten aus dem Internet.",
|
||||
"manual_migration_explanation2": "Probieren Sie Firefox aus und importieren Sie die Lesezeichen, Chronik und Passwörter eines anderen Browsers.",
|
||||
"manual_migration_cancel_button": "Nein, danke",
|
||||
"manual_migration_import_button": "Jetzt importieren"
|
||||
|
@ -1763,6 +1770,7 @@
|
|||
"default_label_loading": "Cargando…",
|
||||
"header_top_sites": "Sitios favoritos",
|
||||
"header_stories": "Historias populares",
|
||||
"header_highlights": "Destacados",
|
||||
"header_visit_again": "Visitar de nuevo",
|
||||
"header_bookmarks": "Marcadores recientes",
|
||||
"header_recommended_by": "Recomendado por {provider}",
|
||||
|
@ -1794,6 +1802,8 @@
|
|||
"search_web_placeholder": "Buscar en la Web",
|
||||
"search_settings": "Cambiar ajustes de búsqueda",
|
||||
"section_info_option": "Info",
|
||||
"section_info_send_feedback": "Enviar comentario",
|
||||
"section_info_privacy_notice": "Aviso de privacidad",
|
||||
"welcome_title": "Bienvenido a la nueva pestaña",
|
||||
"welcome_body": "Firefox utilizará este espacio para mostrarte los marcadores, artículos y vídeos más relevantes y las páginas que has visitado recientemente, para que puedas acceder más rápido.",
|
||||
"welcome_label": "Identificar lo más destacado para ti",
|
||||
|
@ -1803,7 +1813,7 @@
|
|||
"time_label_day": "{number}d",
|
||||
"settings_pane_button_label": "Personalizar la página Nueva pestaña",
|
||||
"settings_pane_header": "Preferencias de nueva pestaña",
|
||||
"settings_pane_body": "Elige qué quieres ver al abrir una nueva pestaña",
|
||||
"settings_pane_body2": "Elige lo quieras ver en esta página.",
|
||||
"settings_pane_search_header": "Buscar",
|
||||
"settings_pane_search_body": "Busca en la Web desde tu nueva pestaña.",
|
||||
"settings_pane_topsites_header": "Sitios populares",
|
||||
|
@ -1813,8 +1823,12 @@
|
|||
"settings_pane_bookmarks_body": "Tus marcadores recién creados, fácilmente accesibles.",
|
||||
"settings_pane_visit_again_header": "Visitar de nuevo",
|
||||
"settings_pane_visit_again_body": "Firefox te mostrará partes de tu historial de navegación que te gustaría recordar o volver a visitar.",
|
||||
"settings_pane_pocketstories_header": "Historias populares",
|
||||
"settings_pane_pocketstories_body": "Pocket, que forma parte de la familia de Mozilla, te ayudará a encontrar contenido de alta calidad que puede que no encuentres de otra forma.",
|
||||
"settings_pane_highlights_header": "Destacados",
|
||||
"settings_pane_highlights_body2": "Vuelve a encontrar todas las cosas interesantes que hayas visitado o marcado recientemente.",
|
||||
"settings_pane_highlights_options_bookmarks": "Marcadores",
|
||||
"settings_pane_highlights_options_visited": "Sitios visitados",
|
||||
"settings_pane_snippets_header": "Fragmentos de código",
|
||||
"settings_pane_snippets_body": "Lee actualizaciones breves de Mozilla sobre Firefox, la cultura de internet y el típico meme aleatorio.",
|
||||
"settings_pane_done_button": "Hecho",
|
||||
"edit_topsites_button_text": "Editar",
|
||||
"edit_topsites_button_label": "Personalizar la sección de Sitios populares",
|
||||
|
@ -1837,10 +1851,10 @@
|
|||
"pocket_read_more": "Temas populares:",
|
||||
"pocket_read_even_more": "Ver más historias",
|
||||
"pocket_feedback_header": "Lo mejor de la web, confirmado por más de 25 millones de personas.",
|
||||
"pocket_feedback_body": "Pocket, que forma parte de la familia de Mozilla, te ayudará a encontrar contenido de alta calidad que puede que no encuentres de otra forma.",
|
||||
"pocket_send_feedback": "Enviar comentario",
|
||||
"pocket_description": "Gracias a Pocket, que ahora forma parte de Mozilla, podrás descubrir contenido de alta calidad que de otra forma te perderías.",
|
||||
"highlights_empty_state": "Empieza a navegar y nosotros te mostraremos aquí algunos de los mejores artículos, videos y otras páginas que hayas visitado recientemente o agregado a marcadores.",
|
||||
"topstories_empty_state": "Ya estás al día. Vuelve luego y busca más historias de {provider}. ¿No puedes esperar? Selecciona un tema popular y encontrás más historias alucinantes por toda la web.",
|
||||
"manual_migration_explanation": "Prueba Firefox con tusmarcadores y sitios favoritos importados desde otro navegador.",
|
||||
"manual_migration_explanation2": "Prueba Firefox con los marcadores, historial y contraseñas de otro navegador.",
|
||||
"manual_migration_cancel_button": "No, gracias",
|
||||
"manual_migration_import_button": "Importar ahora"
|
||||
},
|
||||
|
@ -2363,7 +2377,7 @@
|
|||
"settings_pane_visit_again_header": "Visiter à nouveau",
|
||||
"settings_pane_visit_again_body": "Firefox affichera des extraits de votre historique de navigation dont vous pourriez vouloir vous souvenir ou que vous pourriez vouloir revisiter.",
|
||||
"settings_pane_highlights_header": "Éléments-clés",
|
||||
"settings_pane_highlights_body2": "Retrouvez des pages inintéressantes que vous avez déjà visitées récemment ou ajoutées aux marque-pages.",
|
||||
"settings_pane_highlights_body2": "Retrouvez des pages intéressantes que vous avez visitées récemment ou ajoutées aux marque-pages.",
|
||||
"settings_pane_highlights_options_bookmarks": "Marque-pages",
|
||||
"settings_pane_highlights_options_visited": "Sites visités",
|
||||
"settings_pane_snippets_header": "Brèves",
|
||||
|
@ -3007,6 +3021,7 @@
|
|||
"default_label_loading": "Betöltés…",
|
||||
"header_top_sites": "Népszerű oldalak",
|
||||
"header_stories": "Népszerű történetek",
|
||||
"header_highlights": "Kiemelések",
|
||||
"header_visit_again": "Látogasson el ismét",
|
||||
"header_bookmarks": "Friss könyvjelzők",
|
||||
"header_recommended_by": "A(z) {provider} ajánlásával",
|
||||
|
@ -3038,6 +3053,8 @@
|
|||
"search_web_placeholder": "Keresés a weben",
|
||||
"search_settings": "Keresési beállítások módosítása",
|
||||
"section_info_option": "Információ",
|
||||
"section_info_send_feedback": "Visszajelzés küldése",
|
||||
"section_info_privacy_notice": "Adatvédelmi nyilatkozat",
|
||||
"welcome_title": "Üdvözöljük az új lapon",
|
||||
"welcome_body": "A Firefox ezt a területet a leginkább releváns könyvjelzők, cikkek, videók és nemrég látogatott oldalak megjelenítésére fogja használni, így könnyedén visszatalálhat hozzájuk.",
|
||||
"welcome_label": "A kiemeléseinek azonosítása",
|
||||
|
@ -3047,7 +3064,7 @@
|
|||
"time_label_day": "{number} n",
|
||||
"settings_pane_button_label": "Az Új lap oldal személyre szabása",
|
||||
"settings_pane_header": "Új lap beállításai",
|
||||
"settings_pane_body": "Válassza ki, hogy mit lát, amikor megnyit egy új lapot.",
|
||||
"settings_pane_body2": "Válassza ki, hogy mit akar látni ezen az oldalon.",
|
||||
"settings_pane_search_header": "Keresés",
|
||||
"settings_pane_search_body": "Keresés a weben az új lapon.",
|
||||
"settings_pane_topsites_header": "Népszerű oldalak",
|
||||
|
@ -3057,8 +3074,12 @@
|
|||
"settings_pane_bookmarks_body": "A frissen létrehozott könyvjelzői egy praktikus helyen.",
|
||||
"settings_pane_visit_again_header": "Látogasson el ismét",
|
||||
"settings_pane_visit_again_body": "A Firefox megjeleníti a böngészési előzményeinek azt a részét, amelyet lehet hogy meg szeretne jegyezni, vagy ahová vissza akar térni.",
|
||||
"settings_pane_pocketstories_header": "Népszerű történetek",
|
||||
"settings_pane_pocketstories_body": "A Pocket a Mozilla család tagja, segít az olyan jó minőségű tartalmak fellelésében, melyekkel egyébként nem is találkozott volna.",
|
||||
"settings_pane_highlights_header": "Kiemelések",
|
||||
"settings_pane_highlights_body2": "Találjon vissza azokhoz az érdekes dolgokhoz, amelyeket meglátogatott vagy könyvjelzőzött.",
|
||||
"settings_pane_highlights_options_bookmarks": "Könyvjelzők",
|
||||
"settings_pane_highlights_options_visited": "Látogatott helyek",
|
||||
"settings_pane_snippets_header": "Töredékek",
|
||||
"settings_pane_snippets_body": "Olvasson rövid és érdekes híreket a Mozillától, a Firefoxról, az internetes kultúráról, és időnként kapjon mémeket.",
|
||||
"settings_pane_done_button": "Kész",
|
||||
"edit_topsites_button_text": "Szerkesztés",
|
||||
"edit_topsites_button_label": "A Népszerű oldalak rész testreszabása",
|
||||
|
@ -3081,10 +3102,10 @@
|
|||
"pocket_read_more": "Népszerű témák:",
|
||||
"pocket_read_even_more": "További történetek",
|
||||
"pocket_feedback_header": "A web legjava, több mint 25 millió ember válogatásában.",
|
||||
"pocket_feedback_body": "A Pocket a Mozilla család tagja, segít az olyan jó minőségű tartalmak fellelésében, melyekkel egyébként nem is találkozott volna.",
|
||||
"pocket_send_feedback": "Visszajelzés küldése",
|
||||
"pocket_description": "Fedezzen fel olyan, magas minőségű tartalmakat, amelyek egyébként elkerülnék a figyelmét, a Pocket segítségével, amely most már a Mozilla része.",
|
||||
"highlights_empty_state": "Kezdjen el böngészni, és itt fognak megjelenni azok a nagyszerű cikkek, videók és más lapok, amelyeket nemrég meglátogatott vagy könyvjelzőzött.",
|
||||
"topstories_empty_state": "Már felzárkózott. Nézzen vissza később a legújabb {provider} hírekért. Nem tud várni? Válasszon egy népszerű témát, hogy még több sztorit találjon a weben.",
|
||||
"manual_migration_explanation": "Próbálja ki a Firefoxot egy másik böngészőben lévő kedvenc oldalaival és könyvjelzőivel.",
|
||||
"manual_migration_explanation2": "Próbálja ki a Firefoxot másik böngészőből származó könyvjelzőkkel, előzményekkel és jelszavakkal.",
|
||||
"manual_migration_cancel_button": "Köszönöm, nem",
|
||||
"manual_migration_import_button": "Importálás most"
|
||||
},
|
||||
|
@ -3123,6 +3144,7 @@
|
|||
"default_label_loading": "Memuat…",
|
||||
"header_top_sites": "Situs Teratas",
|
||||
"header_stories": "Cerita Utama",
|
||||
"header_highlights": "Sorotan",
|
||||
"header_visit_again": "Kunjungi Lagi",
|
||||
"header_bookmarks": "Markah Terbaru",
|
||||
"header_recommended_by": "Disarankan oleh {provider}",
|
||||
|
@ -3154,6 +3176,8 @@
|
|||
"search_web_placeholder": "Cari di Web",
|
||||
"search_settings": "Ubah Pengaturan Pencarian",
|
||||
"section_info_option": "Info",
|
||||
"section_info_send_feedback": "Kirim Umpan Balik",
|
||||
"section_info_privacy_notice": "Kebijakan Privasi",
|
||||
"welcome_title": "Selamat datang di tab baru",
|
||||
"welcome_body": "Firefox akan menggunakan ruang ini untuk menampilkan markah, artikel, video, dan laman yang baru-baru ini dikunjungi, yang paling relevan agar Anda bisa kembali mengunjunginya dengan mudah.",
|
||||
"welcome_label": "Mengidentifikasi Sorotan Anda",
|
||||
|
@ -3163,7 +3187,7 @@
|
|||
"time_label_day": "{number} hr",
|
||||
"settings_pane_button_label": "Ubahsuai laman Tab Baru Anda",
|
||||
"settings_pane_header": "Preferensi Tab Baru",
|
||||
"settings_pane_body": "Pilih apa yang Anda lihat ketika Anda membuka tab baru.",
|
||||
"settings_pane_body2": "Pilih apa yang Anda lihat di halaman ini.",
|
||||
"settings_pane_search_header": "Pencarian",
|
||||
"settings_pane_search_body": "Cari Web dari tab baru Anda.",
|
||||
"settings_pane_topsites_header": "Situs Teratas",
|
||||
|
@ -3173,8 +3197,12 @@
|
|||
"settings_pane_bookmarks_body": "Markah Anda dibuat di lokasi yang praktis.",
|
||||
"settings_pane_visit_again_header": "Kunjungi Lagi",
|
||||
"settings_pane_visit_again_body": "Firefox akan menunjukkan bagian dari riwayat penjelajahan yang mungkin ingin Anda ingat atau kunjungi lagi.",
|
||||
"settings_pane_pocketstories_header": "Cerita Utama",
|
||||
"settings_pane_pocketstories_body": "Pocket, bagian dari keluarga Mozilla, akan membantu hubungkan Anda dengan konten berkualitas tinggi yang tak dapat Anda temukan di tempat lain.",
|
||||
"settings_pane_highlights_header": "Sorotan",
|
||||
"settings_pane_highlights_body2": "Temukan jalan kembali ke hal menarik yang baru saja Anda kunjungi atau dimarkah.",
|
||||
"settings_pane_highlights_options_bookmarks": "Markah",
|
||||
"settings_pane_highlights_options_visited": "Situs Terkunjungi",
|
||||
"settings_pane_snippets_header": "Catatan Kecil",
|
||||
"settings_pane_snippets_body": "Baca info pendek terbaru dari Mozilla tentang Firefox, budaya internet dan beberapa meme acak.",
|
||||
"settings_pane_done_button": "Selesai",
|
||||
"edit_topsites_button_text": "Sunting",
|
||||
"edit_topsites_button_label": "Ubahsuai bagian Situs Teratas Anda",
|
||||
|
@ -3197,10 +3225,10 @@
|
|||
"pocket_read_more": "Topik Populer:",
|
||||
"pocket_read_even_more": "Lihat Cerita Lainnya",
|
||||
"pocket_feedback_header": "Yang terbaik dari Web, dikurasi lebih dari 25 juta orang.",
|
||||
"pocket_feedback_body": "Pocket, bagian dari keluarga Mozilla, akan membantu hubungkan Anda dengan konten berkualitas tinggi yang tak dapat Anda temukan di tempat lain.",
|
||||
"pocket_send_feedback": "Kirim Umpanbalik",
|
||||
"pocket_description": "Temukan konten berkualitas tinggi yang mungkin Anda lewatkan dengan bantuan Pocket, yang sekarang menjadi bagian dari Mozilla.",
|
||||
"highlights_empty_state": "Mulai menjelajah, dan kami akan menampilkan beberapa artikel bagus, video, dan halaman lain yang baru saja Anda kunjungi atau termarkah di sini.",
|
||||
"topstories_empty_state": "Maaf Anda tercegat. Periksa lagi nanti untuk lebih banyak cerita terbaik dari {provider}. Tidak mau menunggu? Pilih topik populer untuk menemukan lebih banyak cerita hebat dari seluruh web.",
|
||||
"manual_migration_explanation": "Cobalah Firefox dengan situs dan markah kesukaan Anda dari peramban yang lain.",
|
||||
"manual_migration_explanation2": "Coba Firefox dengan markah, riwayat, dan sandi dari peramban lain.",
|
||||
"manual_migration_cancel_button": "Tidak, Terima kasih",
|
||||
"manual_migration_import_button": "Impor Sekarang"
|
||||
},
|
||||
|
@ -3488,6 +3516,7 @@
|
|||
"default_label_loading": "Asali…",
|
||||
"header_top_sites": "Ismal ifazen",
|
||||
"header_stories": "Tiqsiɣin ifazen",
|
||||
"header_highlights": "Asebrureq",
|
||||
"header_visit_again": "Rzu tikelt-nniḍen",
|
||||
"header_bookmarks": "Ticraḍ n melmi kan",
|
||||
"header_recommended_by": "Iwelleh-it-id {provider}",
|
||||
|
@ -3519,6 +3548,8 @@
|
|||
"search_web_placeholder": "Nadi di Web",
|
||||
"search_settings": "Snifel iγewwaṛen n unadi",
|
||||
"section_info_option": "Talɣut",
|
||||
"section_info_send_feedback": "Azen tikti",
|
||||
"section_info_privacy_notice": "Tasertit n tbaḍnit",
|
||||
"welcome_title": "Ansuf ar yiccer amaynut",
|
||||
"welcome_body": "Firefox ad iseqdec tallunt akken ad d-yesken akk ticraḍ n isebtar iwulmen, imagraden, tividyutin, akked isebtar aniɣer terziḍ melmi kan, ihi tzemreḍ ad d-uɣaleḍ ɣer-sen s wudem fessusen.",
|
||||
"welcome_label": "Asulu n iferdisen tisura",
|
||||
|
@ -3528,7 +3559,7 @@
|
|||
"time_label_day": "{number}n wussan",
|
||||
"settings_pane_button_label": "Sagen asebter n yiccer-ik amaynut",
|
||||
"settings_pane_header": "Ismenyifen n yiccer amaynut",
|
||||
"settings_pane_body": "Fren ayen ara twaliḍ ticki teldiḍ iccer imaynut.",
|
||||
"settings_pane_body2": "Fren ayen ad twaliḍ deg usebter-agi.",
|
||||
"settings_pane_search_header": "Nadi",
|
||||
"settings_pane_search_body": "Nadi di Web seg iccer-ik amaynut.",
|
||||
"settings_pane_topsites_header": "Ismal ifazen",
|
||||
|
@ -3538,8 +3569,12 @@
|
|||
"settings_pane_bookmarks_body": "Ticraḍ yettwarnan melmi kan deg iwen n umdiq ɣef afus.",
|
||||
"settings_pane_visit_again_header": "Rzu tikelt-nniḍen",
|
||||
"settings_pane_visit_again_body": "Firefox ad d-yesken tukkist n umazray-ik n tunigin i tzemreḍ ad twalid tikelt-nniḍen.",
|
||||
"settings_pane_pocketstories_header": "Tiqsiɣin ifazen",
|
||||
"settings_pane_pocketstories_body": "Pocket, aɛeggal n twaxult n Mozilla, ak-d-yefk afus ad twaliḍ agbur n tɣara meqqren i tzemred ad tzegleḍ.",
|
||||
"settings_pane_highlights_header": "Asebrureq",
|
||||
"settings_pane_highlights_body2": "Aff abrid-ik γer wayen i tḥemmleḍ i γef terziḍ yakan neγ tcerḍeḍ-t.",
|
||||
"settings_pane_highlights_options_bookmarks": "Ticraḍ n isebtar",
|
||||
"settings_pane_highlights_options_visited": "Ismal yettwarzan",
|
||||
"settings_pane_snippets_header": "Tiwzillin",
|
||||
"settings_pane_snippets_body": "Wali issalen n Mozilla γef Firefox, adlis internet, akked issalen nniṣen sya γer da.",
|
||||
"settings_pane_done_button": "Immed",
|
||||
"edit_topsites_button_text": "Ẓreg",
|
||||
"edit_topsites_button_label": "Sagen tigezmi n ismal ifazen",
|
||||
|
@ -3562,10 +3597,10 @@
|
|||
"pocket_read_more": "Isental ittwasnen aṭas:",
|
||||
"pocket_read_even_more": "Wali ugar n teqsiḍin",
|
||||
"pocket_feedback_header": "D amezwaru n Web, ittwafren sγur ugar 25 imelyan n imdanen.",
|
||||
"pocket_feedback_body": "Pocket, aɛeggal n twaxult n Mozilla, ak-d-yefk afus ad twaliḍ agbur n tɣara meqqren i tzemred ad tzegleḍ.",
|
||||
"pocket_send_feedback": "Azen tikti",
|
||||
"pocket_description": "S lmendad n Pocket n Mozillan wali aqbur ifazen aṭas, s ttawil-a werǧin ad tzegleḍ taγawsa.",
|
||||
"highlights_empty_state": "Bdu tuniginn sakin nekkni ad k-n-sken imagraden, tividyutin, akked isebtar nniḍen i γef terziḍ yakan neγ i tceṛḍeḍ dagi.",
|
||||
"topstories_empty_state": "Ulac wiyaḍ. Uɣal-d ticki s wugar n imagraden seg {provider}. Ur tebɣiḍ ara ad terǧuḍ? Fren asentel seg wid yettwasnen akken ad twaliḍ imagraden yelhan di Web.",
|
||||
"manual_migration_explanation": "Ɛreḍ Firefox s ismal-ik inurifen akked ticraḍ seg iminig-nniḍen.",
|
||||
"manual_migration_explanation2": "Σreḍ Firefox s ticṛaḍ n isebtar, amazray akked awalen uffiren sγur ilinigen nniḍen.",
|
||||
"manual_migration_cancel_button": "Ala, tanemmirt",
|
||||
"manual_migration_import_button": "Kter tura"
|
||||
},
|
||||
|
@ -3628,9 +3663,11 @@
|
|||
"settings_pane_visit_again_header": "Қайтадан шолу",
|
||||
"settings_pane_visit_again_body": "Firefox сізге есте сақтауды немесе қайта шолуды қалауыңыз мүмкін тарихыңыздың бөліктерін көрсетеді.",
|
||||
"settings_pane_highlights_header": "Ерекше жаңалықтар",
|
||||
"settings_pane_highlights_body2": "Сіз жақында қараған немесе бетбелгілерге қосқан қызықты нәрселерге қайтатын жолды табыңыз.",
|
||||
"settings_pane_highlights_options_bookmarks": "Бетбелгілер",
|
||||
"settings_pane_highlights_options_visited": "Ашылған сайттар",
|
||||
"settings_pane_snippets_header": "Үзінділер",
|
||||
"settings_pane_snippets_body": "Mozilla-дан Firefox және интернет мәдениеті туралы қысқа жаңалықтарды, және кездейсоқ мемдерді оқыңыз.",
|
||||
"settings_pane_done_button": "Дайын",
|
||||
"edit_topsites_button_text": "Түзету",
|
||||
"edit_topsites_button_label": "Топ сайттар санатын баптау",
|
||||
|
@ -3653,7 +3690,10 @@
|
|||
"pocket_read_more": "Әйгілі тақырыптар:",
|
||||
"pocket_read_even_more": "Көбірек хикаяларды қарау",
|
||||
"pocket_feedback_header": "Интернеттің ең жақсысы, 25 миллион адаммен танылған.",
|
||||
"pocket_description": "Ол болмаса, сіз жіберіп алатын мүмкіндігі бар жоғары сапалы құраманы Pocket көмегімен табыңыз, ол енді Mozilla-ның бөлігі болып табылады.",
|
||||
"highlights_empty_state": "Шолуды бастаңыз, сіз жақында шолған немесе бетбелгілерге қосқан тамаша мақалалар, видеолар немесе басқа парақтардың кейбіреулері осында көрсетіледі.",
|
||||
"topstories_empty_state": "Дайын. {provider} ұсынған көбірек мақалаларды алу үшін кейінірек тексеріңіз. Күте алмайсыз ба? Интернеттен көбірек тамаша мақалаларды алу үшін әйгілі теманы таңдаңыз.",
|
||||
"manual_migration_explanation2": "Firefox-ты басқа браузер бетбелгілері, тарихы және парольдерімен қолданып көріңіз.",
|
||||
"manual_migration_cancel_button": "Жоқ, рахмет",
|
||||
"manual_migration_import_button": "Қазір импорттау"
|
||||
},
|
||||
|
@ -4376,6 +4416,7 @@
|
|||
"pocket_read_more": "Populære emner:",
|
||||
"pocket_read_even_more": "Vis flere saker",
|
||||
"pocket_feedback_header": "Det beste av nettet, kurert av over 25 millioner mennesker.",
|
||||
"pocket_description": "Oppdag høykvalitetsinnhold som du ellers ville gå glipp av, ved hjelp av Pocket, som nå er en del av Mozilla.",
|
||||
"highlights_empty_state": "Begynn å surfe, og vi viser noen av de beste artiklene, videoer og andre sider du nylig har besøkt eller bokmerket her.",
|
||||
"topstories_empty_state": "Du har tatt igjen. Kom tilbake senere for flere topphistorier fra {provider}. Kan du ikke vente? Velg et populært emne for å finne flere gode artikler fra hele Internett.",
|
||||
"manual_migration_explanation2": "Prøv Firefox med bokmerkene, historikk og passord fra en annen nettleser.",
|
||||
|
@ -4991,7 +5032,7 @@
|
|||
"menu_action_email_link": "Trametter la colliaziun per e-mail…",
|
||||
"menu_action_open_new_window": "Avrir en ina nova fanestra",
|
||||
"menu_action_open_private_window": "Avrir en ina nova fanestra privata",
|
||||
"menu_action_dismiss": "Serrar",
|
||||
"menu_action_dismiss": "Sbittar",
|
||||
"menu_action_delete": "Stizzar da la cronologia",
|
||||
"menu_action_pin": "Fixar",
|
||||
"menu_action_unpin": "Betg pli fixar",
|
||||
|
@ -5371,6 +5412,8 @@
|
|||
"settings_pane_highlights_body2": "Najdite pot nazaj do zanimivih strani, ki ste jih nedavno obiskali ali dodali med zaznamke.",
|
||||
"settings_pane_highlights_options_bookmarks": "Zaznamki",
|
||||
"settings_pane_highlights_options_visited": "Obiskane strani",
|
||||
"settings_pane_snippets_header": "Izrezki",
|
||||
"settings_pane_snippets_body": "Spremljajte kratke novice o Mozilli in Firefoxu, kulturi interneta in si občasno oglejte kak meme.",
|
||||
"settings_pane_done_button": "Končano",
|
||||
"edit_topsites_button_text": "Uredi",
|
||||
"edit_topsites_button_label": "Prilagodite odsek Glavne strani",
|
||||
|
@ -5384,8 +5427,8 @@
|
|||
"edit_topsites_add_button": "Dodaj",
|
||||
"topsites_form_add_header": "Nova glavna stran",
|
||||
"topsites_form_edit_header": "Uredi glavno stran",
|
||||
"topsites_form_title_placeholder": "Vnesite naslov",
|
||||
"topsites_form_url_placeholder": "Vnesite ali prilepite URL",
|
||||
"topsites_form_title_placeholder": "Vnesite ime",
|
||||
"topsites_form_url_placeholder": "Vnesite ali prilepite spletni naslov",
|
||||
"topsites_form_add_button": "Dodaj",
|
||||
"topsites_form_save_button": "Shrani",
|
||||
"topsites_form_cancel_button": "Prekliči",
|
||||
|
@ -5725,6 +5768,7 @@
|
|||
"default_label_loading": "వస్తోంది…",
|
||||
"header_top_sites": "మేటి సైట్లు",
|
||||
"header_stories": "ముఖ్య కథనాలు",
|
||||
"header_highlights": "విశేషాలు",
|
||||
"header_visit_again": "మళ్లీ సందర్శించండి",
|
||||
"header_bookmarks": "ఇటీవలి ఇష్టాంశములు",
|
||||
"header_recommended_by": "{provider}చే సిఫార్సు చేయబడినది",
|
||||
|
@ -5756,6 +5800,8 @@
|
|||
"search_web_placeholder": "జాలంలో వెతకండి",
|
||||
"search_settings": "శోధన అమరికలు మార్చు",
|
||||
"section_info_option": "సమాచారం",
|
||||
"section_info_send_feedback": "అభిప్రాయాన్ని పంపండి",
|
||||
"section_info_privacy_notice": "గోప్యతా విధానం",
|
||||
"welcome_title": "కొత్త ట్యాబుకు స్వాగతం",
|
||||
"welcome_body": "సముచితమైన మీ ఇష్టాంశాలను, వ్యాసాలను, వీడియోలను, ఇంకా మీరు ఇటీవలే చూసిన పేజీలను మీకు తేలిగ్గా అందుబాటులో ఉంచేందుకు Firefox ఈ జాగాని వాడుకుంటుంది.",
|
||||
"welcome_label": "మీ ముఖ్యాంశాలను గుర్తిస్తున్నది",
|
||||
|
@ -5765,7 +5811,7 @@
|
|||
"time_label_day": "{number}రో",
|
||||
"settings_pane_button_label": "మీ కొత్త ట్యాబు పేజీని మలచుకోండి",
|
||||
"settings_pane_header": "కొత్త ట్యాబు అభిరుచులు",
|
||||
"settings_pane_body": "మీరు కొత్త ట్యాబు తెరిచినప్పుడు ఏం చూడాలో ఎంచుకోండి.",
|
||||
"settings_pane_body2": "మీరు ఈ పేజీలో చూసేదాన్ని ఎంచుకోండి.",
|
||||
"settings_pane_search_header": "వెతకడం",
|
||||
"settings_pane_search_body": "కొత్త ట్యాబు నుండే జాలంలో వెతకండి.",
|
||||
"settings_pane_topsites_header": "మేటి సైట్లు",
|
||||
|
@ -5775,8 +5821,9 @@
|
|||
"settings_pane_bookmarks_body": "ఒక సులభ స్థానంలో మీ క్రొత్తగా సృష్టించిన బుక్మార్క్లు.",
|
||||
"settings_pane_visit_again_header": "మళ్లీ సందర్శించండి",
|
||||
"settings_pane_visit_again_body": "మీరు బ్రౌజింగ్ చరిత్రలో గుర్తుంచుకోవాల్సిన లేదా తిరిగి పొందవలసిన భాగాలను చూపిస్తుంది.",
|
||||
"settings_pane_pocketstories_header": "ముఖ్య కథనాలు",
|
||||
"settings_pane_pocketstories_body": "Mozilla కుటుంబం యొక్క Pocket, మీరు కనుగొనలేకపోయే అధిక-నాణ్యత విషయముకి మిమ్మల్ని అనుసంధానించడానికి సహాయపడుతుంది.",
|
||||
"settings_pane_highlights_header": "విశేషాలు",
|
||||
"settings_pane_highlights_options_bookmarks": "ఇష్టాంశాలు",
|
||||
"settings_pane_highlights_options_visited": "చూసిన సైటులు",
|
||||
"settings_pane_done_button": "పూర్తయింది",
|
||||
"edit_topsites_button_text": "మార్చు",
|
||||
"edit_topsites_button_label": "మీ మేటి సైట్ల విభాగాన్ని మలచుకోండి",
|
||||
|
@ -5799,10 +5846,7 @@
|
|||
"pocket_read_more": "ప్రముఖ అంశాలు:",
|
||||
"pocket_read_even_more": "మరిన్ని కథలను వీక్షించండి",
|
||||
"pocket_feedback_header": "వెబ్లో అత్యుత్తమమైనది, 25 మిలియన్లకు పైగా ప్రజలు పర్యవేక్షించినవి.",
|
||||
"pocket_feedback_body": "Mozilla కుటుంబం యొక్క Pocket, మీరు కనుగొనలేకపోయే అధిక-నాణ్యత విషయముకి మిమ్మల్ని అనుసంధానించడానికి సహాయపడుతుంది.",
|
||||
"pocket_send_feedback": "అభిప్రాయాన్ని పంపండి",
|
||||
"topstories_empty_state": "మీరు పట్టుబడ్డారు. {provider} నుండి మరింత అగ్ర కథనాల కోసం తరువాత తనిఖీ చేయండి. వేచి ఉండలేరా? జాలములోని అంతటి నుండి మరింత గొప్ప కథనాలను కనుగొనడానికి ప్రసిద్ధ అంశం ఎంచుకోండి.",
|
||||
"manual_migration_explanation": "మరొక విహరణి నుండి మీకు ఇష్టమైన సైట్లు మరియు ఇష్టంశాలతో Firefox ను ప్రయత్నించండి.",
|
||||
"manual_migration_cancel_button": "అడిగినందుకు ధన్యవాదాలు, వద్దు",
|
||||
"manual_migration_import_button": "ఇప్పుడే దిగుమతి చేయండి"
|
||||
},
|
||||
|
@ -5865,6 +5909,7 @@
|
|||
"settings_pane_visit_again_header": "เยี่ยมชมอีกครั้ง",
|
||||
"settings_pane_highlights_header": "รายการเด่น",
|
||||
"settings_pane_highlights_options_bookmarks": "ที่คั่นหน้า",
|
||||
"settings_pane_highlights_options_visited": "ไซต์ที่เยี่ยมชมแล้ว",
|
||||
"settings_pane_done_button": "เสร็จสิ้น",
|
||||
"edit_topsites_button_text": "แก้ไข",
|
||||
"edit_topsites_button_label": "ปรับแต่งส่วนไซต์เด่นของคุณ",
|
||||
|
@ -5887,6 +5932,7 @@
|
|||
"pocket_read_more": "หัวข้อยอดนิยม:",
|
||||
"pocket_read_even_more": "ดูเรื่องราวเพิ่มเติม",
|
||||
"pocket_feedback_header": "ที่สุดของเว็บ จัดรายการโดยผู้คนกว่า 25 ล้านคน",
|
||||
"manual_migration_explanation2": "ลอง Firefox ด้วยที่คั่นหน้า, ประวัติ และรหัสผ่านจากเบราว์เซอร์อื่น",
|
||||
"manual_migration_cancel_button": "ไม่ ขอบคุณ",
|
||||
"manual_migration_import_button": "นำเข้าตอนนี้"
|
||||
},
|
||||
|
@ -6294,8 +6340,8 @@
|
|||
"menu_action_remove_bookmark": "移除书签",
|
||||
"menu_action_copy_address": "复制地址",
|
||||
"menu_action_email_link": "用邮件发送链接…",
|
||||
"menu_action_open_new_window": "在新窗口中打开",
|
||||
"menu_action_open_private_window": "在新的隐私窗口中打开",
|
||||
"menu_action_open_new_window": "新建窗口打开",
|
||||
"menu_action_open_private_window": "新建隐私浏览窗口打开",
|
||||
"menu_action_dismiss": "隐藏",
|
||||
"menu_action_delete": "从历史记录中删除",
|
||||
"menu_action_pin": "固定",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:unpack>false</em:unpack>
|
||||
<em:version>2017.09.08.0882-3dbf720c</em:version>
|
||||
<em:version>2017.09.11.1306-373d9fc</em:version>
|
||||
<em:name>Activity Stream</em:name>
|
||||
<em:description>A rich visual history feed and a reimagined home page make it easier than ever to find exactly what you're looking for in Firefox.</em:description>
|
||||
<em:multiprocessCompatible>true</em:multiprocessCompatible>
|
||||
|
|
|
@ -77,6 +77,10 @@ const PREFS_CONFIG = new Map([
|
|||
title: "Number of days to show the manual migration message",
|
||||
value: 4
|
||||
}],
|
||||
["prerender", {
|
||||
title: "Use the prerendered version of activity-stream.html. This is set automatically by PrefsFeed.jsm.",
|
||||
value: true
|
||||
}],
|
||||
["showSearch", {
|
||||
title: "Show the Search bar on the New Tab page",
|
||||
value: true
|
||||
|
|
|
@ -10,6 +10,7 @@ const {actionTypes: at} = Cu.import("resource://activity-stream/common/Actions.j
|
|||
|
||||
const {shortURL} = Cu.import("resource://activity-stream/lib/ShortURL.jsm", {});
|
||||
const {SectionsManager} = Cu.import("resource://activity-stream/lib/SectionsManager.jsm", {});
|
||||
const {TOP_SITES_SHOWMORE_LENGTH} = Cu.import("resource://activity-stream/common/Reducers.jsm", {});
|
||||
const {Dedupe} = Cu.import("resource://activity-stream/common/Dedupe.jsm", {});
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
|
||||
|
@ -17,6 +18,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
|
|||
|
||||
const HIGHLIGHTS_MAX_LENGTH = 9;
|
||||
const HIGHLIGHTS_UPDATE_TIME = 15 * 60 * 1000; // 15 minutes
|
||||
const MANY_EXTRA_LENGTH = HIGHLIGHTS_MAX_LENGTH * 5 + TOP_SITES_SHOWMORE_LENGTH;
|
||||
const SECTION_ID = "highlights";
|
||||
|
||||
this.HighlightsFeed = class HighlightsFeed {
|
||||
|
@ -43,18 +45,39 @@ this.HighlightsFeed = class HighlightsFeed {
|
|||
}
|
||||
|
||||
async fetchHighlights(broadcast = false) {
|
||||
this.highlights = await NewTabUtils.activityStreamLinks.getHighlights();
|
||||
for (let highlight of this.highlights) {
|
||||
highlight.hostname = shortURL(Object.assign({}, highlight, {url: highlight.url}));
|
||||
highlight.image = highlight.preview_image_url;
|
||||
if (highlight.bookmarkGuid) {
|
||||
highlight.type = "bookmark";
|
||||
}
|
||||
}
|
||||
// Request more than the expected length to allow for items being removed by
|
||||
// deduping against Top Sites or multiple history from the same domain, etc.
|
||||
const manyPages = await NewTabUtils.activityStreamLinks.getHighlights({numItems: MANY_EXTRA_LENGTH});
|
||||
|
||||
// Remove any Highlights that are in Top Sites already
|
||||
const deduped = this.dedupe.group(this.store.getState().TopSites.rows, this.highlights);
|
||||
this.highlights = deduped[1];
|
||||
const deduped = this.dedupe.group(this.store.getState().TopSites.rows, manyPages)[1];
|
||||
|
||||
// Keep all "bookmark"s and at most one (most recent) "history" per host
|
||||
this.highlights = [];
|
||||
const hosts = new Set();
|
||||
for (const page of deduped) {
|
||||
const hostname = shortURL(page);
|
||||
// Skip this history page if we already something from the same host
|
||||
if (page.type === "history" && hosts.has(hostname)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We want the page, so update various fields for UI
|
||||
Object.assign(page, {
|
||||
hostname,
|
||||
image: page.preview_image_url,
|
||||
type: page.bookmarkGuid ? "bookmark" : page.type
|
||||
});
|
||||
|
||||
// Add the "bookmark" or not-skipped "history"
|
||||
this.highlights.push(page);
|
||||
hosts.add(hostname);
|
||||
|
||||
// Skip the rest if we have enough items
|
||||
if (this.highlights.length === HIGHLIGHTS_MAX_LENGTH) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SectionsManager.updateSection(SECTION_ID, {rows: this.highlights}, this.highlightsLastUpdated === 0 || broadcast);
|
||||
this.highlightsLastUpdated = Date.now();
|
||||
|
|
|
@ -12,12 +12,30 @@ const {actionCreators: ac, actionTypes: at} = Cu.import("resource://activity-str
|
|||
* newly opened tabs.
|
||||
*/
|
||||
this.NewTabInit = class NewTabInit {
|
||||
constructor() {
|
||||
this._queue = new Set();
|
||||
}
|
||||
reply(target) {
|
||||
const action = {type: at.NEW_TAB_INITIAL_STATE, data: this.store.getState()};
|
||||
this.store.dispatch(ac.SendToContent(action, target));
|
||||
}
|
||||
onAction(action) {
|
||||
let newAction;
|
||||
switch (action.type) {
|
||||
case at.NEW_TAB_LOAD:
|
||||
newAction = {type: at.NEW_TAB_INITIAL_STATE, data: this.store.getState()};
|
||||
this.store.dispatch(ac.SendToContent(newAction, action.meta.fromTarget));
|
||||
case at.NEW_TAB_STATE_REQUEST:
|
||||
// If localization hasn't been loaded yet, we should wait for it.
|
||||
if (!this.store.getState().App.strings) {
|
||||
this._queue.add(action.meta.fromTarget);
|
||||
return;
|
||||
}
|
||||
this.reply(action.meta.fromTarget);
|
||||
break;
|
||||
case at.LOCALE_UPDATED:
|
||||
// If the queue is full because we were waiting for strings,
|
||||
// dispatch them now.
|
||||
if (this._queue.size > 0 && this.store.getState().App.strings) {
|
||||
this._queue.forEach(target => this.reply(target));
|
||||
this._queue.clear();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,17 +7,39 @@ const {utils: Cu} = Components;
|
|||
|
||||
const {actionCreators: ac, actionTypes: at} = Cu.import("resource://activity-stream/common/Actions.jsm", {});
|
||||
const {Prefs} = Cu.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm", {});
|
||||
const {PrerenderData} = Cu.import("resource://activity-stream/common/PrerenderData.jsm", {});
|
||||
|
||||
this.PrefsFeed = class PrefsFeed {
|
||||
constructor(prefMap) {
|
||||
this._prefMap = prefMap;
|
||||
this._prefs = new Prefs();
|
||||
}
|
||||
|
||||
// If the any prefs are set to something other than what the prerendered version
|
||||
// of AS expects, we can't use it.
|
||||
_setPrerenderPref() {
|
||||
for (const prefName of PrerenderData.invalidatingPrefs) {
|
||||
if (this._prefs.get(prefName) !== PrerenderData.initialPrefs[prefName]) {
|
||||
this._prefs.set("prerender", false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this._prefs.set("prerender", true);
|
||||
}
|
||||
|
||||
_checkPrerender(name) {
|
||||
if (PrerenderData.invalidatingPrefs.includes(name)) {
|
||||
this._setPrerenderPref();
|
||||
}
|
||||
}
|
||||
|
||||
onPrefChanged(name, value) {
|
||||
if (this._prefMap.has(name)) {
|
||||
this.store.dispatch(ac.BroadcastToContent({type: at.PREF_CHANGED, data: {name, value}}));
|
||||
}
|
||||
this._checkPrerender(name, value);
|
||||
}
|
||||
|
||||
init() {
|
||||
this._prefs.observeBranch(this);
|
||||
|
||||
|
@ -29,6 +51,8 @@ this.PrefsFeed = class PrefsFeed {
|
|||
|
||||
// Set the initial state of all prefs in redux
|
||||
this.store.dispatch(ac.BroadcastToContent({type: at.PREFS_INITIAL_VALUES, data: values}));
|
||||
|
||||
this._setPrerenderPref();
|
||||
}
|
||||
removeListeners() {
|
||||
this._prefs.ignoreBranch(this);
|
||||
|
|
|
@ -48,7 +48,7 @@ const BUILT_IN_SECTIONS = {
|
|||
icon: "highlights",
|
||||
title: {id: "header_highlights"},
|
||||
maxRows: 3,
|
||||
availableContextMenuOptions: ["CheckBookmark", "SaveToPocket", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl"],
|
||||
availableContextMenuOptions: ["CheckBookmark", "SaveToPocket", "Separator", "OpenInNewWindow", "OpenInPrivateWindow", "Separator", "BlockUrl", "DeleteUrl"],
|
||||
emptyState: {
|
||||
message: {id: "highlights_empty_state"},
|
||||
icon: "highlights"
|
||||
|
|
|
@ -121,7 +121,7 @@ this.SnippetsFeed = class SnippetsFeed {
|
|||
Services.prefs.removeObserver(TELEMETRY_PREF, this._refresh);
|
||||
Services.prefs.removeObserver(FXA_USERNAME_PREF, this._refresh);
|
||||
Services.obs.removeObserver(this, SEARCH_ENGINE_OBSERVER_TOPIC);
|
||||
this.store.dispatch({type: at.SNIPPETS_RESET});
|
||||
this.store.dispatch(ac.BroadcastToContent({type: at.SNIPPETS_RESET}));
|
||||
}
|
||||
|
||||
showFirefoxAccounts(browser) {
|
||||
|
|
|
@ -21,6 +21,7 @@ const UPDATE_TIME = 15 * 60 * 1000; // 15 minutes
|
|||
const DEFAULT_SITES_PREF = "default.sites";
|
||||
const DEFAULT_TOP_SITES = [];
|
||||
const FRECENCY_THRESHOLD = 100; // 1 visit (skip first-run/one-time pages)
|
||||
const MIN_FAVICON_SIZE = 96;
|
||||
|
||||
this.TopSitesFeed = class TopSitesFeed {
|
||||
constructor() {
|
||||
|
@ -95,13 +96,13 @@ this.TopSitesFeed = class TopSitesFeed {
|
|||
}
|
||||
}
|
||||
|
||||
// Now, get a tippy top icon or screenshot for every item
|
||||
// Now, get a tippy top icon, a rich icon, or screenshot for every item
|
||||
for (let link of links) {
|
||||
if (!link) { continue; }
|
||||
|
||||
// Check for tippy top icon.
|
||||
// Check for tippy top icon or a rich icon.
|
||||
link = this._tippyTopProvider.processSite(link);
|
||||
if (link.tippyTopIcon) { continue; }
|
||||
if (link.tippyTopIcon || link.faviconSize >= MIN_FAVICON_SIZE) { continue; }
|
||||
|
||||
// If no tippy top, then we get a screenshot.
|
||||
if (currentScreenshots[link.url]) {
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
const prerender = require("content-src/activity-stream-prerender");
|
||||
const {prerenderStore} = prerender;
|
||||
const {PrerenderData} = require("common/PrerenderData.jsm");
|
||||
|
||||
describe("prerenderStore", () => {
|
||||
it("should create a store", () => {
|
||||
const store = prerenderStore();
|
||||
|
||||
assert.isFunction(store.getState);
|
||||
});
|
||||
it("should start uninitialized", () => {
|
||||
const store = prerenderStore();
|
||||
|
||||
const state = store.getState();
|
||||
assert.equal(state.App.initialized, false);
|
||||
});
|
||||
it("should set the right locale, strings, and text direction", () => {
|
||||
const strings = {foo: "foo"};
|
||||
|
||||
const store = prerenderStore("en-FOO", strings);
|
||||
|
||||
const state = store.getState();
|
||||
assert.equal(state.App.locale, "en-FOO");
|
||||
assert.equal(state.App.strings, strings);
|
||||
assert.equal(state.App.textDirection, "ltr");
|
||||
});
|
||||
it("should add the right initial prefs", () => {
|
||||
const store = prerenderStore();
|
||||
|
||||
const state = store.getState();
|
||||
assert.equal(state.Prefs.values, PrerenderData.initialPrefs);
|
||||
});
|
||||
it("should add TopStories as the first section", () => {
|
||||
const store = prerenderStore();
|
||||
|
||||
const state = store.getState();
|
||||
// TopStories
|
||||
const firstSection = state.Sections[0];
|
||||
assert.equal(firstSection.id, "topstories");
|
||||
// it should start uninitialized
|
||||
assert.equal(firstSection.initialized, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("prerender", () => {
|
||||
it("should set the locale and get the right strings of whatever is passed in", () => {
|
||||
const {store} = prerender("en-US");
|
||||
|
||||
const state = store.getState();
|
||||
assert.equal(state.App.locale, "en-US");
|
||||
assert.equal(state.App.strings.newtab_page_title, "New Tab");
|
||||
});
|
||||
it("should throw if an unknown locale is passed in", () => {
|
||||
assert.throws(() => prerender("en-FOO"));
|
||||
});
|
||||
it("should set the locale to en-PRERENDER and have empty strings if no locale is passed in", () => {
|
||||
const {store} = prerender();
|
||||
|
||||
const state = store.getState();
|
||||
assert.equal(state.App.locale, "en-PRERENDER");
|
||||
assert.equal(state.App.strings.newtab_page_title, " ");
|
||||
});
|
||||
// # TODO: Remove when #3370 is resolved.
|
||||
it("should render a real English string for search_web_placeholder", () => {
|
||||
const {store} = prerender();
|
||||
|
||||
const state = store.getState();
|
||||
assert.equal(state.App.strings.search_web_placeholder, "Search the Web");
|
||||
});
|
||||
});
|
|
@ -26,12 +26,20 @@ describe("Reducers", () => {
|
|||
const nextState = App(undefined, {type: at.LOCALE_UPDATED});
|
||||
assert.equal(nextState, INITIAL_STATE.App);
|
||||
});
|
||||
it("should set locale, strings on LOCALE_UPDATE", () => {
|
||||
it("should set locale, strings and text direction on LOCALE_UPDATE", () => {
|
||||
const strings = {};
|
||||
const action = {type: "LOCALE_UPDATED", data: {locale: "zh-CN", strings}};
|
||||
const nextState = App(undefined, action);
|
||||
assert.propertyVal(nextState, "locale", "zh-CN");
|
||||
assert.propertyVal(nextState, "strings", strings);
|
||||
assert.propertyVal(nextState, "textDirection", "ltr");
|
||||
});
|
||||
it("should set rtl text direction for RTL locales", () => {
|
||||
const action = {type: "LOCALE_UPDATED", data: {locale: "ar"}};
|
||||
|
||||
const nextState = App(undefined, action);
|
||||
|
||||
assert.propertyVal(nextState, "textDirection", "rtl");
|
||||
});
|
||||
});
|
||||
describe("TopSites", () => {
|
||||
|
|
|
@ -30,7 +30,7 @@ describe("Top Sites Feed", () => {
|
|||
updateSection: sinon.spy(),
|
||||
sections: new Map([["highlights", {}]])
|
||||
};
|
||||
shortURLStub = sinon.stub().callsFake(site => site.url);
|
||||
shortURLStub = sinon.stub().callsFake(site => site.url.match(/\/([^/]+)/)[1]);
|
||||
globals.set("NewTabUtils", fakeNewTabUtils);
|
||||
({HighlightsFeed, HIGHLIGHTS_UPDATE_TIME, SECTION_ID} = injector({
|
||||
"lib/ShortURL.jsm": {shortURL: shortURLStub},
|
||||
|
@ -72,7 +72,7 @@ describe("Top Sites Feed", () => {
|
|||
it("should add hostname and image to each link", async () => {
|
||||
links = [{url: "https://mozilla.org", preview_image_url: "https://mozilla.org/preview.jog"}];
|
||||
await feed.fetchHighlights();
|
||||
assert.equal(feed.highlights[0].hostname, links[0].url);
|
||||
assert.equal(feed.highlights[0].hostname, "mozilla.org");
|
||||
assert.equal(feed.highlights[0].image, links[0].preview_image_url);
|
||||
});
|
||||
it("should not include any links already in Top Sites", async () => {
|
||||
|
@ -86,6 +86,30 @@ describe("Top Sites Feed", () => {
|
|||
assert.equal(feed.highlights.length, 1);
|
||||
assert.deepEqual(feed.highlights[0], links[0]);
|
||||
});
|
||||
it("should not include history of same hostname as a bookmark", async () => {
|
||||
links = [
|
||||
{url: "https://site.com/bookmark", type: "bookmark"},
|
||||
{url: "https://site.com/history", type: "history"}
|
||||
];
|
||||
|
||||
await feed.fetchHighlights();
|
||||
|
||||
assert.equal(feed.highlights.length, 1);
|
||||
assert.deepEqual(feed.highlights[0], links[0]);
|
||||
});
|
||||
it("should take the first history of a hostname", async () => {
|
||||
links = [
|
||||
{url: "https://site.com/first", type: "history"},
|
||||
{url: "https://site.com/second", type: "history"},
|
||||
{url: "https://other", type: "history"}
|
||||
];
|
||||
|
||||
await feed.fetchHighlights();
|
||||
|
||||
assert.equal(feed.highlights.length, 2);
|
||||
assert.deepEqual(feed.highlights[0], links[0]);
|
||||
assert.deepEqual(feed.highlights[1], links[2]);
|
||||
});
|
||||
it("should set type to bookmark if there is a bookmarkGuid", async () => {
|
||||
links = [{url: "https://mozilla.org", type: "history", bookmarkGuid: "1234567890"}];
|
||||
await feed.fetchHighlights();
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
const {NewTabInit} = require("lib/NewTabInit.jsm");
|
||||
const {actionTypes: at, actionCreators: ac} = require("common/Actions.jsm");
|
||||
|
||||
describe("NewTabInit", () => {
|
||||
let instance;
|
||||
let store;
|
||||
let STATE;
|
||||
beforeEach(() => {
|
||||
STATE = {};
|
||||
store = {getState: sinon.stub().returns(STATE), dispatch: sinon.stub()};
|
||||
instance = new NewTabInit();
|
||||
instance.store = store;
|
||||
});
|
||||
it("should reply with a copy of the state immediately if localization is ready", () => {
|
||||
STATE.App = {strings: {}};
|
||||
|
||||
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, 123));
|
||||
|
||||
const resp = ac.SendToContent({type: at.NEW_TAB_INITIAL_STATE, data: STATE}, 123);
|
||||
assert.calledWith(store.dispatch, resp);
|
||||
});
|
||||
it("should not reply immediately if localization is not ready", () => {
|
||||
STATE.App = {strings: null};
|
||||
|
||||
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, 123));
|
||||
|
||||
assert.notCalled(store.dispatch);
|
||||
});
|
||||
it("should dispatch responses for queued targets when LOCALE_UPDATED is received", () => {
|
||||
STATE.App = {strings: null};
|
||||
|
||||
// Send requests before strings are ready
|
||||
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "foo"));
|
||||
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "bar"));
|
||||
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "baz"));
|
||||
assert.notCalled(store.dispatch);
|
||||
|
||||
// Update strings
|
||||
STATE.App = {strings: {}};
|
||||
instance.onAction({type: at.LOCALE_UPDATED});
|
||||
|
||||
assert.calledThrice(store.dispatch);
|
||||
const action = {type: at.NEW_TAB_INITIAL_STATE, data: STATE};
|
||||
assert.calledWith(store.dispatch, ac.SendToContent(action, "foo"));
|
||||
assert.calledWith(store.dispatch, ac.SendToContent(action, "bar"));
|
||||
assert.calledWith(store.dispatch, ac.SendToContent(action, "baz"));
|
||||
});
|
||||
it("should clear targets from the queue once they have been sent", () => {
|
||||
STATE.App = {strings: null};
|
||||
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "foo"));
|
||||
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "bar"));
|
||||
instance.onAction(ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST}, "baz"));
|
||||
|
||||
STATE.App = {strings: {}};
|
||||
instance.onAction({type: at.LOCALE_UPDATED});
|
||||
assert.calledThrice(store.dispatch);
|
||||
|
||||
store.dispatch.reset();
|
||||
instance.onAction({type: at.LOCALE_UPDATED});
|
||||
assert.notCalled(store.dispatch);
|
||||
});
|
||||
});
|
|
@ -1,16 +1,20 @@
|
|||
const {PrefsFeed} = require("lib/PrefsFeed.jsm");
|
||||
const {actionTypes: at, actionCreators: ac} = require("common/Actions.jsm");
|
||||
const {PrerenderData} = require("common/PrerenderData.jsm");
|
||||
const {initialPrefs} = PrerenderData;
|
||||
|
||||
const FAKE_PREFS = new Map([["foo", {value: 1}], ["bar", {value: 2}]]);
|
||||
const PRERENDER_PREF_NAME = "prerender";
|
||||
|
||||
describe("PrefsFeed", () => {
|
||||
let feed;
|
||||
let FAKE_PREFS;
|
||||
beforeEach(() => {
|
||||
FAKE_PREFS = new Map([["foo", 1], ["bar", 2]]);
|
||||
feed = new PrefsFeed(FAKE_PREFS);
|
||||
feed.store = {dispatch: sinon.spy()};
|
||||
feed._prefs = {
|
||||
get: sinon.spy(item => FAKE_PREFS.get(item).value),
|
||||
set: sinon.spy(),
|
||||
get: sinon.spy(item => FAKE_PREFS.get(item)),
|
||||
set: sinon.spy((name, value) => FAKE_PREFS.set(name, value)),
|
||||
observe: sinon.spy(),
|
||||
observeBranch: sinon.spy(),
|
||||
ignore: sinon.spy(),
|
||||
|
@ -41,4 +45,42 @@ describe("PrefsFeed", () => {
|
|||
feed.onPrefChanged("foo", 2);
|
||||
assert.calledWith(feed.store.dispatch, ac.BroadcastToContent({type: at.PREF_CHANGED, data: {name: "foo", value: 2}}));
|
||||
});
|
||||
describe("INIT prerendering", () => {
|
||||
it("should set a prerender pref on init", () => {
|
||||
feed.onAction({type: at.INIT});
|
||||
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME);
|
||||
});
|
||||
it("should set prerender pref to true if prefs match initial values", () => {
|
||||
Object.keys(initialPrefs).forEach(name => FAKE_PREFS.set(name, initialPrefs[name]));
|
||||
feed.onAction({type: at.INIT});
|
||||
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME, true);
|
||||
});
|
||||
it("should set prerender pref to false if a pref does not match its initial value", () => {
|
||||
Object.keys(initialPrefs).forEach(name => FAKE_PREFS.set(name, initialPrefs[name]));
|
||||
FAKE_PREFS.set("feeds.section.topstories", false);
|
||||
feed.onAction({type: at.INIT});
|
||||
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME, false);
|
||||
});
|
||||
});
|
||||
describe("onPrefChanged prerendering", () => {
|
||||
it("should not change the prerender pref if the pref is not included in invalidatingPrefs", () => {
|
||||
feed.onPrefChanged("foo123", true);
|
||||
assert.notCalled(feed._prefs.set);
|
||||
});
|
||||
it("should set the prerender pref to false if a pref in invalidatingPrefs is changed from its original value", () => {
|
||||
Object.keys(initialPrefs).forEach(name => FAKE_PREFS.set(name, initialPrefs[name]));
|
||||
|
||||
feed._prefs.set("feeds.section.topstories", false);
|
||||
feed.onPrefChanged("feeds.section.topstories", false);
|
||||
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME, false);
|
||||
});
|
||||
it("should set the prerender pref back to true if the invalidatingPrefs are changed back to their original values", () => {
|
||||
Object.keys(initialPrefs).forEach(name => FAKE_PREFS.set(name, initialPrefs[name]));
|
||||
FAKE_PREFS.set("feeds.section.topstories", false);
|
||||
|
||||
feed._prefs.set("feeds.section.topstories", true);
|
||||
feed.onPrefChanged("feeds.section.topstories", true);
|
||||
assert.calledWith(feed._prefs.set, PRERENDER_PREF_NAME, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const {SnippetsFeed} = require("lib/SnippetsFeed.jsm");
|
||||
const {actionTypes: at} = require("common/Actions.jsm");
|
||||
const {actionCreators: ac, actionTypes: at} = require("common/Actions.jsm");
|
||||
const {GlobalOverrider} = require("test/unit/utils");
|
||||
|
||||
const WEEK_IN_MS = 7 * 24 * 60 * 60 * 1000;
|
||||
|
@ -78,13 +78,13 @@ describe("SnippetsFeed", () => {
|
|||
feed.onAction({type: at.UNINIT});
|
||||
assert.calledOnce(feed.uninit);
|
||||
});
|
||||
it("should dispatch a SNIPPETS_RESET on uninit", () => {
|
||||
it("should broadcast a SNIPPETS_RESET on uninit", () => {
|
||||
const feed = new SnippetsFeed();
|
||||
feed.store = {dispatch: sandbox.stub()};
|
||||
|
||||
feed.uninit();
|
||||
|
||||
assert.calledWith(feed.store.dispatch, {type: at.SNIPPETS_RESET});
|
||||
assert.calledWith(feed.store.dispatch, ac.BroadcastToContent({type: at.SNIPPETS_RESET}));
|
||||
});
|
||||
it("should dispatch an update event when the Search observer is called", async () => {
|
||||
const feed = new SnippetsFeed();
|
||||
|
|
|
@ -295,6 +295,22 @@ describe("Top Sites Feed", () => {
|
|||
assert.calledOnce(feed.store.dispatch);
|
||||
assert.notCalled(feed.getScreenshot);
|
||||
});
|
||||
it("should skip getting screenshot if there is an icon of size greater than 96x96 and no tippy top", async () => {
|
||||
sandbox.stub(feed, "getScreenshot");
|
||||
feed.getLinksWithDefaults = () => [{
|
||||
url: "foo.com",
|
||||
favicon: "data:foo",
|
||||
faviconSize: 196
|
||||
}];
|
||||
feed._tippyTopProvider.processSite = site => {
|
||||
site.tippyTopIcon = null;
|
||||
site.backgroundColor = null;
|
||||
return site;
|
||||
};
|
||||
await feed.refresh(action);
|
||||
assert.calledOnce(feed.store.dispatch);
|
||||
assert.notCalled(feed.getScreenshot);
|
||||
});
|
||||
});
|
||||
describe("getScreenshot", () => {
|
||||
it("should call Screenshots.getScreenshotForURL with the right url", async () => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const initStore = require("content-src/lib/init-store");
|
||||
const {MERGE_STORE_ACTION, rehydrationMiddleware} = initStore;
|
||||
const {GlobalOverrider, addNumberReducer} = require("test/unit/utils");
|
||||
const {actionCreators: ac} = require("common/Actions.jsm");
|
||||
const {actionCreators: ac, actionTypes: at} = require("common/Actions.jsm");
|
||||
|
||||
describe("initStore", () => {
|
||||
let globals;
|
||||
|
@ -16,20 +17,33 @@ describe("initStore", () => {
|
|||
assert.ok(store);
|
||||
assert.property(store.getState(), "number");
|
||||
});
|
||||
it("should add a listener for incoming actions", () => {
|
||||
it("should add a listener that dispatches actions", () => {
|
||||
assert.calledWith(global.addMessageListener, initStore.INCOMING_MESSAGE_NAME);
|
||||
const callback = global.addMessageListener.firstCall.args[1];
|
||||
const listener = global.addMessageListener.firstCall.args[1];
|
||||
globals.sandbox.spy(store, "dispatch");
|
||||
const message = {name: initStore.INCOMING_MESSAGE_NAME, data: {type: "FOO"}};
|
||||
callback(message);
|
||||
|
||||
listener(message);
|
||||
|
||||
assert.calledWith(store.dispatch, message.data);
|
||||
});
|
||||
it("should not throw if addMessageListener is not defined", () => {
|
||||
// Note: this is being set/restored by GlobalOverrider
|
||||
delete global.addMessageListener;
|
||||
|
||||
assert.doesNotThrow(() => initStore({number: addNumberReducer}));
|
||||
});
|
||||
it("should initialize with an initial state if provided as the second argument", () => {
|
||||
store = initStore({number: addNumberReducer}, {number: 42});
|
||||
|
||||
assert.equal(store.getState().number, 42);
|
||||
});
|
||||
it("should log errors from failed messages", () => {
|
||||
const callback = global.addMessageListener.firstCall.args[1];
|
||||
globals.sandbox.stub(global.console, "error");
|
||||
globals.sandbox.stub(store, "dispatch").throws(Error("failed"));
|
||||
|
||||
const message = {name: initStore.INCOMING_MESSAGE_NAME, data: {type: "FOO"}};
|
||||
const message = {name: initStore.INCOMING_MESSAGE_NAME, data: {type: MERGE_STORE_ACTION}};
|
||||
callback(message);
|
||||
|
||||
assert.calledOnce(global.console.error);
|
||||
|
@ -38,13 +52,60 @@ describe("initStore", () => {
|
|||
store.dispatch({type: initStore.MERGE_STORE_ACTION, data: {number: 42}});
|
||||
assert.deepEqual(store.getState(), {number: 42});
|
||||
});
|
||||
it("should send out SendToMain ations", () => {
|
||||
it("should send out SendToMain actions", () => {
|
||||
const action = ac.SendToMain({type: "FOO"});
|
||||
store.dispatch(action);
|
||||
assert.calledWith(global.sendAsyncMessage, initStore.OUTGOING_MESSAGE_NAME, action);
|
||||
});
|
||||
it("should not send out other types of ations", () => {
|
||||
it("should not send out other types of actions", () => {
|
||||
store.dispatch({type: "FOO"});
|
||||
assert.notCalled(global.sendAsyncMessage);
|
||||
});
|
||||
describe("rehydrationMiddleware", () => {
|
||||
it("should allow NEW_TAB_STATE_REQUEST to go through", () => {
|
||||
const action = ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST});
|
||||
const next = sinon.spy();
|
||||
rehydrationMiddleware(store)(next)(action);
|
||||
assert.calledWith(next, action);
|
||||
});
|
||||
it("should dispatch an additional NEW_TAB_STATE_REQUEST if INIT was received after a request", () => {
|
||||
const requestAction = ac.SendToMain({type: at.NEW_TAB_STATE_REQUEST});
|
||||
const next = sinon.spy();
|
||||
|
||||
rehydrationMiddleware(store)(next)(requestAction);
|
||||
|
||||
next.reset();
|
||||
rehydrationMiddleware(store)(next)({type: at.INIT});
|
||||
assert.calledWith(next, requestAction);
|
||||
});
|
||||
it("should allow MERGE_STORE_ACTION to go through", () => {
|
||||
const action = {type: MERGE_STORE_ACTION};
|
||||
const next = sinon.spy();
|
||||
rehydrationMiddleware(store)(next)(action);
|
||||
assert.calledWith(next, action);
|
||||
});
|
||||
it("should not allow actions from main to go through before MERGE_STORE_ACTION was received", () => {
|
||||
const next = sinon.spy();
|
||||
|
||||
rehydrationMiddleware(store)(next)(ac.BroadcastToContent({type: "FOO"}));
|
||||
rehydrationMiddleware(store)(next)(ac.SendToContent({type: "FOO"}, 123));
|
||||
|
||||
assert.notCalled(next);
|
||||
});
|
||||
it("should allow all local actions to go through", () => {
|
||||
const action = {type: "FOO"};
|
||||
const next = sinon.spy();
|
||||
rehydrationMiddleware(store)(next)(action);
|
||||
assert.calledWith(next, action);
|
||||
});
|
||||
it("should allow actions from main to go through after MERGE_STORE_ACTION has been received", () => {
|
||||
const next = sinon.spy();
|
||||
rehydrationMiddleware(store)(next)({type: MERGE_STORE_ACTION});
|
||||
next.reset();
|
||||
|
||||
const action = ac.SendToContent({type: "FOO"}, 123);
|
||||
rehydrationMiddleware(store)(next)(action);
|
||||
assert.calledWith(next, action);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче