Merge mozilla-central to inbound a=merge on a CLOSED TREE

This commit is contained in:
Coroiu Cristina 2019-01-25 23:55:33 +02:00
Родитель 230e9f6e8f caf5db8e62
Коммит 1ec6503fd8
245 изменённых файлов: 4253 добавлений и 1825 удалений

Просмотреть файл

@ -858,8 +858,6 @@ pref("browser.sessionstore.debug", false);
pref("browser.sessionstore.debug.no_auto_updates", false);
// Forget closed windows/tabs after two weeks
pref("browser.sessionstore.cleanup.forget_closed_after", 1209600000);
// Maximum number of bytes of DOMSessionStorage data we collect per origin.
pref("browser.sessionstore.dom_storage_limit", 2048);
// Amount of failed SessionFile writes until we restart the worker.
pref("browser.sessionstore.max_write_failures", 5);
@ -1224,6 +1222,7 @@ pref("services.sync.prefs.sync.intl.accept_languages", true);
pref("services.sync.prefs.sync.layout.spellcheckDefault", true);
pref("services.sync.prefs.sync.lightweightThemes.selectedThemeID", true);
pref("services.sync.prefs.sync.lightweightThemes.usedThemes", true);
pref("services.sync.prefs.sync.media.eme.enabled", true);
pref("services.sync.prefs.sync.network.cookie.cookieBehavior", true);
pref("services.sync.prefs.sync.network.cookie.lifetimePolicy", true);
pref("services.sync.prefs.sync.network.cookie.thirdparty.sessionOnly", true);

Просмотреть файл

@ -11,11 +11,15 @@ const CONTAINER_PAGE = "http://not-tracking.example.com/browser/browser/base/con
const TPC_PREF = "network.cookie.cookieBehavior";
add_task(async function setup() {
let oldCanRecord = Services.telemetry.canRecordExtended;
Services.telemetry.canRecordExtended = true;
// Avoid the content blocking tour interfering with our tests by popping up.
await SpecialPowers.pushPrefEnv({set: [[ContentBlocking.prefIntroCount, ContentBlocking.MAX_INTROS]]});
await UrlClassifierTestUtils.addTestTrackers();
registerCleanupFunction(() => {
Services.telemetry.canRecordExtended = oldCanRecord;
UrlClassifierTestUtils.cleanupTestTrackers();
});
});
@ -38,6 +42,8 @@ async function assertSitesListed(trackersBlocked, thirdPartyBlocked, firstPartyB
await openIdentityPopup();
Services.telemetry.clearEvents();
let categoryItem =
document.getElementById("identity-popup-content-blocking-category-cookies");
ok(BrowserTestUtils.is_visible(categoryItem), "TP category item is visible");
@ -48,6 +54,11 @@ async function assertSitesListed(trackersBlocked, thirdPartyBlocked, firstPartyB
ok(true, "Cookies view was shown");
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN).parent;
let buttonEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "cookies_subview_btn");
is(buttonEvents.length, 1, "recorded telemetry for the button click");
let listHeaders = cookiesView.querySelectorAll(".identity-popup-cookiesView-list-header");
is(listHeaders.length, 3, "We have 3 list headers");

Просмотреть файл

@ -7,17 +7,17 @@ const TP_PREF = "privacy.trackingprotection.enabled";
const TPC_PREF = "network.cookie.cookieBehavior";
const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/trackingUI/trackingPage.html";
async function waitAndAssertPreferencesShown() {
async function waitAndAssertPreferencesShown(_spotlight) {
await BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden");
await TestUtils.waitForCondition(() => gBrowser.currentURI.spec == "about:preferences#privacy",
"Should open about:preferences.");
await ContentTask.spawn(gBrowser.selectedBrowser, {}, async function() {
await ContentTask.spawn(gBrowser.selectedBrowser, {spotlight: _spotlight}, async function({spotlight}) {
let doc = content.document;
let section = await ContentTaskUtils.waitForCondition(
() => doc.querySelector(".spotlight"), "The spotlight should appear.");
is(section.getAttribute("data-subcategory"), "trackingprotection",
"The trackingprotection section is spotlighted.");
is(section.getAttribute("data-subcategory"), spotlight,
"The correct section is spotlighted.");
});
BrowserTestUtils.removeTab(gBrowser.selectedTab);
@ -30,14 +30,13 @@ add_task(async function setup() {
registerCleanupFunction(() => {
Services.telemetry.canRecordExtended = oldCanRecord;
UrlClassifierTestUtils.cleanupTestTrackers();
});
Services.telemetry.clearEvents();
});
// Tests that pressing the preferences icon in the identity popup
// Tests that pressing the content blocking preferences icon in the identity popup
// links to about:preferences
add_task(async function testOpenPreferencesFromPrefsButton() {
add_task(async function testOpenPreferencesFromCBPrefsButton() {
await BrowserTestUtils.withNewTab("https://example.com", async function() {
let promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
@ -45,9 +44,11 @@ add_task(async function testOpenPreferencesFromPrefsButton() {
let preferencesButton = document.getElementById("tracking-protection-preferences-button");
ok(!BrowserTestUtils.is_hidden(preferencesButton), "The enable tracking protection button is shown.");
ok(BrowserTestUtils.is_visible(preferencesButton), "The preferences button is shown.");
let shown = waitAndAssertPreferencesShown();
Services.telemetry.clearEvents();
let shown = waitAndAssertPreferencesShown("trackingprotection");
preferencesButton.click();
await shown;
@ -58,35 +59,105 @@ add_task(async function testOpenPreferencesFromPrefsButton() {
});
});
// Tests that clicking the contentblocking category items "add blocking" labels
// Tests that pressing the permissions preferences icon in the identity popup
// links to about:preferences
add_task(async function testOpenPreferencesFromAddBlockingButtons() {
SpecialPowers.pushPrefEnv({set: [
[TP_PREF, false],
[TPC_PREF, Ci.nsICookieService.BEHAVIOR_ACCEPT],
]});
add_task(async function testOpenPreferencesFromPermissionsPrefsButton() {
await BrowserTestUtils.withNewTab("https://example.com", async function() {
let promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
await promisePanelOpen;
await BrowserTestUtils.withNewTab(TRACKING_PAGE, async function() {
let addBlockingButtons = document.querySelectorAll(".identity-popup-content-blocking-category-add-blocking");
for (let button of addBlockingButtons) {
let promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
await promisePanelOpen;
let preferencesButton = document.getElementById("identity-popup-permission-preferences-button");
ok(BrowserTestUtils.is_visible(button), "Button is shown.");
let shown = waitAndAssertPreferencesShown();
button.click();
await shown;
ok(BrowserTestUtils.is_visible(preferencesButton), "The preferences button is shown.");
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
let clickEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3].endsWith("_add_blocking"));
is(clickEvents.length, 1, "recorded telemetry for the click");
}
Services.telemetry.clearEvents();
let shown = waitAndAssertPreferencesShown("permissions");
preferencesButton.click();
await shown;
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
let clickEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "permission_prefs_btn");
is(clickEvents.length, 1, "recorded telemetry for the click");
});
});
// Tests that pressing the preferences button in the trackers subview
// links to about:preferences
add_task(async function testOpenPreferencesFromTrackersSubview() {
Services.prefs.setBoolPref(TP_PREF, true);
add_task(async function cleanup() {
UrlClassifierTestUtils.cleanupTestTrackers();
await BrowserTestUtils.withNewTab(TRACKING_PAGE, async function() {
let promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
await promisePanelOpen;
let categoryItem =
document.getElementById("identity-popup-content-blocking-category-tracking-protection");
ok(BrowserTestUtils.is_visible(categoryItem), "TP category item is visible");
let trackersView = document.getElementById("identity-popup-trackersView");
let viewShown = BrowserTestUtils.waitForEvent(trackersView, "ViewShown");
categoryItem.click();
await viewShown;
ok(true, "Trackers view was shown");
let preferencesButton = document.getElementById("identity-popup-trackersView-settings-button");
ok(BrowserTestUtils.is_visible(preferencesButton), "The preferences button is shown.");
Services.telemetry.clearEvents();
let shown = waitAndAssertPreferencesShown("trackingprotection");
preferencesButton.click();
await shown;
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
let clickEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "trackers_prefs_btn");
is(clickEvents.length, 1, "recorded telemetry for the click");
});
Services.prefs.clearUserPref(TP_PREF);
});
// Tests that pressing the preferences button in the cookies subview
// links to about:preferences
add_task(async function testOpenPreferencesFromCookiesSubview() {
Services.prefs.setIntPref(TPC_PREF, Ci.nsICookieService.BEHAVIOR_REJECT_TRACKER);
await BrowserTestUtils.withNewTab(TRACKING_PAGE, async function() {
let promisePanelOpen = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popupshown");
gIdentityHandler._identityBox.click();
await promisePanelOpen;
let categoryItem =
document.getElementById("identity-popup-content-blocking-category-cookies");
ok(BrowserTestUtils.is_visible(categoryItem), "TP category item is visible");
let cookiesView = document.getElementById("identity-popup-cookiesView");
let viewShown = BrowserTestUtils.waitForEvent(cookiesView, "ViewShown");
categoryItem.click();
await viewShown;
ok(true, "Cookies view was shown");
let preferencesButton = document.getElementById("identity-popup-cookiesView-settings-button");
ok(BrowserTestUtils.is_visible(preferencesButton), "The preferences button is shown.");
Services.telemetry.clearEvents();
let shown = waitAndAssertPreferencesShown("trackingprotection");
preferencesButton.click();
await shown;
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).parent;
let clickEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "cookies_prefs_btn");
is(clickEvents.length, 1, "recorded telemetry for the click");
});
Services.prefs.clearUserPref(TPC_PREF);
});

Просмотреть файл

@ -9,11 +9,15 @@ const TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/
const TP_PREF = "privacy.trackingprotection.enabled";
add_task(async function setup() {
let oldCanRecord = Services.telemetry.canRecordExtended;
Services.telemetry.canRecordExtended = true;
// Avoid the content blocking tour interfering with our tests by popping up.
await SpecialPowers.pushPrefEnv({set: [[ContentBlocking.prefIntroCount, ContentBlocking.MAX_INTROS]]});
await UrlClassifierTestUtils.addTestTrackers();
registerCleanupFunction(() => {
Services.telemetry.canRecordExtended = oldCanRecord;
UrlClassifierTestUtils.cleanupTestTrackers();
});
});
@ -22,6 +26,8 @@ async function assertSitesListed(blocked) {
await BrowserTestUtils.withNewTab(TRACKING_PAGE, async function(browser) {
await openIdentityPopup();
Services.telemetry.clearEvents();
let categoryItem =
document.getElementById("identity-popup-content-blocking-category-tracking-protection");
ok(BrowserTestUtils.is_visible(categoryItem), "TP category item is visible");
@ -32,6 +38,11 @@ async function assertSitesListed(blocked) {
ok(true, "Trackers view was shown");
let events = Services.telemetry.snapshotEvents(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN).parent;
let buttonEvents = events.filter(
e => e[1] == "security.ui.identitypopup" && e[2] == "click" && e[3] == "trackers_subview_btn");
is(buttonEvents.length, 1, "recorded telemetry for the button click");
let listItems = trackersView.querySelectorAll(".identity-popup-content-blocking-list-item");
is(listItems.length, 1, "We have 1 tracker in the list");

Просмотреть файл

@ -50,7 +50,7 @@
<button id="identity-popup-security-expander"
class="identity-popup-expander"
when-connection="not-secure secure secure-ev secure-cert-user-overridden"
oncommand="gIdentityHandler.showSecuritySubView();"/>
oncommand="gIdentityHandler.showSecuritySubView(); gIdentityHandler.recordClick('security_subview_btn');"/>
</hbox>
<!-- Tracking Protection Section -->
@ -75,14 +75,14 @@
<vbox id="identity-popup-content-blocking-category-list">
<toolbarbutton id="identity-popup-content-blocking-category-tracking-protection"
onclick="ContentBlocking.showTrackersSubview()"
onclick="ContentBlocking.showTrackersSubview(); gIdentityHandler.recordClick('trackers_subview_btn');"
class="identity-popup-content-blocking-category" align="center">
<image class="identity-popup-content-blocking-category-icon tracking-protection-icon"/>
<label flex="1" class="identity-popup-content-blocking-category-label">&contentBlocking.trackingProtection3.label;</label>
<label flex="1" id="identity-popup-content-blocking-tracking-protection-state-label" class="identity-popup-content-blocking-category-state-label"/>
</toolbarbutton>
<toolbarbutton id="identity-popup-content-blocking-category-cookies"
onclick="ContentBlocking.showCookiesSubview()"
onclick="ContentBlocking.showCookiesSubview(); gIdentityHandler.recordClick('cookies_subview_btn');"
class="identity-popup-content-blocking-category" align="center">
<image class="identity-popup-content-blocking-category-icon thirdpartycookies-icon"/>
<label flex="1" id="identity-popup-content-blocking-category-label-default"
@ -126,7 +126,7 @@
<toolbarbutton id="identity-popup-permission-preferences-button"
class="identity-popup-preferences-button subviewbutton"
tooltiptext="&identity.permissionsPreferences.tooltip;"
oncommand="gIdentityHandler.openPermissionPreferences();" />
oncommand="gIdentityHandler.openPermissionPreferences(); gIdentityHandler.recordClick('permission_prefs_btn');" />
</hbox>
<vbox id="identity-popup-permission-list"/>
<description id="identity-popup-permission-reload-hint">&identity.permissionsReloadHint;</description>
@ -250,7 +250,7 @@
<button id="identity-popup-trackersView-settings-button"
label="&contentBlocking.manageSettings.label;"
accesskey="&contentBlocking.manageSettings.accesskey;"
oncommand="ContentBlocking.openPreferences();"/>
oncommand="ContentBlocking.openPreferences(); gIdentityHandler.recordClick('trackers_prefs_btn');"/>
</vbox>
</panelview>
@ -265,7 +265,7 @@
<button id="identity-popup-cookiesView-settings-button"
label="&contentBlocking.manageSettings.label;"
accesskey="&contentBlocking.manageSettings.accesskey;"
oncommand="ContentBlocking.openPreferences();"/>
oncommand="ContentBlocking.openPreferences(); gIdentityHandler.recordClick('cookies_prefs_btn');"/>
</vbox>
</panelview>

Просмотреть файл

@ -41,7 +41,7 @@
}
}
[lwt-newtab-brighttext] {
[lwt-newtab-brighttext]:not(.force-light-theme) {
.secondary {
background-color: $grey-10-10;

Просмотреть файл

@ -0,0 +1,2 @@
// lifted from https://gist.github.com/kitze/23d82bb9eb0baabfd03a6a720b1d637f
export const ConditionalWrapper = ({condition, wrap, children}) => (condition ? wrap(children) : children);

Просмотреть файл

@ -23,7 +23,7 @@
text-decoration: underline;
}
[lwt-newtab-brighttext] & {
[lwt-newtab-brighttext]:not(.force-light-theme) & {
font-weight: bold;
}
}

Просмотреть файл

@ -1,4 +1,5 @@
import {Button} from "../../components/Button/Button";
import {ConditionalWrapper} from "../../components/ConditionalWrapper/ConditionalWrapper";
import React from "react";
import {RichText} from "../../components/RichText/RichText";
import {safeURI} from "../../template-utils";
@ -67,22 +68,64 @@ export class SimpleSnippet extends React.PureComponent {
sendClick={props.sendClick} />);
}
wrapSectionHeader(url) {
return function(children) {
return <a href={url}>{children}</a>;
};
}
wrapSnippetContent(children) {
return <div className="innerContentWrapper">{children}</div>;
}
renderSectionHeader() {
const {props} = this;
// an icon and text must be specified to render the section header
if (props.content.section_title_icon && props.content.section_title_text) {
const sectionTitleIcon = safeURI(props.content.section_title_icon);
const sectionTitleURL = props.content.section_title_url;
return (
<div className="section-header">
<h3 className="section-title">
<ConditionalWrapper condition={sectionTitleURL} wrap={this.wrapSectionHeader(sectionTitleURL)}>
<span className="icon icon-small-spacer" style={{backgroundImage: `url("${sectionTitleIcon}")`}} />
<span className="section-title-text">{props.content.section_title_text}</span>
</ConditionalWrapper>
</h3>
</div>
);
}
return null;
}
render() {
const {props} = this;
const sectionHeader = this.renderSectionHeader();
let className = "SimpleSnippet";
if (props.className) {
className += ` ${props.className}`;
}
if (props.content.tall) {
className += " tall";
}
if (sectionHeader) {
className += " has-section-header";
}
return (<SnippetBase {...props} className={className} textStyle={this.props.textStyle}>
<img src={safeURI(props.content.icon) || DEFAULT_ICON_PATH} className="icon" />
<div>
{this.renderTitle()} <p className="body">{this.renderText()}</p>
{this.props.extraContent}
</div>
{<div>{this.renderButton()}</div>}
{sectionHeader}
<ConditionalWrapper condition={sectionHeader} wrap={this.wrapSnippetContent}>
<img src={safeURI(props.content.icon) || DEFAULT_ICON_PATH} className="icon" />
<div>
{this.renderTitle()} <p className="body">{this.renderText()}</p>
{this.props.extraContent}
</div>
{<div>{this.renderButton()}</div>}
</ConditionalWrapper>
</SnippetBase>);
}
}

Просмотреть файл

@ -97,6 +97,20 @@
"description": "Additional parameters for link action, example which specific menu the button should open"
}
}
},
"section_title_icon": {
"type": "string",
"description": "Section title icon. 16x16px. SVG or PNG preferred. section_title_text must also be specified to display."
},
"section_title_text": {
"type": "string",
"description": "Section title text. section_title_icon must also be specified to display."
},
"section_title_url": {
"allOf": [
{"$ref": "#/definitions/link_url"},
{"description": "A url, section_title_text links to this"}
]
}
},
"additionalProperties": false,
@ -105,6 +119,7 @@
"button_action": ["button_label"],
"button_url": ["button_label"],
"button_color": ["button_label"],
"button_background_color": ["button_label"]
"button_background_color": ["button_label"],
"section_title_url": ["section_title_text"]
}
}

Просмотреть файл

@ -1,3 +1,6 @@
$section-header-height: 30px;
$icon-width: 54px; // width of primary icon + margin
.SimpleSnippet {
&.tall {
padding: 27px 0;
@ -88,4 +91,45 @@
.icon {
align-self: flex-start;
}
&.has-section-header .innerWrapper {
// account for section header being 100% width
flex-wrap: wrap;
padding-top: 7px;
}
// wrapper div added if section-header is displayed that allows icon/text/button
// to squish instead of wrapping. this is effectively replicating layout behavior
// when section-header is *not* present.
.innerContentWrapper {
align-items: center;
display: flex;
}
.section-header {
flex: 0 0 100%;
margin-bottom: 10px;
}
.section-title {
// color should match that of 'Recommended by Pocket' and 'Highlights' in newtab page
color: var(--newtab-section-header-text-color);
display: inline-block;
font-size: 13px;
font-weight: bold;
margin: 0;
a {
color: var(--newtab-section-header-text-color);
font-weight: inherit;
text-decoration: none;
}
.icon {
height: 16px;
margin-inline-end: 6px;
margin-top: -2px;
width: 16px;
}
}
}

Просмотреть файл

@ -92,7 +92,7 @@
background: $yellow-50;
padding: 2px 5px;
[lwt-newtab-brighttext] & {
[lwt-newtab-brighttext]:not(.force-light-theme) & {
color: $black;
}
}

Просмотреть файл

@ -136,6 +136,15 @@ export class BaseContent extends React.PureComponent {
this.props.dispatch(ac.UserEvent({event: "OPEN_NEWTAB_PREFS"}));
}
disableDarkTheme() {
// Dark themes are not supported in discovery stream view
// Add force-light-theme class to body tag to disable dark mode. See Bug 1519764
const bodyClassNames = global.document.body.classList;
if (!bodyClassNames.contains("force-light-theme")) {
bodyClassNames.add("force-light-theme");
}
}
render() {
const {props} = this;
const {App} = props;
@ -147,6 +156,10 @@ export class BaseContent extends React.PureComponent {
const isDiscoveryStream = props.DiscoveryStream.config && props.DiscoveryStream.config.enabled;
const searchHandoffEnabled = prefs["improvesearch.handoffToAwesomebar"];
if (isDiscoveryStream) {
this.disableDarkTheme();
}
const outerClassName = [
"outer-wrapper",
shouldBeFixedToTop && "fixed-to-top",
@ -171,7 +184,10 @@ export class BaseContent extends React.PureComponent {
<ManualMigration />
</div>
}
{isDiscoveryStream ? <DiscoveryStreamBase /> : <Sections />}
{isDiscoveryStream ? (
<ErrorBoundary className="borderless-error">
<DiscoveryStreamBase />
</ErrorBoundary>) : <Sections />}
<PrefsButton onClick={this.openPreferences} />
</div>
<ConfirmDialog />

Просмотреть файл

@ -19,6 +19,11 @@
}
}
.force-light-theme {
--newtab-background-color: #{$grey-10} !important; // sass-lint:disable-line no-important
--newtab-text-primary-color: #{$grey-90} !important; // sass-lint:disable-line no-important
}
main {
margin: auto;
// Offset the snippets container so things at the bottom of the page are still

Просмотреть файл

@ -71,7 +71,7 @@
overflow: hidden;
position: relative;
[lwt-newtab-brighttext] & {
[lwt-newtab-brighttext]:not(.force-light-theme) & {
background-color: $grey-60;
}

Просмотреть файл

@ -113,7 +113,7 @@ export class _DiscoveryStreamBase extends React.PureComponent {
});
}
renderComponent(component) {
renderComponent(component, embedWidth) {
let rows;
const {spocs} = this.props.DiscoveryStream;
@ -157,6 +157,8 @@ export class _DiscoveryStreamBase extends React.PureComponent {
return (
<ImpressionStats rows={rows} dispatch={this.props.dispatch} source={component.type}>
<Hero
subComponentType={embedWidth >= 9 ? `cards` : `list`}
feed={component.feed}
title={component.header && component.header.title}
data={component.data}
border={component.properties.border}
@ -173,6 +175,8 @@ export class _DiscoveryStreamBase extends React.PureComponent {
<ImpressionStats rows={rows} dispatch={this.props.dispatch} source={component.type}>
<List
feed={component.feed}
fullWidth={component.properties.full_width}
hasBorders={component.properties.border === "border"}
hasImages={component.properties.has_images}
hasNumbers={component.properties.has_numbers}
items={component.properties.items}
@ -203,7 +207,7 @@ export class _DiscoveryStreamBase extends React.PureComponent {
{row.components.map((component, componentIndex) => {
styles[rowIndex] = [...styles[rowIndex] || [], component.styles];
return (<div key={`component-${componentIndex}`}>
{this.renderComponent(component)}
{this.renderComponent(component, row.width)}
</div>);
})}
</div>

Просмотреть файл

@ -31,7 +31,7 @@ export class DSCard extends React.PureComponent {
</div>
<div className="meta">
<header className="title">{this.props.title}</header>
<p className="excerpt">{this.props.excerpt}</p>
{this.props.excerpt && <p className="excerpt">{this.props.excerpt}</p>}
{this.props.context ? (
<p className="context">{this.props.context}</p>
) : (

Просмотреть файл

@ -1,6 +1,8 @@
import {actionCreators as ac} from "common/Actions.jsm";
import {DSCard} from "../DSCard/DSCard.jsx";
import {List} from "../List/List.jsx";
import React from "react";
import {truncateText} from "content-src/lib/truncate-text";
export class Hero extends React.PureComponent {
constructor(props) {
@ -36,7 +38,6 @@ export class Hero extends React.PureComponent {
let [heroRec, ...otherRecs] = data.recommendations.slice(0, this.props.items);
this.heroRec = heroRec;
let truncateText = (text, cap) => `${text.substring(0, cap)}${text.length > cap ? `...` : ``}`;
// Note that `{index + 1}` is necessary below for telemetry since we treat heroRec as index 0.
let cards = otherRecs.map((rec, index) => (
@ -49,10 +50,20 @@ export class Hero extends React.PureComponent {
index={index + 1}
type={this.props.type}
dispatch={this.props.dispatch}
context={truncateText(rec.context || "", 22)}
source={truncateText(`TODO: SOURCE`, 22)} />
context={truncateText(rec.context, 22)}
source={truncateText(rec.domain, 22)} />
));
let list = (
<List
recStartingPoint={1}
feed={this.props.feed}
hasImages={true}
hasBorders={this.props.border === `border`}
items={this.props.items}
type={`Hero`} />
);
return (
<div>
<div className="ds-header">{this.props.title}</div>
@ -67,12 +78,12 @@ export class Hero extends React.PureComponent {
{heroRec.context ? (
<p className="context">{truncateText(heroRec.context, 22)}</p>
) : (
<p>{truncateText(`TODO: SOURCE`, 22)}</p>
<p>{truncateText(heroRec.domain, 22)}</p>
)}
</div>
</a>
<div className="cards">
{ cards }
<div className={`${this.props.subComponentType}`}>
{ this.props.subComponentType === `cards` ? cards : list }
</div>
</div>
</div>

Просмотреть файл

@ -1,8 +1,24 @@
$card-header-in-hero-font-size: 13;
$card-header-in-hero-line-height: 20;
.ds-hero {
.img {
@include image-as-background;
}
header {
font-weight: 600;
}
p {
line-height: 1.538;
}
.ds-list {
border-top: 0;
padding-top: 0;
}
.ds-card {
border: 0;
@ -14,6 +30,17 @@
.meta {
padding: 0;
.title {
// show only 2 lines of copy
@include limit-visibile-lines(2, $card-header-in-hero-line-height, $card-header-in-hero-font-size);
font-size: $card-header-in-hero-font-size * 1px;
line-height: $card-header-in-hero-line-height * 1px;
}
}
.img-wrapper {
margin: 0 0 12px;
}
}
@ -29,6 +56,11 @@
border-top: $border-secondary;
border-bottom: $border-secondary;
@at-root .ds-hero-no-border .wrapper {
border-top: 0;
border-bottom: 0;
}
&:hover .meta header {
color: $blue-60;
}
@ -72,6 +104,17 @@
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 24px;
.img-wrapper {
margin: 0;
grid-column: 2;
grid-row: 1;
}
.meta {
grid-column: 1;
grid-row: 1;
}
.img {
height: 0;
padding-top: 100%; // 1:1 aspect ratio
@ -97,6 +140,7 @@
.img-wrapper {
width: 67%;
margin: 0;
}
.img {
@ -114,6 +158,7 @@
p {
font-size: 15px;
line-height: 1.6;
}
}
}

Просмотреть файл

@ -1,6 +1,7 @@
import {actionCreators as ac} from "common/Actions.jsm";
import {connect} from "react-redux";
import React from "react";
import {truncateText} from "content-src/lib/truncate-text";
/**
* @note exported for testing only
@ -39,6 +40,7 @@ export class ListItem extends React.PureComponent {
{this.props.title}
</b>
</div>
{this.props.excerpt && <div className="ds-list-item-excerpt">{truncateText(this.props.excerpt, 90)}</div>}
<div className="ds-list-item-info">{this.props.domain}</div>
</div>
<div className="ds-list-image" style={{backgroundImage: `url(${this.props.image_src})`}} />
@ -60,25 +62,29 @@ export function _List(props) {
const recs = feed.data.recommendations;
let recMarkup = recs.slice(0, props.items).map((rec, index) => (
let recMarkup = recs.slice(props.recStartingPoint, props.items).map((rec, index) => (
<ListItem {...rec} key={`ds-list-item-${index}`} index={index} type={props.type} dispatch={props.dispatch} />)
);
const listStyles = [
"ds-list",
props.fullWidth ? "ds-list-full-width" : "",
props.hasBorders ? "ds-list-borders" : "",
props.hasImages ? "ds-list-images" : "",
props.hasNumbers ? "ds-list-numbers" : "",
];
return (
<div>
{props.header && props.header.title ? <div className="ds-header">{props.header.title}</div> : null }
<hr className="ds-list-border" />
<ul className={listStyles.join(" ")}>{recMarkup}</ul>
</div>
);
}
_List.defaultProps = {
recStartingPoint: 0, // Index of recommendations to start displaying from
fullWidth: false, // Display items taking up the whole column
hasBorders: false, // Display lines separating each item
hasImages: false, // Display images for each item
hasNumbers: false, // Display numbers for each item
items: 6, // Number of stories to display. TODO: get from endpoint

Просмотреть файл

@ -1,17 +1,44 @@
// Type sizes
$item-font-size: 13;
$item-image-size: 72px;
$item-line-height: 20;
.ds-list-border {
border: 0;
border-top: $border-secondary;
// XXX this is gross, and attaches the bottom-border to the item above.
// Ideally, we'd attach the top-border to the item that needs it.
// Unfortunately the border needs to go _above_ the row gap as currently
// set up, which means that some refactoring will be required to do this.
@mixin bottom-border-except-last-grid-row($columns) {
.ds-list-item:not(:nth-last-child(-n+#{$columns})) {
border-bottom: $border-secondary;
margin-bottom: -1px; // cancel out the pixel we used for the border
padding-top: 1px;
padding-bottom: 2px;
}
}
// Instead of using margin, we need to use these to override stuff that comes
// by default from <hr>.
margin-block-start: 8px;
margin-block-end: 8px;
@mixin set-item-sizes($font-size, $line-height, $image-size) {
.ds-list-item {
// XXX see if we really want absolute units, maybe hoist somewhere central?
font-size: $font-size * 1px;
line-height: $line-height * 1px;
}
.ds-list-item-excerpt {
@include limit-visibile-lines(2, $line-height, $font-size);
}
.ds-list-item-info {
@include limit-visibile-lines(1, $line-height, $font-size);
}
.ds-list-item-title {
@include limit-visibile-lines(2, $line-height, $font-size);
}
.ds-list-image {
min-width: $image-size;
width: $image-size;
}
}
.ds-list {
@ -23,22 +50,35 @@ $item-line-height: 20;
// regression detection?
padding-inline-start: 0;
// "2/3 width layout"
.ds-column-5 &,
.ds-column-6 &,
.ds-column-7 &,
.ds-column-8 & {
grid-template-columns: repeat(2, 1fr);
grid-row-gap: 24px;
&:not(.ds-list-full-width) {
@include set-item-sizes($item-font-size, $item-line-height, $item-image-size);
// "2/3 width layout"
.ds-column-5 &,
.ds-column-6 &,
.ds-column-7 &,
.ds-column-8 & {
grid-template-columns: repeat(2, 1fr);
}
// "Full width layout"
.ds-column-9 &,
.ds-column-10 &,
.ds-column-11 &,
.ds-column-12 & {
grid-template-columns: repeat(3, 1fr);
grid-row-gap: 18px;
}
.ds-list-item-excerpt {
display: none;
}
}
// "Full width layout"
.ds-column-9 &,
.ds-column-10 &,
.ds-column-11 &,
.ds-column-12 & {
grid-template-columns: repeat(3, 1fr);
grid-row-gap: 18px;
&:not(.ds-list-images) {
.ds-list-image {
display: none;
}
}
a {
@ -47,12 +87,6 @@ $item-line-height: 20;
}
}
.ds-list-images {
.ds-list-item .ds-list-image {
display: block;
}
}
.ds-list-numbers {
$counter-whitespace: ($item-line-height - $item-font-size) * 1px;
$counter-size: ($item-font-size) * 2px + $counter-whitespace;
@ -90,22 +124,42 @@ $item-line-height: 20;
}
}
// XXX this is gross, and attaches the bottom-border to the item above.
// Ideally, we'd attach the top-border to the item that needs it.
// Unfortunately the border needs to go _above_ the row gap as currently
// set up, which means that some refactoring will be required to do this.
.ds-list-item:nth-child(-n+3) { // all but the last three items
border-bottom: $border-secondary;
margin-bottom: -1px; // cancel out the pixel we used for the border
.ds-list-borders {
border-top: $border-secondary;
padding-top: $item-line-height * 1px;
padding-bottom: 2px;
&.ds-list-full-width,
.ds-column-1 &,
.ds-column-2 &,
.ds-column-3 &,
.ds-column-4 & {
@include bottom-border-except-last-grid-row(1);
}
&:not(.ds-list-full-width) {
// "2/3 width layout"
.ds-column-5 &,
.ds-column-6 &,
.ds-column-7 &,
.ds-column-8 & {
@include bottom-border-except-last-grid-row(2);
}
// "Full width layout"
.ds-column-9 &,
.ds-column-10 &,
.ds-column-11 &,
.ds-column-12 & {
@include bottom-border-except-last-grid-row(3);
}
}
}
.ds-list-full-width {
@include set-item-sizes(17, 24, $item-image-size * 2);
}
.ds-list-item {
// XXX see if we really want absolute units, maybe hoist somewhere central?
line-height: $item-line-height * 1px;
font-size: $item-font-size * 1px;
// reset some stuff from <li>. Should maybe be hoisted when we have better
// regression detection?
display: block;
@ -120,18 +174,17 @@ $item-line-height: 20;
justify-content: space-between;
}
.ds-list-item-excerpt {
color: var(--newtab-text-secondary-color);
margin-bottom: 8px;
}
.ds-list-item-info {
@include limit-visibile-lines(1, $item-line-height, $item-font-size);
color: $grey-50;
overflow: hidden;
color: var(--newtab-text-secondary-color);
text-overflow: ellipsis;
}
.ds-list-item-title {
@include limit-visibile-lines(2, $item-line-height, $item-font-size);
margin-bottom: 8px;
}
@ -141,15 +194,10 @@ $item-line-height: 20;
}
.ds-list-image {
$image-size: 72px;
@include image-as-background;
display: none;
height: $image-size;
height: $item-image-size;
margin-inline-start: $item-font-size * 1px;
min-height: $image-size;
min-width: $image-size;
width: $image-size;
min-height: $item-image-size;
}
&:hover {

Просмотреть файл

@ -10,6 +10,10 @@
justify-items: center;
line-height: $error-fallback-line-height;
&.borderless-error {
box-shadow: none;
}
a {
color: var(--newtab-text-conditional-color);
text-decoration: underline;

Просмотреть файл

@ -146,7 +146,7 @@ export class _Search extends React.PureComponent {
tabIndex="-1"
title={this.props.intl.formatMessage({id: "search_web_placeholder"})}>
<div className="fake-textbox">{this.props.intl.formatMessage({id: "search_web_placeholder"})}</div>
<div className="fake-editable" tabIndex="-1" aria-hidden="true" contentEditable="" onDrop={this.onSearchHandoffDrop} onPaste={this.onSearchHandoffPaste} />
<input type="search" className="fake-editable" tabIndex="-1" aria-hidden="true" onDrop={this.onSearchHandoffDrop} onPaste={this.onSearchHandoffPaste} />
<div className="fake-caret" />
</button>
{/*

Просмотреть файл

@ -181,6 +181,8 @@ $glyph-forward: url('chrome://browser/skin/forward.svg');
.fake-editable {
color: transparent;
height: 100%;
opacity: 0;
position: absolute;
top: 0;
left: 0;

Просмотреть файл

@ -0,0 +1,3 @@
export function truncateText(text = "", cap) {
return text.substring(0, cap).trim() + (text.length > cap ? "…" : "");
}

Просмотреть файл

@ -78,7 +78,7 @@ body {
--newtab-snippets-background-color: #{$white};
--newtab-snippets-hairline-color: transparent;
&[lwt-newtab-brighttext] {
&[lwt-newtab-brighttext]:not(.force-light-theme) {
// General styles
--newtab-background-color: #{$grey-80};
--newtab-border-primary-color: #{$grey-10-80};

Просмотреть файл

@ -4,7 +4,7 @@ $os-infopanel-arrow-height: 10px;
$os-infopanel-arrow-offset-end: 7px;
$os-infopanel-arrow-width: 18px;
[lwt-newtab-brighttext] {
[lwt-newtab-brighttext]:not(.force-light-theme) {
-moz-osx-font-smoothing: grayscale;
}

Просмотреть файл

@ -68,7 +68,7 @@ body {
--newtab-card-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
--newtab-snippets-background-color: #FFF;
--newtab-snippets-hairline-color: transparent; }
body[lwt-newtab-brighttext] {
body[lwt-newtab-brighttext]:not(.force-light-theme) {
--newtab-background-color: #2A2A2E;
--newtab-border-primary-color: rgba(249, 249, 250, 0.8);
--newtab-border-secondary-color: rgba(249, 249, 250, 0.1);
@ -336,6 +336,10 @@ input[type='text'], input[type='search'] {
.outer-wrapper a {
color: var(--newtab-link-primary-color); }
.force-light-theme {
--newtab-background-color: #F9F9FA !important;
--newtab-text-primary-color: #0C0C0D !important; }
main {
margin: auto;
padding-bottom: 68px;
@ -399,6 +403,8 @@ main {
justify-content: center;
justify-items: center;
line-height: 1.5; }
.as-error-fallback.borderless-error {
box-shadow: none; }
.as-error-fallback a {
color: var(--newtab-text-conditional-color);
text-decoration: underline; }
@ -1081,6 +1087,8 @@ main {
caret-color: transparent; }
.search-handoff-button .fake-editable {
color: transparent;
height: 100%;
opacity: 0;
position: absolute;
top: 0;
left: 0;
@ -1343,7 +1351,7 @@ main {
height: 122px;
overflow: hidden;
position: relative; }
[lwt-newtab-brighttext] .card-outer .card-preview-image-outer {
[lwt-newtab-brighttext]:not(.force-light-theme) .card-outer .card-preview-image-outer {
background-color: #4A4A4F; }
.card-outer .card-preview-image-outer::after {
border-bottom: 1px solid var(--newtab-card-hairline-color);
@ -1682,7 +1690,7 @@ main {
.asrouter-admin .message-item.current .message-id span {
background: #FFE900;
padding: 2px 5px; }
[lwt-newtab-brighttext] .asrouter-admin .message-item.current .message-id span {
[lwt-newtab-brighttext]:not(.force-light-theme) .asrouter-admin .message-item.current .message-id span {
color: #000; }
.asrouter-admin .message-item.blocked .message-id,
.asrouter-admin .message-item.blocked .message-summary {
@ -1855,6 +1863,16 @@ main {
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box; }
.ds-hero header {
font-weight: 600; }
.ds-hero p {
line-height: 1.538; }
.ds-hero .ds-list {
border-top: 0;
padding-top: 0; }
.ds-hero .ds-card {
border: 0; }
.ds-hero .ds-card:hover {
@ -1863,6 +1881,13 @@ main {
border-radius: 0; }
.ds-hero .ds-card .meta {
padding: 0; }
.ds-hero .ds-card .meta .title {
max-height: 3.07692em;
overflow: hidden;
font-size: 13px;
line-height: 20px; }
.ds-hero .ds-card .img-wrapper {
margin: 0 0 12px; }
.ds-hero .img-wrapper {
margin: 0 0 12px; }
@ -1873,6 +1898,9 @@ main {
padding: 20px 0;
border-top: 1px solid var(--newtab-border-secondary-color);
border-bottom: 1px solid var(--newtab-border-secondary-color); }
.ds-hero-no-border .wrapper {
border-top: 0;
border-bottom: 0; }
.ds-hero .wrapper:hover .meta header {
color: #0060DF; }
.ds-hero .wrapper:active .meta header {
@ -1897,6 +1925,19 @@ main {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 24px; }
.ds-column-5 .ds-hero .wrapper .img-wrapper,
.ds-column-6 .ds-hero .wrapper .img-wrapper,
.ds-column-7 .ds-hero .wrapper .img-wrapper,
.ds-column-8 .ds-hero .wrapper .img-wrapper {
margin: 0;
grid-column: 2;
grid-row: 1; }
.ds-column-5 .ds-hero .wrapper .meta,
.ds-column-6 .ds-hero .wrapper .meta,
.ds-column-7 .ds-hero .wrapper .meta,
.ds-column-8 .ds-hero .wrapper .meta {
grid-column: 1;
grid-row: 1; }
.ds-column-5 .ds-hero .wrapper .img,
.ds-column-6 .ds-hero .wrapper .img,
.ds-column-7 .ds-hero .wrapper .img,
@ -1923,7 +1964,8 @@ main {
.ds-column-10 .ds-hero .wrapper .img-wrapper,
.ds-column-11 .ds-hero .wrapper .img-wrapper,
.ds-column-12 .ds-hero .wrapper .img-wrapper {
width: 67%; }
width: 67%;
margin: 0; }
.ds-column-9 .ds-hero .wrapper .img,
.ds-column-10 .ds-hero .wrapper .img,
.ds-column-11 .ds-hero .wrapper .img,
@ -1945,7 +1987,8 @@ main {
.ds-column-10 .ds-hero .wrapper .meta p,
.ds-column-11 .ds-hero .wrapper .meta p,
.ds-column-12 .ds-hero .wrapper .meta p {
font-size: 15px; }
font-size: 15px;
line-height: 1.6; }
.ds-column-9 .ds-hero .cards,
.ds-column-10 .ds-hero .cards,
@ -1960,36 +2003,44 @@ main {
height: 0;
border-top: 1px solid var(--newtab-border-secondary-color); }
.ds-list-border {
border: 0;
border-top: 1px solid var(--newtab-border-secondary-color);
padding-top: 1px;
margin-block-start: 8px;
margin-block-end: 8px; }
.ds-list {
display: grid;
grid-row-gap: 24px;
grid-column-gap: 24px;
padding-inline-start: 0; }
.ds-column-5 .ds-list,
.ds-column-6 .ds-list,
.ds-column-7 .ds-list,
.ds-column-8 .ds-list {
grid-template-columns: repeat(2, 1fr);
grid-row-gap: 24px; }
.ds-column-9 .ds-list,
.ds-column-10 .ds-list,
.ds-column-11 .ds-list,
.ds-column-12 .ds-list {
.ds-list:not(.ds-list-full-width) .ds-list-item {
font-size: 13px;
line-height: 20px; }
.ds-list:not(.ds-list-full-width) .ds-list-item-excerpt {
max-height: 3.07692em;
overflow: hidden; }
.ds-list:not(.ds-list-full-width) .ds-list-item-info {
max-height: 1.53846em;
overflow: hidden; }
.ds-list:not(.ds-list-full-width) .ds-list-item-title {
max-height: 3.07692em;
overflow: hidden; }
.ds-list:not(.ds-list-full-width) .ds-list-image {
min-width: 72px;
width: 72px; }
.ds-column-5 .ds-list:not(.ds-list-full-width),
.ds-column-6 .ds-list:not(.ds-list-full-width),
.ds-column-7 .ds-list:not(.ds-list-full-width),
.ds-column-8 .ds-list:not(.ds-list-full-width) {
grid-template-columns: repeat(2, 1fr); }
.ds-column-9 .ds-list:not(.ds-list-full-width),
.ds-column-10 .ds-list:not(.ds-list-full-width),
.ds-column-11 .ds-list:not(.ds-list-full-width),
.ds-column-12 .ds-list:not(.ds-list-full-width) {
grid-template-columns: repeat(3, 1fr);
grid-row-gap: 18px; }
.ds-list:not(.ds-list-full-width) .ds-list-item-excerpt {
display: none; }
.ds-list:not(.ds-list-images) .ds-list-image {
display: none; }
.ds-list a {
color: #0C0C0D; }
.ds-list-images .ds-list-item .ds-list-image {
display: block; }
.ds-list-numbers .ds-list-item {
counter-increment: list; }
@ -2013,14 +2064,53 @@ main {
.ds-list-numbers .ds-list-item-link:active::before {
background-color: #003EAA; }
.ds-list-item:nth-child(-n+3) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-list-borders {
border-top: 1px solid var(--newtab-border-secondary-color);
padding-top: 20px; }
.ds-list-borders.ds-list-full-width .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-1 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-2 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-3 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-4 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-column-5 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)),
.ds-column-6 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)),
.ds-column-7 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)),
.ds-column-8 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-column-9 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)),
.ds-column-10 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)),
.ds-column-11 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)),
.ds-column-12 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-list-full-width .ds-list-item {
font-size: 17px;
line-height: 24px; }
.ds-list-full-width .ds-list-item-excerpt {
max-height: 2.82353em;
overflow: hidden; }
.ds-list-full-width .ds-list-item-info {
max-height: 1.41176em;
overflow: hidden; }
.ds-list-full-width .ds-list-item-title {
max-height: 2.82353em;
overflow: hidden; }
.ds-list-full-width .ds-list-image {
min-width: 144px;
width: 144px; }
.ds-list-item {
line-height: 20px;
font-size: 13px;
display: block;
text-align: start; }
.ds-list-item .ds-list-item-link {
@ -2028,15 +2118,13 @@ main {
padding-bottom: 16px;
display: flex;
justify-content: space-between; }
.ds-list-item .ds-list-item-excerpt {
color: var(--newtab-text-secondary-color);
margin-bottom: 8px; }
.ds-list-item .ds-list-item-info {
max-height: 1.53846em;
overflow: hidden;
color: #737373;
overflow: hidden;
color: var(--newtab-text-secondary-color);
text-overflow: ellipsis; }
.ds-list-item .ds-list-item-title {
max-height: 3.07692em;
overflow: hidden;
margin-bottom: 8px; }
.ds-list-item .ds-list-item-text {
display: flex;
@ -2049,12 +2137,9 @@ main {
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
display: none;
height: 72px;
margin-inline-start: 13px;
min-height: 72px;
min-width: 72px;
width: 72px; }
min-height: 72px; }
.ds-list-item:hover .ds-list-item-title {
color: var(--newtab-link-primary-color); }
.ds-list-item:active .ds-list-item-title {
@ -2241,18 +2326,18 @@ main {
.ASRouterButton.secondary:active {
background-color: rgba(12, 12, 13, 0.3); }
[lwt-newtab-brighttext] .secondary {
[lwt-newtab-brighttext]:not(.force-light-theme) .secondary {
background-color: rgba(249, 249, 250, 0.1); }
[lwt-newtab-brighttext] .secondary:hover {
[lwt-newtab-brighttext]:not(.force-light-theme) .secondary:hover {
background-color: rgba(249, 249, 250, 0.2); }
[lwt-newtab-brighttext] .secondary:active {
[lwt-newtab-brighttext]:not(.force-light-theme) .secondary:active {
background-color: rgba(249, 249, 250, 0.3); }
[lwt-newtab-brighttext] .footer .secondary {
[lwt-newtab-brighttext]:not(.force-light-theme) .footer .secondary {
background-color: rgba(249, 249, 250, 0.3); }
[lwt-newtab-brighttext] .footer .secondary:hover {
[lwt-newtab-brighttext]:not(.force-light-theme) .footer .secondary:hover {
background-color: rgba(249, 249, 250, 0.4); }
[lwt-newtab-brighttext] .footer .secondary:active {
[lwt-newtab-brighttext]:not(.force-light-theme) .footer .secondary:active {
background-color: rgba(249, 249, 250, 0.5); }
.SnippetBaseContainer {
@ -2274,7 +2359,7 @@ main {
color: var(--newtab-link-primary-color); }
.SnippetBaseContainer a:hover {
text-decoration: underline; }
[lwt-newtab-brighttext] .SnippetBaseContainer a {
[lwt-newtab-brighttext]:not(.force-light-theme) .SnippetBaseContainer a {
font-weight: bold; }
.SnippetBaseContainer input[type='checkbox'] {
margin-inline-start: 0; }
@ -2581,6 +2666,34 @@ main {
.SimpleSnippet .icon {
align-self: flex-start; }
.SimpleSnippet.has-section-header .innerWrapper {
flex-wrap: wrap;
padding-top: 7px; }
.SimpleSnippet .innerContentWrapper {
align-items: center;
display: flex; }
.SimpleSnippet .section-header {
flex: 0 0 100%;
margin-bottom: 10px; }
.SimpleSnippet .section-title {
color: var(--newtab-section-header-text-color);
display: inline-block;
font-size: 13px;
font-weight: bold;
margin: 0; }
.SimpleSnippet .section-title a {
color: var(--newtab-section-header-text-color);
font-weight: inherit;
text-decoration: none; }
.SimpleSnippet .section-title .icon {
height: 16px;
margin-inline-end: 6px;
margin-top: -2px;
width: 16px; }
.SubmitFormSnippet {
flex-direction: column;
flex: 1 1 100%;

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1,6 +1,6 @@
@charset "UTF-8";
/* This is the mac variant */
[lwt-newtab-brighttext] {
[lwt-newtab-brighttext]:not(.force-light-theme) {
-moz-osx-font-smoothing: grayscale; }
html {
@ -71,7 +71,7 @@ body {
--newtab-card-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
--newtab-snippets-background-color: #FFF;
--newtab-snippets-hairline-color: transparent; }
body[lwt-newtab-brighttext] {
body[lwt-newtab-brighttext]:not(.force-light-theme) {
--newtab-background-color: #2A2A2E;
--newtab-border-primary-color: rgba(249, 249, 250, 0.8);
--newtab-border-secondary-color: rgba(249, 249, 250, 0.1);
@ -339,6 +339,10 @@ input[type='text'], input[type='search'] {
.outer-wrapper a {
color: var(--newtab-link-primary-color); }
.force-light-theme {
--newtab-background-color: #F9F9FA !important;
--newtab-text-primary-color: #0C0C0D !important; }
main {
margin: auto;
padding-bottom: 68px;
@ -402,6 +406,8 @@ main {
justify-content: center;
justify-items: center;
line-height: 1.5; }
.as-error-fallback.borderless-error {
box-shadow: none; }
.as-error-fallback a {
color: var(--newtab-text-conditional-color);
text-decoration: underline; }
@ -1084,6 +1090,8 @@ main {
caret-color: transparent; }
.search-handoff-button .fake-editable {
color: transparent;
height: 100%;
opacity: 0;
position: absolute;
top: 0;
left: 0;
@ -1346,7 +1354,7 @@ main {
height: 122px;
overflow: hidden;
position: relative; }
[lwt-newtab-brighttext] .card-outer .card-preview-image-outer {
[lwt-newtab-brighttext]:not(.force-light-theme) .card-outer .card-preview-image-outer {
background-color: #4A4A4F; }
.card-outer .card-preview-image-outer::after {
border-bottom: 1px solid var(--newtab-card-hairline-color);
@ -1685,7 +1693,7 @@ main {
.asrouter-admin .message-item.current .message-id span {
background: #FFE900;
padding: 2px 5px; }
[lwt-newtab-brighttext] .asrouter-admin .message-item.current .message-id span {
[lwt-newtab-brighttext]:not(.force-light-theme) .asrouter-admin .message-item.current .message-id span {
color: #000; }
.asrouter-admin .message-item.blocked .message-id,
.asrouter-admin .message-item.blocked .message-summary {
@ -1858,6 +1866,16 @@ main {
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box; }
.ds-hero header {
font-weight: 600; }
.ds-hero p {
line-height: 1.538; }
.ds-hero .ds-list {
border-top: 0;
padding-top: 0; }
.ds-hero .ds-card {
border: 0; }
.ds-hero .ds-card:hover {
@ -1866,6 +1884,13 @@ main {
border-radius: 0; }
.ds-hero .ds-card .meta {
padding: 0; }
.ds-hero .ds-card .meta .title {
max-height: 3.07692em;
overflow: hidden;
font-size: 13px;
line-height: 20px; }
.ds-hero .ds-card .img-wrapper {
margin: 0 0 12px; }
.ds-hero .img-wrapper {
margin: 0 0 12px; }
@ -1876,6 +1901,9 @@ main {
padding: 20px 0;
border-top: 1px solid var(--newtab-border-secondary-color);
border-bottom: 1px solid var(--newtab-border-secondary-color); }
.ds-hero-no-border .wrapper {
border-top: 0;
border-bottom: 0; }
.ds-hero .wrapper:hover .meta header {
color: #0060DF; }
.ds-hero .wrapper:active .meta header {
@ -1900,6 +1928,19 @@ main {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 24px; }
.ds-column-5 .ds-hero .wrapper .img-wrapper,
.ds-column-6 .ds-hero .wrapper .img-wrapper,
.ds-column-7 .ds-hero .wrapper .img-wrapper,
.ds-column-8 .ds-hero .wrapper .img-wrapper {
margin: 0;
grid-column: 2;
grid-row: 1; }
.ds-column-5 .ds-hero .wrapper .meta,
.ds-column-6 .ds-hero .wrapper .meta,
.ds-column-7 .ds-hero .wrapper .meta,
.ds-column-8 .ds-hero .wrapper .meta {
grid-column: 1;
grid-row: 1; }
.ds-column-5 .ds-hero .wrapper .img,
.ds-column-6 .ds-hero .wrapper .img,
.ds-column-7 .ds-hero .wrapper .img,
@ -1926,7 +1967,8 @@ main {
.ds-column-10 .ds-hero .wrapper .img-wrapper,
.ds-column-11 .ds-hero .wrapper .img-wrapper,
.ds-column-12 .ds-hero .wrapper .img-wrapper {
width: 67%; }
width: 67%;
margin: 0; }
.ds-column-9 .ds-hero .wrapper .img,
.ds-column-10 .ds-hero .wrapper .img,
.ds-column-11 .ds-hero .wrapper .img,
@ -1948,7 +1990,8 @@ main {
.ds-column-10 .ds-hero .wrapper .meta p,
.ds-column-11 .ds-hero .wrapper .meta p,
.ds-column-12 .ds-hero .wrapper .meta p {
font-size: 15px; }
font-size: 15px;
line-height: 1.6; }
.ds-column-9 .ds-hero .cards,
.ds-column-10 .ds-hero .cards,
@ -1963,36 +2006,44 @@ main {
height: 0;
border-top: 1px solid var(--newtab-border-secondary-color); }
.ds-list-border {
border: 0;
border-top: 1px solid var(--newtab-border-secondary-color);
padding-top: 1px;
margin-block-start: 8px;
margin-block-end: 8px; }
.ds-list {
display: grid;
grid-row-gap: 24px;
grid-column-gap: 24px;
padding-inline-start: 0; }
.ds-column-5 .ds-list,
.ds-column-6 .ds-list,
.ds-column-7 .ds-list,
.ds-column-8 .ds-list {
grid-template-columns: repeat(2, 1fr);
grid-row-gap: 24px; }
.ds-column-9 .ds-list,
.ds-column-10 .ds-list,
.ds-column-11 .ds-list,
.ds-column-12 .ds-list {
.ds-list:not(.ds-list-full-width) .ds-list-item {
font-size: 13px;
line-height: 20px; }
.ds-list:not(.ds-list-full-width) .ds-list-item-excerpt {
max-height: 3.07692em;
overflow: hidden; }
.ds-list:not(.ds-list-full-width) .ds-list-item-info {
max-height: 1.53846em;
overflow: hidden; }
.ds-list:not(.ds-list-full-width) .ds-list-item-title {
max-height: 3.07692em;
overflow: hidden; }
.ds-list:not(.ds-list-full-width) .ds-list-image {
min-width: 72px;
width: 72px; }
.ds-column-5 .ds-list:not(.ds-list-full-width),
.ds-column-6 .ds-list:not(.ds-list-full-width),
.ds-column-7 .ds-list:not(.ds-list-full-width),
.ds-column-8 .ds-list:not(.ds-list-full-width) {
grid-template-columns: repeat(2, 1fr); }
.ds-column-9 .ds-list:not(.ds-list-full-width),
.ds-column-10 .ds-list:not(.ds-list-full-width),
.ds-column-11 .ds-list:not(.ds-list-full-width),
.ds-column-12 .ds-list:not(.ds-list-full-width) {
grid-template-columns: repeat(3, 1fr);
grid-row-gap: 18px; }
.ds-list:not(.ds-list-full-width) .ds-list-item-excerpt {
display: none; }
.ds-list:not(.ds-list-images) .ds-list-image {
display: none; }
.ds-list a {
color: #0C0C0D; }
.ds-list-images .ds-list-item .ds-list-image {
display: block; }
.ds-list-numbers .ds-list-item {
counter-increment: list; }
@ -2016,14 +2067,53 @@ main {
.ds-list-numbers .ds-list-item-link:active::before {
background-color: #003EAA; }
.ds-list-item:nth-child(-n+3) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-list-borders {
border-top: 1px solid var(--newtab-border-secondary-color);
padding-top: 20px; }
.ds-list-borders.ds-list-full-width .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-1 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-2 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-3 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-4 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-column-5 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)),
.ds-column-6 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)),
.ds-column-7 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)),
.ds-column-8 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-column-9 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)),
.ds-column-10 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)),
.ds-column-11 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)),
.ds-column-12 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-list-full-width .ds-list-item {
font-size: 17px;
line-height: 24px; }
.ds-list-full-width .ds-list-item-excerpt {
max-height: 2.82353em;
overflow: hidden; }
.ds-list-full-width .ds-list-item-info {
max-height: 1.41176em;
overflow: hidden; }
.ds-list-full-width .ds-list-item-title {
max-height: 2.82353em;
overflow: hidden; }
.ds-list-full-width .ds-list-image {
min-width: 144px;
width: 144px; }
.ds-list-item {
line-height: 20px;
font-size: 13px;
display: block;
text-align: start; }
.ds-list-item .ds-list-item-link {
@ -2031,15 +2121,13 @@ main {
padding-bottom: 16px;
display: flex;
justify-content: space-between; }
.ds-list-item .ds-list-item-excerpt {
color: var(--newtab-text-secondary-color);
margin-bottom: 8px; }
.ds-list-item .ds-list-item-info {
max-height: 1.53846em;
overflow: hidden;
color: #737373;
overflow: hidden;
color: var(--newtab-text-secondary-color);
text-overflow: ellipsis; }
.ds-list-item .ds-list-item-title {
max-height: 3.07692em;
overflow: hidden;
margin-bottom: 8px; }
.ds-list-item .ds-list-item-text {
display: flex;
@ -2052,12 +2140,9 @@ main {
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
display: none;
height: 72px;
margin-inline-start: 13px;
min-height: 72px;
min-width: 72px;
width: 72px; }
min-height: 72px; }
.ds-list-item:hover .ds-list-item-title {
color: var(--newtab-link-primary-color); }
.ds-list-item:active .ds-list-item-title {
@ -2244,18 +2329,18 @@ main {
.ASRouterButton.secondary:active {
background-color: rgba(12, 12, 13, 0.3); }
[lwt-newtab-brighttext] .secondary {
[lwt-newtab-brighttext]:not(.force-light-theme) .secondary {
background-color: rgba(249, 249, 250, 0.1); }
[lwt-newtab-brighttext] .secondary:hover {
[lwt-newtab-brighttext]:not(.force-light-theme) .secondary:hover {
background-color: rgba(249, 249, 250, 0.2); }
[lwt-newtab-brighttext] .secondary:active {
[lwt-newtab-brighttext]:not(.force-light-theme) .secondary:active {
background-color: rgba(249, 249, 250, 0.3); }
[lwt-newtab-brighttext] .footer .secondary {
[lwt-newtab-brighttext]:not(.force-light-theme) .footer .secondary {
background-color: rgba(249, 249, 250, 0.3); }
[lwt-newtab-brighttext] .footer .secondary:hover {
[lwt-newtab-brighttext]:not(.force-light-theme) .footer .secondary:hover {
background-color: rgba(249, 249, 250, 0.4); }
[lwt-newtab-brighttext] .footer .secondary:active {
[lwt-newtab-brighttext]:not(.force-light-theme) .footer .secondary:active {
background-color: rgba(249, 249, 250, 0.5); }
.SnippetBaseContainer {
@ -2277,7 +2362,7 @@ main {
color: var(--newtab-link-primary-color); }
.SnippetBaseContainer a:hover {
text-decoration: underline; }
[lwt-newtab-brighttext] .SnippetBaseContainer a {
[lwt-newtab-brighttext]:not(.force-light-theme) .SnippetBaseContainer a {
font-weight: bold; }
.SnippetBaseContainer input[type='checkbox'] {
margin-inline-start: 0; }
@ -2584,6 +2669,34 @@ main {
.SimpleSnippet .icon {
align-self: flex-start; }
.SimpleSnippet.has-section-header .innerWrapper {
flex-wrap: wrap;
padding-top: 7px; }
.SimpleSnippet .innerContentWrapper {
align-items: center;
display: flex; }
.SimpleSnippet .section-header {
flex: 0 0 100%;
margin-bottom: 10px; }
.SimpleSnippet .section-title {
color: var(--newtab-section-header-text-color);
display: inline-block;
font-size: 13px;
font-weight: bold;
margin: 0; }
.SimpleSnippet .section-title a {
color: var(--newtab-section-header-text-color);
font-weight: inherit;
text-decoration: none; }
.SimpleSnippet .section-title .icon {
height: 16px;
margin-inline-end: 6px;
margin-top: -2px;
width: 16px; }
.SubmitFormSnippet {
flex-direction: column;
flex: 1 1 100%;

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -68,7 +68,7 @@ body {
--newtab-card-shadow: 0 1px 4px 0 rgba(12, 12, 13, 0.1);
--newtab-snippets-background-color: #FFF;
--newtab-snippets-hairline-color: transparent; }
body[lwt-newtab-brighttext] {
body[lwt-newtab-brighttext]:not(.force-light-theme) {
--newtab-background-color: #2A2A2E;
--newtab-border-primary-color: rgba(249, 249, 250, 0.8);
--newtab-border-secondary-color: rgba(249, 249, 250, 0.1);
@ -336,6 +336,10 @@ input[type='text'], input[type='search'] {
.outer-wrapper a {
color: var(--newtab-link-primary-color); }
.force-light-theme {
--newtab-background-color: #F9F9FA !important;
--newtab-text-primary-color: #0C0C0D !important; }
main {
margin: auto;
padding-bottom: 68px;
@ -399,6 +403,8 @@ main {
justify-content: center;
justify-items: center;
line-height: 1.5; }
.as-error-fallback.borderless-error {
box-shadow: none; }
.as-error-fallback a {
color: var(--newtab-text-conditional-color);
text-decoration: underline; }
@ -1081,6 +1087,8 @@ main {
caret-color: transparent; }
.search-handoff-button .fake-editable {
color: transparent;
height: 100%;
opacity: 0;
position: absolute;
top: 0;
left: 0;
@ -1343,7 +1351,7 @@ main {
height: 122px;
overflow: hidden;
position: relative; }
[lwt-newtab-brighttext] .card-outer .card-preview-image-outer {
[lwt-newtab-brighttext]:not(.force-light-theme) .card-outer .card-preview-image-outer {
background-color: #4A4A4F; }
.card-outer .card-preview-image-outer::after {
border-bottom: 1px solid var(--newtab-card-hairline-color);
@ -1682,7 +1690,7 @@ main {
.asrouter-admin .message-item.current .message-id span {
background: #FFE900;
padding: 2px 5px; }
[lwt-newtab-brighttext] .asrouter-admin .message-item.current .message-id span {
[lwt-newtab-brighttext]:not(.force-light-theme) .asrouter-admin .message-item.current .message-id span {
color: #000; }
.asrouter-admin .message-item.blocked .message-id,
.asrouter-admin .message-item.blocked .message-summary {
@ -1855,6 +1863,16 @@ main {
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box; }
.ds-hero header {
font-weight: 600; }
.ds-hero p {
line-height: 1.538; }
.ds-hero .ds-list {
border-top: 0;
padding-top: 0; }
.ds-hero .ds-card {
border: 0; }
.ds-hero .ds-card:hover {
@ -1863,6 +1881,13 @@ main {
border-radius: 0; }
.ds-hero .ds-card .meta {
padding: 0; }
.ds-hero .ds-card .meta .title {
max-height: 3.07692em;
overflow: hidden;
font-size: 13px;
line-height: 20px; }
.ds-hero .ds-card .img-wrapper {
margin: 0 0 12px; }
.ds-hero .img-wrapper {
margin: 0 0 12px; }
@ -1873,6 +1898,9 @@ main {
padding: 20px 0;
border-top: 1px solid var(--newtab-border-secondary-color);
border-bottom: 1px solid var(--newtab-border-secondary-color); }
.ds-hero-no-border .wrapper {
border-top: 0;
border-bottom: 0; }
.ds-hero .wrapper:hover .meta header {
color: #0060DF; }
.ds-hero .wrapper:active .meta header {
@ -1897,6 +1925,19 @@ main {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-column-gap: 24px; }
.ds-column-5 .ds-hero .wrapper .img-wrapper,
.ds-column-6 .ds-hero .wrapper .img-wrapper,
.ds-column-7 .ds-hero .wrapper .img-wrapper,
.ds-column-8 .ds-hero .wrapper .img-wrapper {
margin: 0;
grid-column: 2;
grid-row: 1; }
.ds-column-5 .ds-hero .wrapper .meta,
.ds-column-6 .ds-hero .wrapper .meta,
.ds-column-7 .ds-hero .wrapper .meta,
.ds-column-8 .ds-hero .wrapper .meta {
grid-column: 1;
grid-row: 1; }
.ds-column-5 .ds-hero .wrapper .img,
.ds-column-6 .ds-hero .wrapper .img,
.ds-column-7 .ds-hero .wrapper .img,
@ -1923,7 +1964,8 @@ main {
.ds-column-10 .ds-hero .wrapper .img-wrapper,
.ds-column-11 .ds-hero .wrapper .img-wrapper,
.ds-column-12 .ds-hero .wrapper .img-wrapper {
width: 67%; }
width: 67%;
margin: 0; }
.ds-column-9 .ds-hero .wrapper .img,
.ds-column-10 .ds-hero .wrapper .img,
.ds-column-11 .ds-hero .wrapper .img,
@ -1945,7 +1987,8 @@ main {
.ds-column-10 .ds-hero .wrapper .meta p,
.ds-column-11 .ds-hero .wrapper .meta p,
.ds-column-12 .ds-hero .wrapper .meta p {
font-size: 15px; }
font-size: 15px;
line-height: 1.6; }
.ds-column-9 .ds-hero .cards,
.ds-column-10 .ds-hero .cards,
@ -1960,36 +2003,44 @@ main {
height: 0;
border-top: 1px solid var(--newtab-border-secondary-color); }
.ds-list-border {
border: 0;
border-top: 1px solid var(--newtab-border-secondary-color);
padding-top: 1px;
margin-block-start: 8px;
margin-block-end: 8px; }
.ds-list {
display: grid;
grid-row-gap: 24px;
grid-column-gap: 24px;
padding-inline-start: 0; }
.ds-column-5 .ds-list,
.ds-column-6 .ds-list,
.ds-column-7 .ds-list,
.ds-column-8 .ds-list {
grid-template-columns: repeat(2, 1fr);
grid-row-gap: 24px; }
.ds-column-9 .ds-list,
.ds-column-10 .ds-list,
.ds-column-11 .ds-list,
.ds-column-12 .ds-list {
.ds-list:not(.ds-list-full-width) .ds-list-item {
font-size: 13px;
line-height: 20px; }
.ds-list:not(.ds-list-full-width) .ds-list-item-excerpt {
max-height: 3.07692em;
overflow: hidden; }
.ds-list:not(.ds-list-full-width) .ds-list-item-info {
max-height: 1.53846em;
overflow: hidden; }
.ds-list:not(.ds-list-full-width) .ds-list-item-title {
max-height: 3.07692em;
overflow: hidden; }
.ds-list:not(.ds-list-full-width) .ds-list-image {
min-width: 72px;
width: 72px; }
.ds-column-5 .ds-list:not(.ds-list-full-width),
.ds-column-6 .ds-list:not(.ds-list-full-width),
.ds-column-7 .ds-list:not(.ds-list-full-width),
.ds-column-8 .ds-list:not(.ds-list-full-width) {
grid-template-columns: repeat(2, 1fr); }
.ds-column-9 .ds-list:not(.ds-list-full-width),
.ds-column-10 .ds-list:not(.ds-list-full-width),
.ds-column-11 .ds-list:not(.ds-list-full-width),
.ds-column-12 .ds-list:not(.ds-list-full-width) {
grid-template-columns: repeat(3, 1fr);
grid-row-gap: 18px; }
.ds-list:not(.ds-list-full-width) .ds-list-item-excerpt {
display: none; }
.ds-list:not(.ds-list-images) .ds-list-image {
display: none; }
.ds-list a {
color: #0C0C0D; }
.ds-list-images .ds-list-item .ds-list-image {
display: block; }
.ds-list-numbers .ds-list-item {
counter-increment: list; }
@ -2013,14 +2064,53 @@ main {
.ds-list-numbers .ds-list-item-link:active::before {
background-color: #003EAA; }
.ds-list-item:nth-child(-n+3) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-list-borders {
border-top: 1px solid var(--newtab-border-secondary-color);
padding-top: 20px; }
.ds-list-borders.ds-list-full-width .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-1 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-2 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-3 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)),
.ds-column-4 .ds-list-borders .ds-list-item:not(:nth-last-child(-n+1)) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-column-5 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)),
.ds-column-6 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)),
.ds-column-7 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)),
.ds-column-8 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+2)) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-column-9 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)),
.ds-column-10 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)),
.ds-column-11 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)),
.ds-column-12 .ds-list-borders:not(.ds-list-full-width) .ds-list-item:not(:nth-last-child(-n+3)) {
border-bottom: 1px solid var(--newtab-border-secondary-color);
margin-bottom: -1px;
padding-bottom: 2px; }
.ds-list-full-width .ds-list-item {
font-size: 17px;
line-height: 24px; }
.ds-list-full-width .ds-list-item-excerpt {
max-height: 2.82353em;
overflow: hidden; }
.ds-list-full-width .ds-list-item-info {
max-height: 1.41176em;
overflow: hidden; }
.ds-list-full-width .ds-list-item-title {
max-height: 2.82353em;
overflow: hidden; }
.ds-list-full-width .ds-list-image {
min-width: 144px;
width: 144px; }
.ds-list-item {
line-height: 20px;
font-size: 13px;
display: block;
text-align: start; }
.ds-list-item .ds-list-item-link {
@ -2028,15 +2118,13 @@ main {
padding-bottom: 16px;
display: flex;
justify-content: space-between; }
.ds-list-item .ds-list-item-excerpt {
color: var(--newtab-text-secondary-color);
margin-bottom: 8px; }
.ds-list-item .ds-list-item-info {
max-height: 1.53846em;
overflow: hidden;
color: #737373;
overflow: hidden;
color: var(--newtab-text-secondary-color);
text-overflow: ellipsis; }
.ds-list-item .ds-list-item-title {
max-height: 3.07692em;
overflow: hidden;
margin-bottom: 8px; }
.ds-list-item .ds-list-item-text {
display: flex;
@ -2049,12 +2137,9 @@ main {
border-radius: 4px;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
display: none;
height: 72px;
margin-inline-start: 13px;
min-height: 72px;
min-width: 72px;
width: 72px; }
min-height: 72px; }
.ds-list-item:hover .ds-list-item-title {
color: var(--newtab-link-primary-color); }
.ds-list-item:active .ds-list-item-title {
@ -2241,18 +2326,18 @@ main {
.ASRouterButton.secondary:active {
background-color: rgba(12, 12, 13, 0.3); }
[lwt-newtab-brighttext] .secondary {
[lwt-newtab-brighttext]:not(.force-light-theme) .secondary {
background-color: rgba(249, 249, 250, 0.1); }
[lwt-newtab-brighttext] .secondary:hover {
[lwt-newtab-brighttext]:not(.force-light-theme) .secondary:hover {
background-color: rgba(249, 249, 250, 0.2); }
[lwt-newtab-brighttext] .secondary:active {
[lwt-newtab-brighttext]:not(.force-light-theme) .secondary:active {
background-color: rgba(249, 249, 250, 0.3); }
[lwt-newtab-brighttext] .footer .secondary {
[lwt-newtab-brighttext]:not(.force-light-theme) .footer .secondary {
background-color: rgba(249, 249, 250, 0.3); }
[lwt-newtab-brighttext] .footer .secondary:hover {
[lwt-newtab-brighttext]:not(.force-light-theme) .footer .secondary:hover {
background-color: rgba(249, 249, 250, 0.4); }
[lwt-newtab-brighttext] .footer .secondary:active {
[lwt-newtab-brighttext]:not(.force-light-theme) .footer .secondary:active {
background-color: rgba(249, 249, 250, 0.5); }
.SnippetBaseContainer {
@ -2274,7 +2359,7 @@ main {
color: var(--newtab-link-primary-color); }
.SnippetBaseContainer a:hover {
text-decoration: underline; }
[lwt-newtab-brighttext] .SnippetBaseContainer a {
[lwt-newtab-brighttext]:not(.force-light-theme) .SnippetBaseContainer a {
font-weight: bold; }
.SnippetBaseContainer input[type='checkbox'] {
margin-inline-start: 0; }
@ -2581,6 +2666,34 @@ main {
.SimpleSnippet .icon {
align-self: flex-start; }
.SimpleSnippet.has-section-header .innerWrapper {
flex-wrap: wrap;
padding-top: 7px; }
.SimpleSnippet .innerContentWrapper {
align-items: center;
display: flex; }
.SimpleSnippet .section-header {
flex: 0 0 100%;
margin-bottom: 10px; }
.SimpleSnippet .section-title {
color: var(--newtab-section-header-text-color);
display: inline-block;
font-size: 13px;
font-weight: bold;
margin: 0; }
.SimpleSnippet .section-title a {
color: var(--newtab-section-header-text-color);
font-weight: inherit;
text-decoration: none; }
.SimpleSnippet .section-title .icon {
height: 16px;
margin-inline-end: 6px;
margin-top: -2px;
width: 16px; }
.SubmitFormSnippet {
flex-direction: column;
flex: 1 1 100%;

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -1948,7 +1948,7 @@ module.exports = {"title":"EOYSnippet","description":"Fundraising Snippet","vers
/* 19 */
/***/ (function(module) {
module.exports = {"title":"SimpleSnippet","description":"A simple template with an icon, text, and optional button.","version":"1.1.1","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Snippet title displayed before snippet text"}]},"text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"button_action":{"type":"string","description":"The type of action the button should trigger."},"button_url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"A url, button_label links to this"}]},"button_action_args":{"type":"string","description":"Additional parameters for button action, example which specific menu the button should open"},"button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}]},"button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"block_button_text":{"type":"string","description":"Tooltip text used for dismiss button.","default":"Remove this"},"tall":{"type":"boolean","description":"To be used by fundraising only, increases height to roughly 120px. Defaults to false."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked"},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."},"args":{"type":"string","description":"Additional parameters for link action, example which specific menu the button should open"}}}},"additionalProperties":false,"required":["text"],"dependencies":{"button_action":["button_label"],"button_url":["button_label"],"button_color":["button_label"],"button_background_color":["button_label"]}};
module.exports = {"title":"SimpleSnippet","description":"A simple template with an icon, text, and optional button.","version":"1.1.1","type":"object","definitions":{"plainText":{"description":"Plain text (no HTML allowed)","type":"string"},"richText":{"description":"Text with HTML subset allowed: i, b, u, strong, em, br","type":"string"},"link_url":{"description":"Target for links or buttons","type":"string","format":"uri"}},"properties":{"title":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Snippet title displayed before snippet text"}]},"text":{"allOf":[{"$ref":"#/definitions/richText"},{"description":"Main body text of snippet. HTML subset allowed: i, b, u, strong, em, br"}]},"icon":{"type":"string","description":"Snippet icon. 64x64px. SVG or PNG preferred."},"title_icon":{"type":"string","description":"Small icon that shows up before the title / text. 16x16px. SVG or PNG preferred. Grayscale."},"button_action":{"type":"string","description":"The type of action the button should trigger."},"button_url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"A url, button_label links to this"}]},"button_action_args":{"type":"string","description":"Additional parameters for button action, example which specific menu the button should open"},"button_label":{"allOf":[{"$ref":"#/definitions/plainText"},{"description":"Text for a button next to main snippet text that links to button_url. Requires button_url."}]},"button_color":{"type":"string","description":"The text color of the button. Valid CSS color."},"button_background_color":{"type":"string","description":"The background color of the button. Valid CSS color."},"block_button_text":{"type":"string","description":"Tooltip text used for dismiss button.","default":"Remove this"},"tall":{"type":"boolean","description":"To be used by fundraising only, increases height to roughly 120px. Defaults to false."},"do_not_autoblock":{"type":"boolean","description":"Used to prevent blocking the snippet after the CTA (link or button) has been clicked"},"links":{"additionalProperties":{"url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"The url where the link points to."}]},"metric":{"type":"string","description":"Custom event name sent with telemetry event."},"args":{"type":"string","description":"Additional parameters for link action, example which specific menu the button should open"}}},"section_title_icon":{"type":"string","description":"Section title icon. 16x16px. SVG or PNG preferred. section_title_text must also be specified to display."},"section_title_text":{"type":"string","description":"Section title text. section_title_icon must also be specified to display."},"section_title_url":{"allOf":[{"$ref":"#/definitions/link_url"},{"description":"A url, section_title_text links to this"}]}},"additionalProperties":false,"required":["text"],"dependencies":{"button_action":["button_label"],"button_url":["button_label"],"button_color":["button_label"],"button_background_color":["button_label"],"section_title_url":["section_title_text"]}};
/***/ }),
/* 20 */
@ -2372,6 +2372,15 @@ class BaseContent extends react__WEBPACK_IMPORTED_MODULE_9___default.a.PureCompo
this.props.dispatch(common_Actions_jsm__WEBPACK_IMPORTED_MODULE_0__["actionCreators"].UserEvent({ event: "OPEN_NEWTAB_PREFS" }));
}
disableDarkTheme() {
// Dark themes are not supported in discovery stream view
// Add force-light-theme class to body tag to disable dark mode. See Bug 1519764
const bodyClassNames = global.document.body.classList;
if (!bodyClassNames.contains("force-light-theme")) {
bodyClassNames.add("force-light-theme");
}
}
render() {
const { props } = this;
const { App } = props;
@ -2383,6 +2392,10 @@ class BaseContent extends react__WEBPACK_IMPORTED_MODULE_9___default.a.PureCompo
const isDiscoveryStream = props.DiscoveryStream.config && props.DiscoveryStream.config.enabled;
const searchHandoffEnabled = prefs["improvesearch.handoffToAwesomebar"];
if (isDiscoveryStream) {
this.disableDarkTheme();
}
const outerClassName = ["outer-wrapper", shouldBeFixedToTop && "fixed-to-top", prefs.showSearch && this.state.fixedSearch && !noSectionsEnabled && "fixed-search", prefs.showSearch && noSectionsEnabled && "only-search"].filter(v => v).join(" ");
return react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(
@ -2411,7 +2424,11 @@ class BaseContent extends react__WEBPACK_IMPORTED_MODULE_9___default.a.PureCompo
{ className: "non-collapsible-section" },
react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_ManualMigration_ManualMigration__WEBPACK_IMPORTED_MODULE_7__["ManualMigration"], null)
),
isDiscoveryStream ? react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_DiscoveryStreamBase_DiscoveryStreamBase__WEBPACK_IMPORTED_MODULE_5__["DiscoveryStreamBase"], null) : react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_11__["Sections"], null),
isDiscoveryStream ? react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(
content_src_components_ErrorBoundary_ErrorBoundary__WEBPACK_IMPORTED_MODULE_6__["ErrorBoundary"],
{ className: "borderless-error" },
react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_DiscoveryStreamBase_DiscoveryStreamBase__WEBPACK_IMPORTED_MODULE_5__["DiscoveryStreamBase"], null)
) : react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_Sections_Sections__WEBPACK_IMPORTED_MODULE_11__["Sections"], null),
react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(PrefsButton, { onClick: this.openPreferences })
),
react__WEBPACK_IMPORTED_MODULE_9___default.a.createElement(content_src_components_ConfirmDialog_ConfirmDialog__WEBPACK_IMPORTED_MODULE_3__["ConfirmDialog"], null)
@ -6410,7 +6427,7 @@ class _Search extends react__WEBPACK_IMPORTED_MODULE_4___default.a.PureComponent
{ className: "fake-textbox" },
this.props.intl.formatMessage({ id: "search_web_placeholder" })
),
react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: "fake-editable", tabIndex: "-1", "aria-hidden": "true", contentEditable: "", onDrop: this.onSearchHandoffDrop, onPaste: this.onSearchHandoffPaste }),
react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", { type: "search", className: "fake-editable", tabIndex: "-1", "aria-hidden": "true", onDrop: this.onSearchHandoffDrop, onPaste: this.onSearchHandoffPaste }),
react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("div", { className: "fake-caret" })
),
react__WEBPACK_IMPORTED_MODULE_4___default.a.createElement("input", {
@ -7056,7 +7073,7 @@ class DSCard_DSCard extends external_React_default.a.PureComponent {
{ className: "title" },
this.props.title
),
external_React_default.a.createElement(
this.props.excerpt && external_React_default.a.createElement(
"p",
{ className: "excerpt" },
this.props.excerpt
@ -7132,127 +7149,10 @@ CardGrid_CardGrid.defaultProps = {
// EXTERNAL MODULE: external "ReactRedux"
var external_ReactRedux_ = __webpack_require__(24);
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/Hero/Hero.jsx
class Hero_Hero extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
this.onLinkClick = this.onLinkClick.bind(this);
}
onLinkClick(event) {
if (this.props.dispatch) {
this.props.dispatch(Actions["actionCreators"].UserEvent({
event: "CLICK",
source: this.props.type.toUpperCase(),
action_position: 0
}));
this.props.dispatch(Actions["actionCreators"].ImpressionStats({
source: this.props.type.toUpperCase(),
click: 0,
tiles: [{ id: this.heroRec.id, pos: 0 }]
}));
}
}
render() {
const { data } = this.props;
// Handle a render before feed has been fetched by displaying nothing
if (!data || !data.recommendations) {
return external_React_default.a.createElement("div", null);
}
let [heroRec, ...otherRecs] = data.recommendations.slice(0, this.props.items);
this.heroRec = heroRec;
let truncateText = (text, cap) => `${text.substring(0, cap)}${text.length > cap ? `...` : ``}`;
// Note that `{index + 1}` is necessary below for telemetry since we treat heroRec as index 0.
let cards = otherRecs.map((rec, index) => external_React_default.a.createElement(DSCard_DSCard, {
key: `dscard-${index}`,
image_src: rec.image_src,
title: truncateText(rec.title, 44),
url: rec.url,
id: rec.id,
index: index + 1,
type: this.props.type,
dispatch: this.props.dispatch,
context: truncateText(rec.context || "", 22),
source: truncateText(`TODO: SOURCE`, 22) }));
return external_React_default.a.createElement(
"div",
null,
external_React_default.a.createElement(
"div",
{ className: "ds-header" },
this.props.title
),
external_React_default.a.createElement(
"div",
{ className: `ds-hero ds-hero-${this.props.border}` },
external_React_default.a.createElement(
"a",
{ href: heroRec.url, className: "wrapper", onClick: this.onLinkClick },
external_React_default.a.createElement(
"div",
{ className: "img-wrapper" },
external_React_default.a.createElement("div", { className: "img", style: { backgroundImage: `url(${heroRec.image_src})` } })
),
external_React_default.a.createElement(
"div",
{ className: "meta" },
external_React_default.a.createElement(
"header",
null,
truncateText(heroRec.title, 28)
),
external_React_default.a.createElement(
"p",
null,
truncateText(heroRec.excerpt, 114)
),
heroRec.context ? external_React_default.a.createElement(
"p",
{ className: "context" },
truncateText(heroRec.context, 22)
) : external_React_default.a.createElement(
"p",
null,
truncateText(`TODO: SOURCE`, 22)
)
)
),
external_React_default.a.createElement(
"div",
{ className: "cards" },
cards
)
)
);
}
// CONCATENATED MODULE: ./content-src/lib/truncate-text.js
function truncateText(text = "", cap) {
return text.substring(0, cap).trim() + (text.length > cap ? "…" : "");
}
Hero_Hero.defaultProps = {
data: {},
border: `border`,
items: 1 // Number of stories to display
};
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/HorizontalRule/HorizontalRule.jsx
class HorizontalRule_HorizontalRule extends external_React_default.a.PureComponent {
render() {
return external_React_default.a.createElement("hr", { className: "ds-hr" });
}
}
// EXTERNAL MODULE: ./content-src/components/DiscoveryStreamImpressionStats/ImpressionStats.jsx
var ImpressionStats = __webpack_require__(29);
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/List/List.jsx
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
@ -7260,6 +7160,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
/**
* @note exported for testing only
*/
@ -7306,6 +7207,11 @@ class List_ListItem extends external_React_default.a.PureComponent {
this.props.title
)
),
this.props.excerpt && external_React_default.a.createElement(
"div",
{ className: "ds-list-item-excerpt" },
truncateText(this.props.excerpt, 90)
),
external_React_default.a.createElement(
"div",
{ className: "ds-list-item-info" },
@ -7330,9 +7236,9 @@ function _List(props) {
const recs = feed.data.recommendations;
let recMarkup = recs.slice(0, props.items).map((rec, index) => external_React_default.a.createElement(List_ListItem, _extends({}, rec, { key: `ds-list-item-${index}`, index: index, type: props.type, dispatch: props.dispatch })));
let recMarkup = recs.slice(props.recStartingPoint, props.items).map((rec, index) => external_React_default.a.createElement(List_ListItem, _extends({}, rec, { key: `ds-list-item-${index}`, index: index, type: props.type, dispatch: props.dispatch })));
const listStyles = ["ds-list", props.hasImages ? "ds-list-images" : "", props.hasNumbers ? "ds-list-numbers" : ""];
const listStyles = ["ds-list", props.fullWidth ? "ds-list-full-width" : "", props.hasBorders ? "ds-list-borders" : "", props.hasImages ? "ds-list-images" : "", props.hasNumbers ? "ds-list-numbers" : ""];
return external_React_default.a.createElement(
"div",
null,
@ -7341,7 +7247,6 @@ function _List(props) {
{ className: "ds-header" },
props.header.title
) : null,
external_React_default.a.createElement("hr", { className: "ds-list-border" }),
external_React_default.a.createElement(
"ul",
{ className: listStyles.join(" ") },
@ -7351,12 +7256,145 @@ function _List(props) {
}
_List.defaultProps = {
recStartingPoint: 0, // Index of recommendations to start displaying from
fullWidth: false, // Display items taking up the whole column
hasBorders: false, // Display lines separating each item
hasImages: false, // Display images for each item
hasNumbers: false, // Display numbers for each item
items: 6 // Number of stories to display. TODO: get from endpoint
};
const List = Object(external_ReactRedux_["connect"])(state => ({ DiscoveryStream: state.DiscoveryStream }))(_List);
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/Hero/Hero.jsx
class Hero_Hero extends external_React_default.a.PureComponent {
constructor(props) {
super(props);
this.onLinkClick = this.onLinkClick.bind(this);
}
onLinkClick(event) {
if (this.props.dispatch) {
this.props.dispatch(Actions["actionCreators"].UserEvent({
event: "CLICK",
source: this.props.type.toUpperCase(),
action_position: 0
}));
this.props.dispatch(Actions["actionCreators"].ImpressionStats({
source: this.props.type.toUpperCase(),
click: 0,
tiles: [{ id: this.heroRec.id, pos: 0 }]
}));
}
}
render() {
const { data } = this.props;
// Handle a render before feed has been fetched by displaying nothing
if (!data || !data.recommendations) {
return external_React_default.a.createElement("div", null);
}
let [heroRec, ...otherRecs] = data.recommendations.slice(0, this.props.items);
this.heroRec = heroRec;
// Note that `{index + 1}` is necessary below for telemetry since we treat heroRec as index 0.
let cards = otherRecs.map((rec, index) => external_React_default.a.createElement(DSCard_DSCard, {
key: `dscard-${index}`,
image_src: rec.image_src,
title: truncateText(rec.title, 44),
url: rec.url,
id: rec.id,
index: index + 1,
type: this.props.type,
dispatch: this.props.dispatch,
context: truncateText(rec.context, 22),
source: truncateText(rec.domain, 22) }));
let list = external_React_default.a.createElement(List, {
recStartingPoint: 1,
feed: this.props.feed,
hasImages: true,
hasBorders: this.props.border === `border`,
items: this.props.items,
type: `Hero` });
return external_React_default.a.createElement(
"div",
null,
external_React_default.a.createElement(
"div",
{ className: "ds-header" },
this.props.title
),
external_React_default.a.createElement(
"div",
{ className: `ds-hero ds-hero-${this.props.border}` },
external_React_default.a.createElement(
"a",
{ href: heroRec.url, className: "wrapper", onClick: this.onLinkClick },
external_React_default.a.createElement(
"div",
{ className: "img-wrapper" },
external_React_default.a.createElement("div", { className: "img", style: { backgroundImage: `url(${heroRec.image_src})` } })
),
external_React_default.a.createElement(
"div",
{ className: "meta" },
external_React_default.a.createElement(
"header",
null,
truncateText(heroRec.title, 28)
),
external_React_default.a.createElement(
"p",
null,
truncateText(heroRec.excerpt, 114)
),
heroRec.context ? external_React_default.a.createElement(
"p",
{ className: "context" },
truncateText(heroRec.context, 22)
) : external_React_default.a.createElement(
"p",
null,
truncateText(heroRec.domain, 22)
)
)
),
external_React_default.a.createElement(
"div",
{ className: `${this.props.subComponentType}` },
this.props.subComponentType === `cards` ? cards : list
)
)
);
}
}
Hero_Hero.defaultProps = {
data: {},
border: `border`,
items: 1 // Number of stories to display
};
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/HorizontalRule/HorizontalRule.jsx
class HorizontalRule_HorizontalRule extends external_React_default.a.PureComponent {
render() {
return external_React_default.a.createElement("hr", { className: "ds-hr" });
}
}
// EXTERNAL MODULE: ./content-src/components/DiscoveryStreamImpressionStats/ImpressionStats.jsx
var ImpressionStats = __webpack_require__(29);
// CONCATENATED MODULE: ./content-src/components/DiscoveryStreamComponents/Navigation/Navigation.jsx
@ -7725,7 +7763,7 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
});
}
renderComponent(component) {
renderComponent(component, embedWidth) {
let rows;
const { spocs } = this.props.DiscoveryStream;
@ -7766,6 +7804,8 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
ImpressionStats["ImpressionStats"],
{ rows: rows, dispatch: this.props.dispatch, source: component.type },
external_React_default.a.createElement(Hero_Hero, {
subComponentType: embedWidth >= 9 ? `cards` : `list`,
feed: component.feed,
title: component.header && component.header.title,
data: component.data,
border: component.properties.border,
@ -7782,6 +7822,8 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
{ rows: rows, dispatch: this.props.dispatch, source: component.type },
external_React_default.a.createElement(List, {
feed: component.feed,
fullWidth: component.properties.full_width,
hasBorders: component.properties.border === "border",
hasImages: component.properties.has_images,
hasNumbers: component.properties.has_numbers,
items: component.properties.items,
@ -7821,7 +7863,7 @@ class DiscoveryStreamBase_DiscoveryStreamBase extends external_React_default.a.P
return external_React_default.a.createElement(
"div",
{ key: `component-${componentIndex}` },
this.renderComponent(component)
this.renderComponent(component, row.width)
);
})
)
@ -7881,6 +7923,9 @@ const Button = props => {
props.children
);
};
// CONCATENATED MODULE: ./content-src/asrouter/components/ConditionalWrapper/ConditionalWrapper.jsx
// lifted from https://gist.github.com/kitze/23d82bb9eb0baabfd03a6a720b1d637f
const ConditionalWrapper = ({ condition, wrap, children }) => condition ? wrap(children) : children;
// EXTERNAL MODULE: ./content-src/asrouter/components/RichText/RichText.jsx
var RichText = __webpack_require__(16);
@ -7966,6 +8011,7 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < argument
const DEFAULT_ICON_PATH = "chrome://branding/content/icon64.png";
class SimpleSnippet_SimpleSnippet extends external_React_default.a.PureComponent {
@ -8035,35 +8081,95 @@ class SimpleSnippet_SimpleSnippet extends external_React_default.a.PureComponent
sendClick: props.sendClick });
}
wrapSectionHeader(url) {
return function (children) {
return external_React_default.a.createElement(
"a",
{ href: url },
children
);
};
}
wrapSnippetContent(children) {
return external_React_default.a.createElement(
"div",
{ className: "innerContentWrapper" },
children
);
}
renderSectionHeader() {
const { props } = this;
// an icon and text must be specified to render the section header
if (props.content.section_title_icon && props.content.section_title_text) {
const sectionTitleIcon = Object(template_utils["safeURI"])(props.content.section_title_icon);
const sectionTitleURL = props.content.section_title_url;
return external_React_default.a.createElement(
"div",
{ className: "section-header" },
external_React_default.a.createElement(
"h3",
{ className: "section-title" },
external_React_default.a.createElement(
ConditionalWrapper,
{ condition: sectionTitleURL, wrap: this.wrapSectionHeader(sectionTitleURL) },
external_React_default.a.createElement("span", { className: "icon icon-small-spacer", style: { backgroundImage: `url("${sectionTitleIcon}")` } }),
external_React_default.a.createElement(
"span",
{ className: "section-title-text" },
props.content.section_title_text
)
)
)
);
}
return null;
}
render() {
const { props } = this;
const sectionHeader = this.renderSectionHeader();
let className = "SimpleSnippet";
if (props.className) {
className += ` ${props.className}`;
}
if (props.content.tall) {
className += " tall";
}
if (sectionHeader) {
className += " has-section-header";
}
return external_React_default.a.createElement(
SnippetBase_SnippetBase,
_extends({}, props, { className: className, textStyle: this.props.textStyle }),
external_React_default.a.createElement("img", { src: Object(template_utils["safeURI"])(props.content.icon) || DEFAULT_ICON_PATH, className: "icon" }),
sectionHeader,
external_React_default.a.createElement(
"div",
null,
this.renderTitle(),
" ",
ConditionalWrapper,
{ condition: sectionHeader, wrap: this.wrapSnippetContent },
external_React_default.a.createElement("img", { src: Object(template_utils["safeURI"])(props.content.icon) || DEFAULT_ICON_PATH, className: "icon" }),
external_React_default.a.createElement(
"p",
{ className: "body" },
this.renderText()
"div",
null,
this.renderTitle(),
" ",
external_React_default.a.createElement(
"p",
{ className: "body" },
this.renderText()
),
this.props.extraContent
),
this.props.extraContent
),
external_React_default.a.createElement(
"div",
null,
this.renderButton()
external_React_default.a.createElement(
"div",
null,
this.renderButton()
)
)
);
}

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -183,7 +183,7 @@ const PREFS_CONFIG = new Map([
} else {
searchShortcuts.push("google");
}
if (["AT", "DE", "FR", "GB", "IT", "JP", "US"].includes(geo)) {
if (["DE", "FR", "GB", "IT", "JP", "US"].includes(geo)) {
searchShortcuts.push("amazon");
}
return searchShortcuts.join(",");
@ -217,6 +217,7 @@ const PREFS_CONFIG = new Map([
title: "Configuration for the new pocket new tab",
value: JSON.stringify({
enabled: false,
show_spocs: true,
// This is currently an exmple layout used for dev purposes.
layout_endpoint: "https://getpocket.com/v3/newtab/layout?version=1&consumer_key=40249-e88c401e1b1f2242d9e441c4&layout_variant=basic",
}),

Просмотреть файл

@ -42,6 +42,12 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
return this._prefCache.config;
}
get showSpocs() {
// showSponsored is generally a use set spoc opt out,
// show_spocs is generally a mozilla set value.
return this.store.getState().Prefs.values.showSponsored && this.config.show_spocs;
}
setupPrefs() {
Services.prefs.addObserver(CONFIG_PREF_NAME, this);
// Send the initial state of the pref on our reducer
@ -157,31 +163,40 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
async loadSpocs() {
const cachedData = await this.cache.get() || {};
let {spocs} = cachedData;
if (!spocs || !(Date.now() - spocs.lastUpdated < SPOCS_FEEDS_UPDATE_TIME)) {
const spocsResponse = await this.fetchSpocs();
if (spocsResponse) {
spocs = {
lastUpdated: Date.now(),
data: spocsResponse,
};
await this.cache.set("spocs", spocs);
} else {
Cu.reportError("No response for spocs_endpoint prop");
// Use old data if we have it, otherwise nothing.
spocs = spocs || {};
let spocs;
if (this.showSpocs) {
spocs = cachedData.spocs;
if (!spocs || !(Date.now() - spocs.lastUpdated < SPOCS_FEEDS_UPDATE_TIME)) {
const spocsResponse = await this.fetchSpocs();
if (spocsResponse) {
spocs = {
lastUpdated: Date.now(),
data: spocsResponse,
};
await this.cache.set("spocs", spocs);
} else {
Cu.reportError("No response for spocs_endpoint prop");
}
}
}
if (spocs) {
this.store.dispatch(ac.BroadcastToContent({
type: at.DISCOVERY_STREAM_SPOCS_UPDATE,
data: {
lastUpdated: spocs.lastUpdated,
spocs: spocs.data,
},
}));
}
// Use good data if we have it, otherwise nothing.
// We can have no data if spocs set to off.
// We can have no data if request fails and there is no good cache.
// We want to send an update spocs or not, so client can render something.
spocs = spocs || {
lastUpdated: Date.now(),
data: {},
};
this.store.dispatch(ac.BroadcastToContent({
type: at.DISCOVERY_STREAM_SPOCS_UPDATE,
data: {
lastUpdated: spocs.lastUpdated,
spocs: spocs.data,
},
}));
}
async getComponentFeed(feedUrl) {
@ -275,6 +290,12 @@ this.DiscoveryStreamFeed = class DiscoveryStreamFeed {
// When this feed is shutting down:
this.uninitPrefs();
break;
case at.PREF_CHANGED:
// Check if spocs was disabled. Remove them if they were.
if (action.data.name === "showSponsored") {
await this.loadSpocs();
}
break;
}
}
};

Просмотреть файл

@ -219,6 +219,34 @@ const MESSAGES = () => ([
"test": "takeover",
},
},
{
"id": "SIMPLE_TEST_WITH_SECTION_HEADING",
"template": "simple_snippet",
"content": {
"button_label": "Get one now!",
"button_url": "https://www.mozilla.org/en-US/firefox/accounts",
"icon": TEST_ICON,
"title": "Firefox Account!",
"text": "<syncLink>Sync it, link it, take it with you</syncLink>. All this and more with a Firefox Account.",
"links": {"syncLink": {"url": "https://www.mozilla.org/en-US/firefox/accounts"}},
"block_button_text": "Block",
"section_title_icon": "resource://activity-stream/data/content/assets/glyph-pocket-16.svg",
"section_title_text": "Messages from Mozilla",
},
},
{
"id": "SIMPLE_TEST_WITH_SECTION_HEADING_AND_LINK",
"template": "simple_snippet",
"content": {
"icon": TEST_ICON,
"title": "Firefox Account!",
"text": "Sync it, link it, take it with you. All this and more with a Firefox Account.",
"block_button_text": "Block",
"section_title_icon": "resource://activity-stream/data/content/assets/glyph-pocket-16.svg",
"section_title_text": "Messages from Mozilla (click for info)",
"section_title_url": "https://www.mozilla.org/about",
},
},
]);
const SnippetsTestMessageProvider = {

Просмотреть файл

@ -163,7 +163,7 @@ this.TopSitesFeed = class TopSitesFeed {
const shouldPin = this.store.getState().Prefs.values[SEARCH_SHORTCUTS_SEARCH_ENGINES_PREF]
.split(",")
.map(getSearchProvider)
.filter(s => s);
.filter(s => s && s.shortURL !== this._currentSearchHostname);
// If we've previously inserted all search shortcuts return early
if (shouldPin.every(shortcut => prevInsertedShortcuts.includes(shortcut.shortURL))) {

Просмотреть файл

@ -91,6 +91,11 @@ section_disclaimer_topstories_buttontext=Tamam, başa düşdüm
# what is shown for the homepage, new windows, and new tabs.
prefs_home_header=Firefox Ev Məzmunu
prefs_home_description=Firefox Evdə hansı məzmunları görmək istədiyinizi seçin.
prefs_content_discovery_header=Firefox Ev
prefs_content_discovery_description=Firefox Evdəki Məzmun Kəşfi yüksək keyfiyyətli və sizə uyğun internet məqalələrini kəşf etməyinizə imkan verir.
prefs_content_discovery_button=Məzmun Kəşfini Söndür
# 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
@ -144,7 +149,6 @@ pocket_read_more=Məşhur Mövzular:
# end of the list of popular topic links.
pocket_read_even_more=Daha çox hekayə gör
pocket_more_reccommendations=Daha Çox Tövsiyyələr
pocket_learn_more=Ətraflı Öyrən
pocket_how_it_works=Bu necə işləyir
pocket_cta_button=Pocket əldə edin
pocket_cta_text=Sevdiyiniz məqalələri Pocket-də saxlayın və möhtəşəm yeni yazıları kəşf edin.

Просмотреть файл

@ -91,6 +91,9 @@ section_disclaimer_topstories_buttontext=Ok, ¡ya caché!
# what is shown for the homepage, new windows, and new tabs.
prefs_home_header=Contenido de la página de inicio de Firefox
prefs_home_description=Elige qué contenido quieres en tu pantalla de inicio de Firefox.
prefs_content_discovery_header=Inicio de Firefox
# 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

Просмотреть файл

@ -93,6 +93,7 @@ prefs_home_header=Contenu de la page daccueil de Firefox
prefs_home_description=Choisissez le contenu que vous souhaitez pour la page daccueil de Firefox.
prefs_content_discovery_header=Page daccueil de Firefox
prefs_content_discovery_button=Désactiver la découverte de contenu
# 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).

Просмотреть файл

@ -91,6 +91,9 @@ section_disclaimer_topstories_buttontext=Oĩma, hesakãma chéve
# what is shown for the homepage, new windows, and new tabs.
prefs_home_header=Kuatiarogue retepy Firefox ñepyrũháme
prefs_home_description=Eiporavo mbae retepýpa eipota Firefox mbaerechaha ñepyrũháme.
prefs_content_discovery_header=Firefox kuatiarogue ñepyrũ
# 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
@ -144,7 +147,6 @@ pocket_read_more=Ñe'ẽmbyrã Ojehayhuvéva:
# end of the list of popular topic links.
pocket_read_even_more=Ahechaseve Mombe'upy
pocket_more_reccommendations=Hetave jeeporã
pocket_learn_more=Kuaave
pocket_how_it_works=Mbaéichapa ombaapo
pocket_cta_button=Eguereko Pocket
pocket_cta_text=Eñongatu umi eipotáva tembiasakue Pocket-pe ha emombarete ne akã ñemoñeẽ haevévape.

Просмотреть файл

@ -22,7 +22,7 @@ type_label_visited=Đã truy cập
type_label_bookmarked=Đã được đánh dấu
type_label_recommended=Xu hướng
type_label_pocket=Đã lưu vào Pocket
type_label_downloaded=Đã tải về
type_label_downloaded=Đã tải xuống
# LOCALIZATION NOTE (menu_action_*): These strings are displayed in a context
# menu and are meant as a call to action for a given page.
@ -91,6 +91,11 @@ section_disclaimer_topstories_buttontext=Ok, đã hiểu
# what is shown for the homepage, new windows, and new tabs.
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_content_discovery_header=Trang chủ Firefox
prefs_content_discovery_description=Khám phá nội dung trong trang chủ Firefox cho phép bạn khám phá các bài viết chất lượng cao, có liên quan trên web.
prefs_content_discovery_button=Tắt khám phá nội dung
# 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

Просмотреть файл

@ -40,9 +40,9 @@ window.gActivityStreamStrings = {
"section_disclaimer_topstories_buttontext": "Tamam, başa düşdüm",
"prefs_home_header": "Firefox Ev Məzmunu",
"prefs_home_description": "Firefox Evdə hansı məzmunları görmək istədiyinizi seçin.",
"prefs_content_discovery_header": "Firefox Home",
"prefs_content_discovery_description": "Content Discovery in Firefox Home allows you to discover high-quality, relevant articles from across the web.",
"prefs_content_discovery_button": "Turn Off Content Discovery",
"prefs_content_discovery_header": "Firefox Ev",
"prefs_content_discovery_description": "Firefox Evdəki Məzmun Kəşfi yüksək keyfiyyətli və sizə uyğun internet məqalələrini kəşf etməyinizə imkan verir.",
"prefs_content_discovery_button": "Məzmun Kəşfini Söndür",
"prefs_section_rows_option": "{num} sətir;{num} sətir",
"prefs_search_header": "Web Axtarış",
"prefs_topsites_description": "Ən çox ziyarət etdiyiniz saytlar",
@ -110,6 +110,5 @@ window.gActivityStreamStrings = {
"firstrun_privacy_notice": "Məxfilik Bildirişi",
"firstrun_continue_to_login": "Davam et",
"firstrun_skip_login": "Bu addımı keç",
"context_menu_title": "Menyunu aç",
"pocket_learn_more": "Ətraflı Öyrən"
"context_menu_title": "Menyunu aç"
};

Просмотреть файл

@ -40,7 +40,7 @@ window.gActivityStreamStrings = {
"section_disclaimer_topstories_buttontext": "Ok, ¡ya caché!",
"prefs_home_header": "Contenido de la página de inicio de Firefox",
"prefs_home_description": "Elige qué contenido quieres en tu pantalla de inicio de Firefox.",
"prefs_content_discovery_header": "Página de inicio de Firefox",
"prefs_content_discovery_header": "Inicio de Firefox",
"prefs_content_discovery_description": "Content Discovery en la página de inicio de Firefox le permite descubrir artículos relevantes de alta calidad en toda la web.",
"prefs_content_discovery_button": "Desactivar Content Discovery",
"prefs_section_rows_option": "{num} fila;{num} filas",

Просмотреть файл

@ -42,7 +42,7 @@ window.gActivityStreamStrings = {
"prefs_home_description": "Choisissez le contenu que vous souhaitez pour la page daccueil de Firefox.",
"prefs_content_discovery_header": "Page daccueil de Firefox",
"prefs_content_discovery_description": "Content Discovery in Firefox Home allows you to discover high-quality, relevant articles from across the web.",
"prefs_content_discovery_button": "Turn Off Content Discovery",
"prefs_content_discovery_button": "Désactiver la découverte de contenu",
"prefs_section_rows_option": "{num} ligne;{num} lignes",
"prefs_search_header": "Recherche web",
"prefs_topsites_description": "Les sites que vous visitez le plus",

Просмотреть файл

@ -40,7 +40,7 @@ window.gActivityStreamStrings = {
"section_disclaimer_topstories_buttontext": "Oĩma, hesakãma chéve",
"prefs_home_header": "Kuatiarogue retepy Firefox ñepyrũháme",
"prefs_home_description": "Eiporavo mbae retepýpa eipota Firefox mbaerechaha ñepyrũháme.",
"prefs_content_discovery_header": "Firefox Home",
"prefs_content_discovery_header": "Firefox kuatiarogue ñepyrũ",
"prefs_content_discovery_description": "Content Discovery in Firefox Home allows you to discover high-quality, relevant articles from across the web.",
"prefs_content_discovery_button": "Turn Off Content Discovery",
"prefs_section_rows_option": "{num} rysýi; {num} rysýi",
@ -110,6 +110,5 @@ window.gActivityStreamStrings = {
"firstrun_privacy_notice": "Ñemigua purureko",
"firstrun_continue_to_login": "Eku'ejey",
"firstrun_skip_login": "Ehejánte kóva",
"context_menu_title": "Eike poravorãme",
"pocket_learn_more": "Kuaave"
"context_menu_title": "Eike poravorãme"
};

Просмотреть файл

@ -10,7 +10,7 @@ window.gActivityStreamStrings = {
"type_label_bookmarked": "Đã được đánh dấu",
"type_label_recommended": "Xu hướng",
"type_label_pocket": "Đã lưu vào Pocket",
"type_label_downloaded": "Đã tải về",
"type_label_downloaded": "Đã tải xuống",
"menu_action_bookmark": "Đánh dấu",
"menu_action_remove_bookmark": "Xóa đánh dấu",
"menu_action_open_new_window": "Mở trong cửa sổ mới",
@ -40,9 +40,9 @@ 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_content_discovery_header": "Firefox Home",
"prefs_content_discovery_description": "Content Discovery in Firefox Home allows you to discover high-quality, relevant articles from across the web.",
"prefs_content_discovery_button": "Turn Off Content Discovery",
"prefs_content_discovery_header": "Trang chủ Firefox",
"prefs_content_discovery_description": "Khám phá nội dung trong trang chủ Firefox cho phép bạn khám phá các bài viết chất lượng cao, có liên quan trên web.",
"prefs_content_discovery_button": "Tắt khám phá nội dung",
"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",

Просмотреть файл

@ -58,8 +58,8 @@ test_newtab({
before: setDefaultTopSites,
test: async function searchTopSites_dismiss() {
const siteSelector = ".search-shortcut";
await ContentTaskUtils.waitForCondition(() => content.document.querySelectorAll(siteSelector).length === 2,
"2 search topsites are loaded by default");
await ContentTaskUtils.waitForCondition(() => content.document.querySelectorAll(siteSelector).length === 1,
"1 search topsites is loaded by default");
const contextMenuItems = content.openContextMenuAndGetOptions(siteSelector);
is(contextMenuItems.length, 2, "Search TopSites should only have Unpin and Dismiss");

Просмотреть файл

@ -126,7 +126,7 @@ test_newtab({
await ContentTaskUtils.waitForCondition(() => content.document.querySelector(".search-shortcut .title.pinned"), "Wait for pinned search topsites");
const searchTopSites = content.document.querySelectorAll(".title.pinned");
ok(searchTopSites.length >= 2, "There should be at least 2 search topsites");
ok(searchTopSites.length >= 1, "There should be at least 2 search topsites");
searchTopSites[0].click();

Просмотреть файл

@ -69,6 +69,38 @@ describe("SimpleSnippet", () => {
assert.calledOnce(wrapper.props().onAction);
assert.calledWithExactly(wrapper.props().onAction, {type: "OPEN_APPLICATIONS_MENU", data: {args: "appMenu"}});
});
it("should not wrap the main content if a section header is not present", () => {
const wrapper = mountAndCheckProps({text: "bar"});
assert.lengthOf(wrapper.find(".innerContentWrapper"), 0);
});
it("should wrap the main content if a section header is present", () => {
const wrapper = mountAndCheckProps({
section_title_icon: "data:image/gif;base64,R0lGODl",
section_title_text: "Messages from Mozilla",
});
assert.lengthOf(wrapper.find(".innerContentWrapper"), 1);
});
it("should render a section header if text and icon are specified", () => {
const wrapper = mountAndCheckProps({
section_title_icon: "data:image/gif;base64,R0lGODl",
section_title_text: "Messages from Mozilla",
});
assert.equal(wrapper.find(".section-title .icon").prop("style").backgroundImage, 'url("data:image/gif;base64,R0lGODl")');
assert.equal(wrapper.find(".section-title-text").text().trim(), "Messages from Mozilla");
// ensure there is no <a> when a section_title_url is not specified
assert.lengthOf(wrapper.find(".section-title a"), 0);
});
it("should render a section header wrapped in an <a> tag if a url is provided", () => {
const wrapper = mountAndCheckProps({
section_title_icon: "data:image/gif;base64,R0lGODl",
section_title_text: "Messages from Mozilla",
section_title_url: "https://www.mozilla.org",
});
assert.equal(wrapper.find(".section-title a").prop("href"), "https://www.mozilla.org");
});
it("should send an OPEN_URL action when button_url is defined and button is clicked", () => {
const wrapper = mountAndCheckProps({
button_label: "Button",

Просмотреть файл

@ -0,0 +1,37 @@
import {truncateText} from "content-src/lib/truncate-text";
describe("truncateText", () => {
it("should accept nothing", () => {
assert.equal(truncateText(), "");
});
it("should give back string with no truncating", () => {
const str = "hello";
assert.equal(truncateText(str), str);
});
it("should give back short string for long cap", () => {
const str = "hello";
assert.equal(truncateText(str, 100), str);
});
it("should give back string for exact cap", () => {
const str = "hello";
assert.equal(truncateText(str, str.length), str);
});
it("should cap off long string with ellipsis", () => {
const str = "hello world";
assert.equal(truncateText(str, 5), "hello…");
});
it("should avoid putting ellipsis after whitespace", () => {
const str = "hello world";
assert.equal(truncateText(str, 10), "hello…");
});
});

Просмотреть файл

@ -18,7 +18,7 @@ describe("DiscoveryStreamFeed", () => {
sandbox = sinon.createSandbox();
configPrefStub = sandbox.stub(global.Services.prefs, "getStringPref")
.withArgs(CONFIG_PREF_NAME)
.returns(JSON.stringify({enabled: false, layout_endpoint: "foo.com"}));
.returns(JSON.stringify({enabled: false, show_spocs: false, layout_endpoint: "foo.com"}));
// Fetch
fetchStub = sandbox.stub(global, "fetch");
@ -38,11 +38,11 @@ describe("DiscoveryStreamFeed", () => {
describe("#observe", () => {
it("should update state.DiscoveryStream.config when the pref changes", async () => {
configPrefStub.returns(JSON.stringify({enabled: true, layout_endpoint: "foo"}));
configPrefStub.returns(JSON.stringify({enabled: true, show_spocs: false, layout_endpoint: "foo"}));
feed.observe(null, null, CONFIG_PREF_NAME);
assert.deepEqual(feed.store.getState().DiscoveryStream.config, {enabled: true, layout_endpoint: "foo"});
assert.deepEqual(feed.store.getState().DiscoveryStream.config, {enabled: true, show_spocs: false, layout_endpoint: "foo"});
});
});
@ -173,6 +173,9 @@ describe("DiscoveryStreamFeed", () => {
});
describe("#loadSpocs", () => {
beforeEach(() => {
Object.defineProperty(feed, "showSpocs", {get: () => true});
});
it("should fetch fresh data if cache is empty", async () => {
sandbox.stub(feed.cache, "get").returns(Promise.resolve());
sandbox.stub(feed, "fetchSpocs").returns(Promise.resolve("data"));
@ -210,6 +213,19 @@ describe("DiscoveryStreamFeed", () => {
});
describe("#fetchSpocs", () => {
beforeEach(() => {
Object.defineProperty(feed, "showSpocs", {get: () => true});
});
it("should return null for fetchSpocs with no spocs_endpoint", async () => {
feed.store.dispatch(ac.BroadcastToContent({
type: at.DISCOVERY_STREAM_SPOCS_ENDPOINT,
data: "",
}));
const result = await feed.fetchSpocs();
assert.isNull(result);
});
it("should return old spocs if fetch failed", async () => {
sandbox.stub(feed.cache, "set").returns(Promise.resolve());
feed.store.dispatch(ac.BroadcastToContent({
@ -241,6 +257,37 @@ describe("DiscoveryStreamFeed", () => {
assert.equal(feed.store.getState().DiscoveryStream.spocs.data, "new data");
});
});
describe("#showSpocs", () => {
it("should return false from showSpocs if user pref showSponsored is false", async () => {
feed.store.getState = () => ({
Prefs: {values: {showSponsored: false}},
});
Object.defineProperty(feed, "config", {get: () => ({show_spocs: true})});
assert.isFalse(feed.showSpocs);
});
it("should return false from showSpocs if DiscoveryStrea pref show_spocs is false", async () => {
feed.store.getState = () => ({
Prefs: {values: {showSponsored: true}},
});
Object.defineProperty(feed, "config", {get: () => ({show_spocs: false})});
assert.isFalse(feed.showSpocs);
});
it("should return true from showSpocs if both prefs are true", async () => {
feed.store.getState = () => ({
Prefs: {values: {showSponsored: true}},
});
Object.defineProperty(feed, "config", {get: () => ({show_spocs: true})});
assert.isTrue(feed.showSpocs);
});
it("should fire loadSpocs is showSponsored pref changes", async () => {
sandbox.stub(feed, "loadSpocs").returns(Promise.resolve());
await feed.onAction({type: at.PREF_CHANGED, data: {name: "showSponsored"}});
assert.calledOnce(feed.loadSpocs);
});
});
describe("#clearCache", () => {
it("should set .layout, .feeds and .spocs to {}", async () => {

Просмотреть файл

@ -1343,6 +1343,12 @@ describe("Top Sites Feed", () => {
assert.deepEqual(fakeNewTabUtils.pinnedLinks.links[6], {url: "https://amazon.com", searchTopSite: true, label: "@amazon"});
});
it("should not pin shortcuts for the current default search engine", async () => {
feed._currentSearchHostname = "google";
await feed._maybeInsertSearchShortcuts(fakeNewTabUtils.pinnedLinks.links);
assert.deepEqual(fakeNewTabUtils.pinnedLinks.links[3], {url: "https://amazon.com", searchTopSite: true, label: "@amazon"});
});
it("should only pin the first shortcut if there's only one available slot", async () => {
fakeNewTabUtils.pinnedLinks.links[3] = {url: ""};
await feed._maybeInsertSearchShortcuts(fakeNewTabUtils.pinnedLinks.links);

Просмотреть файл

@ -1369,6 +1369,12 @@ BrowserGlue.prototype = {
Services.prefs.addObserver("urlclassifier.trackingTable", this._matchCBCategory);
Services.prefs.addObserver("network.cookie.cookieBehavior", this._matchCBCategory);
Services.prefs.addObserver(ContentBlockingCategoriesPrefs.PREF_CB_CATEGORY, this._updateCBCategory);
Services.prefs.addObserver("media.autoplay.default", this._updateAutoplayPref);
},
_updateAutoplayPref() {
let blocked = Services.prefs.getIntPref("media.autoplay.default", 1);
Services.telemetry.scalarSet("media.autoplay_default_blocked", blocked);
},
_matchCBCategory() {

Просмотреть файл

@ -8,12 +8,8 @@ var EXPORTED_SYMBOLS = ["ContentRestore"];
ChromeUtils.import("resource://gre/modules/Services.jsm", this);
ChromeUtils.defineModuleGetter(this, "FormData",
"resource://gre/modules/FormData.jsm");
ChromeUtils.defineModuleGetter(this, "SessionHistory",
"resource://gre/modules/sessionstore/SessionHistory.jsm");
ChromeUtils.defineModuleGetter(this, "SessionStorage",
"resource:///modules/sessionstore/SessionStorage.jsm");
ChromeUtils.defineModuleGetter(this, "Utils",
"resource://gre/modules/sessionstore/Utils.jsm");
@ -141,7 +137,7 @@ ContentRestoreInternal.prototype = {
if (tabData.storage && this.docShell instanceof Ci.nsIDocShell) {
SessionStorage.restore(this.docShell, tabData.storage);
SessionStoreUtils.restoreSessionStorage(this.docShell, tabData.storage);
delete tabData.storage;
}
@ -303,7 +299,7 @@ ContentRestoreInternal.prototype = {
// restore() will return false, and thus abort restoration for the
// current |frame| and its descendants, if |data.url| is given but
// doesn't match the loaded document's URL.
return FormData.restore(frame, data);
return SessionStoreUtils.restoreFormData(frame.document, data);
});
// Restore scroll data.

Просмотреть файл

@ -18,8 +18,6 @@ ChromeUtils.defineModuleGetter(this, "ContentRestore",
"resource:///modules/sessionstore/ContentRestore.jsm");
ChromeUtils.defineModuleGetter(this, "SessionHistory",
"resource://gre/modules/sessionstore/SessionHistory.jsm");
ChromeUtils.defineModuleGetter(this, "SessionStorage",
"resource:///modules/sessionstore/SessionStorage.jsm");
ChromeUtils.defineModuleGetter(this, "Utils",
"resource://gre/modules/sessionstore/Utils.jsm");
@ -533,7 +531,10 @@ class SessionStorageListener extends Handler {
// messages.
this.resetChanges();
this.messageQueue.push("storage", () => SessionStorage.collect(content));
this.messageQueue.push("storage", () => {
let data = SessionStoreUtils.collectSessionStorage(content);
return Object.keys(data).length ? data : null;
});
}
onPageLoadCompleted() {

Просмотреть файл

@ -1,211 +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";
var EXPORTED_SYMBOLS = ["SessionStorage"];
ChromeUtils.import("resource://gre/modules/Services.jsm");
// A bound to the size of data to store for DOM Storage.
const DOM_STORAGE_LIMIT_PREF = "browser.sessionstore.dom_storage_limit";
// Returns the principal for a given |frame| contained in a given |docShell|.
function getPrincipalForFrame(docShell, frame) {
let ssm = Services.scriptSecurityManager;
let uri = frame.document.documentURIObject;
return ssm.getDocShellCodebasePrincipal(uri, docShell);
}
var SessionStorage = Object.freeze({
/**
* Updates all sessionStorage "super cookies"
* @param content
* A tab's global, i.e. the root frame we want to collect for.
* @return Returns a nested object that will have hosts as keys and per-origin
* session storage data as strings. For example:
* {"https://example.com^userContextId=1": {"key": "value", "my_number": "123"}}
*/
collect(content) {
return SessionStorageInternal.collect(content);
},
/**
* Restores all sessionStorage "super cookies".
* @param aDocShell
* A tab's docshell (containing the sessionStorage)
* @param aStorageData
* A nested object with storage data to be restored that has hosts as
* keys and per-origin session storage data as strings. For example:
* {"https://example.com^userContextId=1": {"key": "value", "my_number": "123"}}
*/
restore(aDocShell, aStorageData) {
SessionStorageInternal.restore(aDocShell, aStorageData);
},
});
/**
* Calls the given callback |cb|, passing |frame| and each of its descendants.
*/
function forEachNonDynamicChildFrame(frame, cb) {
// Call for current frame.
cb(frame);
// Call the callback recursively for each descendant.
SessionStoreUtils.forEachNonDynamicChildFrame(frame, subframe => {
return forEachNonDynamicChildFrame(subframe, cb);
});
}
var SessionStorageInternal = {
/**
* Reads all session storage data from the given docShell.
* @param content
* A tab's global, i.e. the root frame we want to collect for.
* @return Returns a nested object that will have hosts as keys and per-origin
* session storage data as strings. For example:
* {"https://example.com^userContextId=1": {"key": "value", "my_number": "123"}}
*/
collect(content) {
let data = {};
let visitedOrigins = new Set();
let docShell = content.docShell;
forEachNonDynamicChildFrame(content, frame => {
let principal = getPrincipalForFrame(docShell, frame);
if (!principal) {
return;
}
// Get the origin of the current history entry
// and use that as a key for the per-principal storage data.
let origin;
try {
// The origin getter may throw for about:blank iframes as of bug 1340710,
// but we should ignore them anyway.
origin = principal.origin;
} catch (e) {
return;
}
if (visitedOrigins.has(origin)) {
// Don't read a host twice.
return;
}
// Mark the current origin as visited.
visitedOrigins.add(origin);
let originData = this._readEntry(principal, docShell);
if (Object.keys(originData).length) {
data[origin] = originData;
}
});
return Object.keys(data).length ? data : null;
},
/**
* Writes session storage data to the given tab.
* @param aDocShell
* A tab's docshell (containing the sessionStorage)
* @param aStorageData
* A nested object with storage data to be restored that has hosts as
* keys and per-origin session storage data as strings. For example:
* {"https://example.com^userContextId=1": {"key": "value", "my_number": "123"}}
*/
restore(aDocShell, aStorageData) {
for (let origin of Object.keys(aStorageData)) {
let data = aStorageData[origin];
let principal;
try {
// NOTE: In capture() we record the full origin for the URI which the
// sessionStorage is being captured for. As of bug 1235657 this code
// stopped parsing any origins which have originattributes correctly, as
// it decided to use the origin attributes from the docshell, and try to
// interpret the origin as a URI. Since bug 1353844 this code now correctly
// parses the full origin, and then discards the origin attributes, to
// make the behavior line up with the original intentions in bug 1235657
// while preserving the ability to read all session storage from
// previous versions. In the future, if this behavior is desired, we may
// want to use the spec instead of the origin as the key, and avoid
// transmitting origin attribute information which we then discard when
// restoring.
//
// If changing this logic, make sure to also change the principal
// computation logic in SessionStore::_sendRestoreHistory.
let attrs = aDocShell.getOriginAttributes();
let dataPrincipal = Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(origin);
principal = Services.scriptSecurityManager.createCodebasePrincipal(dataPrincipal.URI, attrs);
} catch (e) {
console.error(e);
continue;
}
let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
// There is no need to pass documentURI, it's only used to fill
// documentURI property of domstorage event, which in this case has no
// consumer. Prevention of events in case of missing documentURI will be
// solved in a followup bug to bug 600307.
// Null window because the current window doesn't match the principal yet
// and loads about:blank.
let storage = storageManager.createStorage(null, principal, "", aDocShell.usePrivateBrowsing);
for (let key of Object.keys(data)) {
try {
storage.setItem(key, data[key]);
} catch (e) {
// throws e.g. for URIs that can't have sessionStorage
console.error(e);
}
}
}
},
/**
* Reads an entry in the session storage data contained in a tab's history.
* @param aURI
* That history entry uri
* @param aDocShell
* A tab's docshell (containing the sessionStorage)
*/
_readEntry(aPrincipal, aDocShell) {
let hostData = {};
let storage;
let window = aDocShell.domWindow;
try {
let storageManager = aDocShell.QueryInterface(Ci.nsIDOMStorageManager);
storage = storageManager.getStorage(window, aPrincipal);
storage.length; // XXX: Bug 1232955 - storage.length can throw, catch that failure
} catch (e) {
// sessionStorage might throw if it's turned off, see bug 458954
storage = null;
}
if (!storage || !storage.length) {
return hostData;
}
// If the DOMSessionStorage contains too much data, ignore it.
let usage = window.windowUtils.getStorageUsage(storage);
if (usage > Services.prefs.getIntPref(DOM_STORAGE_LIMIT_PREF)) {
return hostData;
}
for (let i = 0; i < storage.length; i++) {
try {
let key = storage.key(i);
hostData[key] = storage.getItem(key);
} catch (e) {
// This currently throws for secured items (cf. bug 442048).
}
}
return hostData;
},
};

Просмотреть файл

@ -20,7 +20,6 @@ EXTRA_JS_MODULES.sessionstore = [
'SessionMigration.jsm',
'SessionSaver.jsm',
'SessionStartup.jsm',
'SessionStorage.jsm',
'SessionStore.jsm',
'SessionWorker.js',
'SessionWorker.jsm',

Просмотреть файл

@ -310,7 +310,7 @@ class UrlbarInput {
let url = result.payload.url;
switch (result.type) {
case UrlbarUtils.MATCH_TYPE.TAB_SWITCH: {
case UrlbarUtils.RESULT_TYPE.TAB_SWITCH: {
if (this._overrideDefaultAction(event)) {
where = "current";
break;
@ -328,7 +328,7 @@ class UrlbarInput {
}
return;
}
case UrlbarUtils.MATCH_TYPE.SEARCH: {
case UrlbarUtils.RESULT_TYPE.SEARCH: {
url = this._maybeCanonizeURL(event,
result.payload.suggestion || result.payload.query);
if (url) {
@ -346,7 +346,7 @@ class UrlbarInput {
this._recordSearch(engine, event, actionDetails);
break;
}
case UrlbarUtils.MATCH_TYPE.OMNIBOX:
case UrlbarUtils.RESULT_TYPE.OMNIBOX:
// Give the extension control of handling the command.
ExtensionSearchHandler.handleInputEntered(result.payload.keyword,
result.payload.content,
@ -366,7 +366,7 @@ class UrlbarInput {
let val;
switch (result.type) {
case UrlbarUtils.MATCH_TYPE.SEARCH:
case UrlbarUtils.RESULT_TYPE.SEARCH:
val = result.payload.suggestion || result.payload.query;
break;
default: {

Просмотреть файл

@ -21,13 +21,13 @@ XPCOMUtils.defineLazyModuleGetters(this, {
XPCOMUtils.defineLazyGetter(this, "logger", () =>
Log.repository.getLogger("Places.Urlbar.UrlbarMuxerUnifiedComplete"));
const MATCH_TYPE_TO_GROUP = new Map([
[ UrlbarUtils.MATCH_TYPE.TAB_SWITCH, UrlbarUtils.MATCH_GROUP.GENERAL ],
[ UrlbarUtils.MATCH_TYPE.SEARCH, UrlbarUtils.MATCH_GROUP.SUGGESTION ],
[ UrlbarUtils.MATCH_TYPE.URL, UrlbarUtils.MATCH_GROUP.GENERAL ],
[ UrlbarUtils.MATCH_TYPE.KEYWORD, UrlbarUtils.MATCH_GROUP.GENERAL ],
[ UrlbarUtils.MATCH_TYPE.OMNIBOX, UrlbarUtils.MATCH_GROUP.EXTENSION ],
[ UrlbarUtils.MATCH_TYPE.REMOTE_TAB, UrlbarUtils.MATCH_GROUP.GENERAL ],
const RESULT_TYPE_TO_GROUP = new Map([
[ UrlbarUtils.RESULT_TYPE.TAB_SWITCH, UrlbarUtils.MATCH_GROUP.GENERAL ],
[ UrlbarUtils.RESULT_TYPE.SEARCH, UrlbarUtils.MATCH_GROUP.SUGGESTION ],
[ UrlbarUtils.RESULT_TYPE.URL, UrlbarUtils.MATCH_GROUP.GENERAL ],
[ UrlbarUtils.RESULT_TYPE.KEYWORD, UrlbarUtils.MATCH_GROUP.GENERAL ],
[ UrlbarUtils.RESULT_TYPE.OMNIBOX, UrlbarUtils.MATCH_GROUP.EXTENSION ],
[ UrlbarUtils.RESULT_TYPE.REMOTE_TAB, UrlbarUtils.MATCH_GROUP.GENERAL ],
]);
/**
@ -54,7 +54,7 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
// Check the first match, if it's a preselected search match, use search buckets.
let firstMatch = context.results[0];
let buckets = context.preselected &&
firstMatch.type == UrlbarUtils.MATCH_TYPE.SEARCH ?
firstMatch.type == UrlbarUtils.RESULT_TYPE.SEARCH ?
UrlbarPrefs.get("matchBucketsSearch") :
UrlbarPrefs.get("matchBuckets");
logger.debug(`Buckets: ${buckets}`);
@ -78,12 +78,12 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
sortedMatches.push(match);
handled.add(match);
count--;
} else if (group == MATCH_TYPE_TO_GROUP.get(match.type)) {
} else if (group == RESULT_TYPE_TO_GROUP.get(match.type)) {
sortedMatches.push(match);
handled.add(match);
count--;
} else if (!MATCH_TYPE_TO_GROUP.has(match.type)) {
let errorMsg = `Match type ${match.type} is not mapped to a match group.`;
} else if (!RESULT_TYPE_TO_GROUP.has(match.type)) {
let errorMsg = `Result type ${match.type} is not mapped to a match group.`;
logger.error(errorMsg);
Cu.reportError(errorMsg);
}

Просмотреть файл

@ -147,11 +147,11 @@ const PREF_TYPES = new Map([
["number", "Int"],
]);
// Buckets for match insertion.
// Every time a new match is returned, we go through each bucket in array order,
// and look for the first one having available space for the given match type.
// Buckets for result insertion.
// Every time a new result is returned, we go through each bucket in array order,
// and look for the first one having available space for the given result type.
// Each bucket is an array containing the following indices:
// 0: The match type of the acceptable entries.
// 0: The result type of the acceptable entries.
// 1: available number of slots in this bucket.
// There are different matchBuckets definition for different contexts, currently
// a general one (matchBuckets) and a search one (matchBucketsSearch).

Просмотреть файл

@ -162,7 +162,7 @@ class ProviderOpenTabs extends UrlbarProvider {
cancel();
return;
}
addCallback(this, new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
addCallback(this, new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS, {
url: row.getResultByName("url"),
userContextId: row.getResultByName("userContextId"),

Просмотреть файл

@ -223,7 +223,7 @@ function makeUrlbarResult(tokens, info) {
switch (action.type) {
case "searchengine":
return new UrlbarResult(
UrlbarUtils.MATCH_TYPE.SEARCH,
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.MATCH_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
engine: [action.params.engineName, true],
@ -235,7 +235,7 @@ function makeUrlbarResult(tokens, info) {
);
case "keyword":
return new UrlbarResult(
UrlbarUtils.MATCH_TYPE.KEYWORD,
UrlbarUtils.RESULT_TYPE.KEYWORD,
UrlbarUtils.MATCH_SOURCE.BOOKMARKS,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
url: [action.params.url, true],
@ -246,7 +246,7 @@ function makeUrlbarResult(tokens, info) {
);
case "extension":
return new UrlbarResult(
UrlbarUtils.MATCH_TYPE.OMNIBOX,
UrlbarUtils.RESULT_TYPE.OMNIBOX,
UrlbarUtils.MATCH_SOURCE.OTHER_NETWORK,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
title: [info.comment, true],
@ -257,7 +257,7 @@ function makeUrlbarResult(tokens, info) {
);
case "remotetab":
return new UrlbarResult(
UrlbarUtils.MATCH_TYPE.REMOTE_TAB,
UrlbarUtils.RESULT_TYPE.REMOTE_TAB,
UrlbarUtils.MATCH_SOURCE.TABS,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
url: [action.params.url, true],
@ -268,7 +268,7 @@ function makeUrlbarResult(tokens, info) {
);
case "switchtab":
return new UrlbarResult(
UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
url: [action.params.url, true],
@ -279,7 +279,7 @@ function makeUrlbarResult(tokens, info) {
);
case "visiturl":
return new UrlbarResult(
UrlbarUtils.MATCH_TYPE.URL,
UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.MATCH_SOURCE.OTHER_LOCAL,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
title: [info.comment, true],
@ -295,7 +295,7 @@ function makeUrlbarResult(tokens, info) {
if (info.style.includes("priority-search")) {
return new UrlbarResult(
UrlbarUtils.MATCH_TYPE.SEARCH,
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.MATCH_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
engine: [info.comment, true],
@ -322,7 +322,7 @@ function makeUrlbarResult(tokens, info) {
source = UrlbarUtils.MATCH_SOURCE.HISTORY;
}
return new UrlbarResult(
UrlbarUtils.MATCH_TYPE.URL,
UrlbarUtils.RESULT_TYPE.URL,
source,
...UrlbarResult.payloadAndSimpleHighlights(tokens, {
url: [info.url, true],

Просмотреть файл

@ -7,9 +7,9 @@
/**
* This module exports a urlbar result class, each representing a single result
* found by a provider that can be passed from the model to the view through
* the controller. It is mainly defined by a match type, and a payload,
* the controller. It is mainly defined by a result type, and a payload,
* containing the data. A few getters allow to retrieve information common to all
* the match types.
* the result types.
*/
var EXPORTED_SYMBOLS = ["UrlbarResult"];
@ -25,9 +25,9 @@ XPCOMUtils.defineLazyModuleGetters(this, {
class UrlbarResult {
/**
* Creates a result.
* @param {integer} matchType one of UrlbarUtils.MATCH_TYPE.* values
* @param {integer} resultType one of UrlbarUtils.RESULT_TYPE.* values
* @param {integer} matchSource one of UrlbarUtils.MATCH_SOURCE.* values
* @param {object} payload data for this match. A payload should always
* @param {object} payload data for this result. A payload should always
* contain a way to extract a final url to visit. The url getter
* should have a case for each of the types.
* @param {object} [payloadHighlights] payload highlights, if any. Each
@ -36,13 +36,13 @@ class UrlbarResult {
* length] tuples. Each tuple indicates a substring in the correspoding
* payload property.
*/
constructor(matchType, matchSource, payload, payloadHighlights = {}) {
constructor(resultType, matchSource, payload, payloadHighlights = {}) {
// Type describes the payload and visualization that should be used for
// this match.
if (!Object.values(UrlbarUtils.MATCH_TYPE).includes(matchType)) {
throw new Error("Invalid match type");
// this result.
if (!Object.values(UrlbarUtils.RESULT_TYPE).includes(resultType)) {
throw new Error("Invalid result type");
}
this.type = matchType;
this.type = resultType;
// Source describes which data has been used to derive this match. In case
// multiple sources are involved, use the more privacy restricted.
@ -51,15 +51,15 @@ class UrlbarResult {
}
this.source = matchSource;
// The payload contains match data. Some of the data is common across
// The payload contains result data. Some of the data is common across
// multiple types, but most of it will vary.
if (!payload || (typeof payload != "object")) {
throw new Error("Invalid match payload");
throw new Error("Invalid result payload");
}
this.payload = payload;
if (!payloadHighlights || (typeof payloadHighlights != "object")) {
throw new Error("Invalid match payload highlights");
throw new Error("Invalid result payload highlights");
}
this.payloadHighlights = payloadHighlights;
@ -74,7 +74,7 @@ class UrlbarResult {
}
/**
* Returns a title that could be used as a label for this match.
* Returns a title that could be used as a label for this result.
* @returns {string} The label to show in a simplified title / url view.
*/
get title() {
@ -95,14 +95,14 @@ class UrlbarResult {
*/
get _titleAndHighlights() {
switch (this.type) {
case UrlbarUtils.MATCH_TYPE.TAB_SWITCH:
case UrlbarUtils.MATCH_TYPE.URL:
case UrlbarUtils.MATCH_TYPE.OMNIBOX:
case UrlbarUtils.MATCH_TYPE.REMOTE_TAB:
case UrlbarUtils.RESULT_TYPE.TAB_SWITCH:
case UrlbarUtils.RESULT_TYPE.URL:
case UrlbarUtils.RESULT_TYPE.OMNIBOX:
case UrlbarUtils.RESULT_TYPE.REMOTE_TAB:
return this.payload.title ?
[this.payload.title, this.payloadHighlights.title] :
[this.payload.url || "", this.payloadHighlights.url || []];
case UrlbarUtils.MATCH_TYPE.SEARCH:
case UrlbarUtils.RESULT_TYPE.SEARCH:
return this.payload.suggestion ?
[this.payload.suggestion, this.payloadHighlights.suggestion] :
[this.payload.query, this.payloadHighlights.query];

Просмотреть файл

@ -45,7 +45,7 @@ var UrlbarUtils = {
MAXIMUM_ALLOWED_EXTENSION_MATCHES: 6,
// This is used by UnifiedComplete, the new implementation will use
// PROVIDER_TYPE and MATCH_TYPE
// PROVIDER_TYPE and RESULT_TYPE
MATCH_GROUP: {
HEURISTIC: "heuristic",
GENERAL: "general",
@ -67,7 +67,7 @@ var UrlbarUtils = {
},
// Defines UrlbarResult types.
MATCH_TYPE: {
RESULT_TYPE: {
// An open tab.
// Payload: { icon, url, userContextId }
TAB_SWITCH: 1,

Просмотреть файл

@ -272,8 +272,8 @@ class UrlbarView {
let favicon = this._createElement("img");
favicon.className = "urlbarView-favicon";
if (result.type == UrlbarUtils.MATCH_TYPE.SEARCH ||
result.type == UrlbarUtils.MATCH_TYPE.KEYWORD) {
if (result.type == UrlbarUtils.RESULT_TYPE.SEARCH ||
result.type == UrlbarUtils.RESULT_TYPE.KEYWORD) {
favicon.src = "chrome://browser/skin/search-glass.svg";
} else {
favicon.src = result.payload.icon || "chrome://mozapps/skin/places/defaultFavicon.svg";
@ -302,11 +302,11 @@ class UrlbarView {
let secondary = this._createElement("span");
secondary.className = "urlbarView-secondary";
switch (result.type) {
case UrlbarUtils.MATCH_TYPE.TAB_SWITCH:
case UrlbarUtils.RESULT_TYPE.TAB_SWITCH:
secondary.classList.add("urlbarView-action");
secondary.textContent = bundle.GetStringFromName("switchToTab2");
break;
case UrlbarUtils.MATCH_TYPE.SEARCH:
case UrlbarUtils.RESULT_TYPE.SEARCH:
secondary.classList.add("urlbarView-action");
secondary.textContent =
bundle.formatStringFromName("searchWithEngine",

Просмотреть файл

@ -4,6 +4,7 @@
[DEFAULT]
prefs=browser.urlbar.quantumbar=true
tags=quantumbar
support-files =
dummy_page.html
head.js

Просмотреть файл

@ -1,5 +1,6 @@
[DEFAULT]
prefs=browser.urlbar.quantumbar=false
tags=urlbar
support-files =
../browser/dummy_page.html
../browser/head-common.js

Просмотреть файл

@ -33,7 +33,7 @@ add_task(function losslessDecode() {
let urlNoScheme = "example.com/\u30a2\u30a4\u30a6\u30a8\u30aa";
let url = "http://" + urlNoScheme;
if (Services.prefs.getBoolPref("browser.urlbar.quantumbar", true)) {
const result = new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
const result = new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url });
gURLBar.setValueFromResult(result);

Просмотреть файл

@ -10,7 +10,7 @@
ChromeUtils.import("resource://gre/modules/PromiseUtils.jsm");
const TEST_URL = "http://example.com";
const match = new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
const match = new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url: TEST_URL });
let controller;

Просмотреть файл

@ -9,7 +9,7 @@
"use strict";
const TEST_URL = "http://example.com";
const MATCH = new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
const MATCH = new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url: TEST_URL });
const TELEMETRY_1ST_RESULT = "PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS";
@ -156,7 +156,7 @@ add_task(async function test_n_autocomplete_results() {
for (let i = 0; i < 5; i++) {
resultsPromise = promiseControllerNotification(controller, "onQueryResults");
provider.addResults([
new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url: TEST_URL + "/i" }),
]);
@ -178,7 +178,7 @@ add_task(async function test_n_autocomplete_results() {
// Add one more, to check neither are updated.
resultsPromise = promiseControllerNotification(controller, "onQueryResults");
provider.addResults([
new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url: TEST_URL + "/6" }),
]);

Просмотреть файл

@ -23,13 +23,13 @@ add_task(async function test_muxer() {
"Should throw with invalid sort");
let matches = [
new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url: "http://mozilla.org/tab/" }),
new UrlbarResult(UrlbarUtils.MATCH_TYPE.URL,
new UrlbarResult(UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.MATCH_SOURCE.BOOKMARKS,
{ url: "http://mozilla.org/bookmark/" }),
new UrlbarResult(UrlbarUtils.MATCH_TYPE.URL,
new UrlbarResult(UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.MATCH_SOURCE.HISTORY,
{ url: "http://mozilla.org/history/" }),
];

Просмотреть файл

@ -19,8 +19,8 @@ add_task(async function test_openTabs() {
let callback = function(provider, match) {
matchCount++;
Assert.equal(provider, UrlbarProviderOpenTabs, "Got the expected provider");
Assert.equal(match.type, UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
"Got the expected match type");
Assert.equal(match.type, UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
"Got the expected result type");
Assert.equal(match.payload.url, url, "Got the expected url");
Assert.equal(match.payload.title, undefined, "Got the expected title");
};

Просмотреть файл

@ -49,13 +49,13 @@ add_task(async function test_unifiedComplete() {
Assert.equal(context.results.length, 6, "Found the expected number of matches");
Assert.deepEqual([
UrlbarUtils.MATCH_TYPE.SEARCH,
UrlbarUtils.MATCH_TYPE.SEARCH,
UrlbarUtils.MATCH_TYPE.SEARCH,
UrlbarUtils.MATCH_TYPE.URL,
UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_TYPE.URL,
], context.results.map(m => m.type), "Check match types");
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.RESULT_TYPE.URL,
], context.results.map(m => m.type), "Check result types");
Assert.deepEqual([
"moz",

Просмотреть файл

@ -29,7 +29,7 @@ add_task(async function test_providers() {
/invalid provider/,
"Should throw with invalid cancelQuery");
let match = new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
let match = new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url: "http://mozilla.org/foo/" });

Просмотреть файл

@ -4,7 +4,7 @@
"use strict";
add_task(async function test_filtering() {
let match = new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
let match = new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url: "http://mozilla.org/foo/" });
let providerName = registerBasicTestProvider([match]);
@ -29,7 +29,7 @@ add_task(async function test_filtering() {
let matches = [
match,
new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.HISTORY,
{ url: "http://mozilla.org/foo/" }),
];
@ -67,10 +67,10 @@ add_task(async function test_filter_javascript() {
},
},
});
let match = new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
let match = new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url: "http://mozilla.org/foo/" });
let jsMatch = new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
let jsMatch = new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.HISTORY,
{ url: "javascript:foo" });
let providerName = registerBasicTestProvider([match, jsMatch]);
@ -110,10 +110,10 @@ add_task(async function test_filter_sources() {
});
let goodMatches = [
new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url: "http://mozilla.org/foo/" }),
new UrlbarResult(UrlbarUtils.MATCH_TYPE.URL,
new UrlbarResult(UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.MATCH_SOURCE.HISTORY,
{ url: "http://mozilla.org/foo/" }),
];
@ -144,7 +144,7 @@ add_task(async function test_filter_sources() {
UrlbarProvidersManager.registerProvider(new TestProvider());
let badMatches = [
new UrlbarResult(UrlbarUtils.MATCH_TYPE.URL,
new UrlbarResult(UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.MATCH_SOURCE.BOOKMARKS,
{ url: "http://mozilla.org/foo/" }),
];

Просмотреть файл

@ -7,7 +7,7 @@ add_task(async function test_maxResults() {
const MATCHES_LENGTH = 20;
let matches = [];
for (let i = 0; i < MATCHES_LENGTH; i++) {
matches.push(new UrlbarResult(UrlbarUtils.MATCH_TYPE.TAB_SWITCH,
matches.push(new UrlbarResult(UrlbarUtils.RESULT_TYPE.TAB_SWITCH,
UrlbarUtils.MATCH_SOURCE.TABS,
{ url: `http://mozilla.org/foo/${i}` }));
}

Просмотреть файл

@ -111,7 +111,7 @@ Queries can be canceled.
The *searchString* gets tokenized by the `UrlbarTokenizer <https://dxr.mozilla.org/mozilla-central/source/browser/components/urlbar/UrlbarTokenizer.jsm>`_
component into tokens, some of these tokens have a special meaning and can be
used by the user to restrict the search to specific match type (See the
used by the user to restrict the search to specific result type (See the
*UrlbarTokenizer::TYPE* enum).
.. caution::
@ -355,29 +355,29 @@ UrlbarResult
===========
An `UrlbarResult <https://dxr.mozilla.org/mozilla-central/source/browser/components/urlbar/UrlbarResult.jsm>`_
instance represents a single search result with a match type, that
instance represents a single search result with a result type, that
identifies specific kind of results.
Each kind has its own properties, that the *View* may support, and a few common
properties, supported by all of the results.
.. note::
Match types are also enumerated by *UrlbarUtils.MATCH_TYPE*.
Result types are also enumerated by *UrlbarUtils.RESULT_TYPE*.
.. highlight:: JavaScript
.. code::
UrlbarResult {
constructor(matchType, payload);
constructor(resultType, payload);
type: {integer} One of UrlbarUtils.MATCH_TYPE.
type: {integer} One of UrlbarUtils.RESULT_TYPE.
source: {integer} One of UrlbarUtils.MATCH_SOURCE.
title: {string} A title that may be used as a label for this match.
icon: {string} Url of an icon for this match.
payload: {object} Object containing properties for the specific MATCH_TYPE.
title: {string} A title that may be used as a label for this result.
icon: {string} Url of an icon for this result.
payload: {object} Object containing properties for the specific RESULT_TYPE.
}
The following MATCH_TYPEs are supported:
The following RESULT_TYPEs are supported:
.. highlight:: JavaScript
.. code::

Просмотреть файл

@ -174,7 +174,6 @@
#identity-popup-content-blocking-report-breakage,
.identity-popup-content-blocking-category-label,
.identity-popup-content-blocking-category-state-label,
.identity-popup-content-blocking-category-add-blocking,
.identity-popup-permission-label,
.identity-popup-permission-state-label,
.identity-popup-security-content > description,
@ -676,7 +675,6 @@ description#identity-popup-content-verifier,
}
.identity-popup-content-blocking-category-state-label,
.identity-popup-content-blocking-category-add-blocking,
.identity-popup-permission-state-label {
margin-inline-end: 5px;
text-align: end;

Просмотреть файл

@ -32,6 +32,7 @@
background: var(--autocomplete-popup-background);
color: var(--autocomplete-popup-color);
border: 1px solid var(--autocomplete-popup-border-color);
font: menu;
}
.urlbarView-body-inner {

Просмотреть файл

@ -66,7 +66,6 @@ NS_INTERFACE_MAP_BEGIN(NullPrincipalURI)
else
NS_INTERFACE_MAP_ENTRY(nsIURI)
NS_INTERFACE_MAP_ENTRY(nsISizeOf)
NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableURI)
NS_INTERFACE_MAP_END
////////////////////////////////////////////////////////////////////////////////
@ -301,9 +300,6 @@ NullPrincipalURI::GetDisplayPrePath(nsACString& aPrePath) {
return GetPrePath(aPrePath);
}
////////////////////////////////////////////////////////////////////////////////
//// nsIIPCSerializableURI
void NullPrincipalURI::Serialize(mozilla::ipc::URIParams& aParams) {
aParams = mozilla::ipc::NullPrincipalURIParams();
}

Просмотреть файл

@ -15,7 +15,6 @@
#include "nsISizeOf.h"
#include "nsString.h"
#include "mozilla/Attributes.h"
#include "nsIIPCSerializableURI.h"
#include "mozilla/MemoryReporting.h"
#include "NullPrincipal.h"
#include "nsID.h"
@ -33,13 +32,10 @@ namespace mozilla {
class Encoding;
class NullPrincipalURI final : public nsIURI,
public nsISizeOf,
public nsIIPCSerializableURI {
class NullPrincipalURI final : public nsIURI, public nsISizeOf {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIURI
NS_DECL_NSIIPCSERIALIZABLEURI
// nsISizeOf
virtual size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override;

Просмотреть файл

@ -39,7 +39,7 @@
/* Global layout vars */
--page-width: 664px;
--base-distance: 4px;
--base-unit: 4px;
/* Global styles */
--base-font-style: message-box;
@ -52,12 +52,12 @@
/*
* Variables particular to about:debugging
*/
--alt-heading-icon-size: calc(var(--base-distance) * 6);
--alt-heading-icon-gap: var(--base-distance);
--main-heading-icon-size: calc(var(--base-distance) * 16);
--main-heading-icon-gap: calc(var(--base-distance) * 3);
--main-subheading-icon-size: calc(var(--base-distance) * 5);
--main-subheading-heading-icon-gap: calc(var(--base-distance) * 2);
--alt-heading-icon-size: calc(var(--base-unit) * 6);
--alt-heading-icon-gap: var(--base-unit);
--main-heading-icon-size: calc(var(--base-unit) * 16);
--main-heading-icon-gap: calc(var(--base-unit) * 3);
--main-subheading-icon-size: calc(var(--base-unit) * 5);
--main-subheading-heading-icon-gap: calc(var(--base-unit) * 2);
}
/*
@ -148,7 +148,7 @@ a:active {
* +--------+-------------+
*/
.main-subheading {
margin-block-start: calc(var(--base-distance) * 4);
margin-block-start: calc(var(--base-unit) * 4);
font-weight: 600;
font-size: 1.46em; /* import from .header-name in common.inc.css */
line-height: 1.3em; /* import from .header-name in common.inc.css */
@ -172,7 +172,7 @@ a:active {
line-height: 1.2; /* odd value - from common.inc.css */
margin-block-start: 0;
margin-block-end: calc(var(--base-distance) * 4);
margin-block-end: calc(var(--base-unit) * 4);
}
/* Alternative style for a subheading (i.e. h2). It features an icon */
@ -181,7 +181,7 @@ a:active {
* +--------+-------------+
*/
.alt-subheading {
margin-block-start: calc(var(--base-distance) * 4);
margin-block-start: calc(var(--base-unit) * 4);
font-weight: 600;
font-size: 1.14em;
line-height: 1.4em; /* odd value - from common.inc.css */
@ -210,13 +210,13 @@ a:active {
/* adds breathing space to the separator */
.separator--breathe {
margin: calc(var(--base-distance) * 4) 0;
margin: calc(var(--base-unit) * 4) 0;
}
/* a series of button-like elements, layed out horizontally */
.toolbar {
display: flex;
column-gap: var(--base-distance);
column-gap: var(--base-unit);
}
/*
@ -235,12 +235,12 @@ Form controls
background-color: var(--page-background);
margin: 0;
height: calc(var(--base-distance) * 8); /* Note: this is from Photon, not common.css */
padding-inline-start: calc(var(--base-distance) * 5);
padding-inline-end: calc(var(--base-distance) * 5);
height: calc(var(--base-unit) * 8); /* Note: this is from Photon, not common.css */
padding-inline-start: calc(var(--base-unit) * 5);
padding-inline-end: calc(var(--base-unit) * 5);
border: 1px solid var(--box-border-color);
border-radius: calc(var(--base-distance) / 2);
border-radius: calc(var(--base-unit) / 2);
}
.default-button:enabled:hover {
@ -253,16 +253,16 @@ Form controls
/* smaller size for a default button */
.default-button--micro {
padding-inline-start: calc(2 * var(--base-distance));
padding-inline-end: calc(2 * var(--base-distance));
padding-inline-start: calc(2 * var(--base-unit));
padding-inline-end: calc(2 * var(--base-unit));
font-size: var(--micro-font-size);
height: calc(var(--base-distance) * 6);
height: calc(var(--base-unit) * 6);
}
/* standard inputs */
.default-input {
line-height: unset;
padding: 0 calc(var(--base-distance) * 2);
padding: 0 calc(var(--base-unit) * 2);
height: 100%;
border: 1px solid var(--box-border-color);
@ -282,8 +282,8 @@ Form controls
.badge {
font-size: var(--micro-font-size);
background: var(--grey-30);
border-radius: calc(var(--base-distance) / 2);
padding: var(--base-distance) calc(2 * var(--base-distance));
border-radius: calc(var(--base-unit) / 2);
padding: var(--base-unit) calc(2 * var(--base-unit));
}
.badge--info {

Просмотреть файл

@ -54,6 +54,6 @@
}
.page__section {
margin-block-end: calc(var(--base-distance) * 12);
margin-block-end: calc(var(--base-unit) * 12);
--section-inline-margin: calc(var(--alt-heading-icon-size) + var(--alt-heading-icon-gap));
}

Просмотреть файл

@ -3,6 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.connection-prompt-setting {
margin-block-end: var(--base-distance);
margin-block-end: var(--base-unit);
text-align: right;
}

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.connect-page__usb__toggle-button {
margin-top: calc(var(--base-distance) * 4);
margin-top: calc(var(--base-unit) * 4);
}
.connect-page__disabled-section {

Просмотреть файл

@ -5,9 +5,9 @@
.connect-page__step-list {
list-style-type: decimal;
list-style-position: outside;
margin-inline-start: calc(var(--section-inline-margin) + var(--base-distance) * 4);
margin-inline-start: calc(var(--section-inline-margin) + var(--base-unit) * 4);
}
.connect-page__step {
padding-inline-start: var(--base-distance);
padding-inline-start: var(--base-unit);
}

Просмотреть файл

@ -11,7 +11,7 @@
*/
.connect-page__network-form {
display: grid;
grid-column-gap: calc(var(--base-distance) * 2);
grid-column-gap: calc(var(--base-unit) * 2);
grid-template-columns: auto 1fr auto;
align-items: center;
}

Просмотреть файл

@ -12,5 +12,5 @@
.connect-page__network-location {
display: grid;
grid-template-columns: auto max-content;
margin: calc(var(--base-distance) * 2) 0;
margin: calc(var(--base-unit) * 2) 0;
}

Просмотреть файл

@ -14,11 +14,11 @@
*/
.debug-target-item {
display: grid;
grid-template-columns: calc(var(--base-distance) * 9) 1fr max-content;
grid-column-gap: calc(var(--base-distance) * 2);
grid-template-columns: calc(var(--base-unit) * 9) 1fr max-content;
grid-column-gap: calc(var(--base-unit) * 2);
grid-template-areas: "icon name action"
". detail detail";
margin-block-end: calc(var(--base-distance) * 4);
margin-block-end: calc(var(--base-unit) * 4);
}
.debug-target-item__icon {
@ -30,7 +30,7 @@
grid-area: name;
/* so as to ellipsis */
min-width: 0;
font-size: calc(var(--base-distance) * 5);
font-size: calc(var(--base-unit) * 5);
}
.debug-target-item__action {

Просмотреть файл

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.debug-target-list {
margin-inline-start: calc(var(--base-distance) * 6);
margin-inline-start: calc(var(--base-unit) * 6);
overflow: hidden;
}

Просмотреть файл

@ -17,7 +17,7 @@
.extension-detail {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: calc(var(--base-distance) * 2);
grid-column-gap: calc(var(--base-unit) * 2);
}
.extension-detail__manifest {

Просмотреть файл

@ -51,7 +51,7 @@ class ServiceWorkerAction extends PureComponent {
if (!isRunning) {
const startLabel = this.props.getString("about-debugging-worker-action-start");
return this._renderButton({
className: "default-button",
className: "default-button js-start-button",
disabled: isMultiE10s,
label: startLabel,
onClick: this.start.bind(this),

Просмотреть файл

@ -3,5 +3,5 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.temporary-extension-detail__temporary-id-message {
padding: calc(var(--base-distance) * 2) 0;
padding: calc(var(--base-unit) * 2) 0;
}

Просмотреть файл

@ -19,5 +19,5 @@
.worker-detail {
display: grid;
grid-template-columns: auto 1fr;
grid-column-gap: calc(4 * var(--base-distance));
grid-column-gap: calc(4 * var(--base-unit));
}

Просмотреть файл

@ -24,18 +24,18 @@
*/
.message {
background-color: var(--message-background-color);
border-radius: var(--base-distance);
border-radius: var(--base-unit);
color: var(--message-color);
display: grid;
fill: var(--message-color);
grid-column-gap: var(--base-distance);
grid-template-columns: calc(var(--base-distance) * 6) 1fr;
margin: calc(var(--base-distance) * 2) 0;
padding: var(--base-distance);
grid-column-gap: var(--base-unit);
grid-template-columns: calc(var(--base-unit) * 6) 1fr;
margin: calc(var(--base-unit) * 2) 0;
padding: var(--base-unit);
-moz-context-properties: fill;
}
.message__icon {
margin: var(--base-distance);
margin: var(--base-unit);
}

Просмотреть файл

@ -41,6 +41,6 @@
}
.sidebar-item--breathe {
margin-block-start: calc(2 * var(--base-distance));
margin-block-end: calc(2 * var(--base-distance));
margin-block-start: calc(2 * var(--base-unit));
margin-block-end: calc(2 * var(--base-unit));
}

Просмотреть файл

@ -14,8 +14,8 @@
font-size: 0.8em;
align-items: center;
display: grid;
grid-column-gap: var(--base-distance);
grid-template-columns: calc(var(--base-distance) * 6) 1fr auto;
grid-column-gap: var(--base-unit);
grid-template-columns: calc(var(--base-unit) * 6) 1fr auto;
height: 100%;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше