зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1616280 - Use shadow DOM to hide Remote L10n translations for from local translations r=k88hudson
Differential Revision: https://phabricator.services.mozilla.com/D63895
This commit is contained in:
Родитель
af4a04d2c5
Коммит
d88ff7e8b9
|
@ -0,0 +1,67 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// This is loaded into all XUL windows. Wrap in a block to prevent
|
||||
// leaking to window scope.
|
||||
{
|
||||
const { RemoteL10n } = ChromeUtils.import(
|
||||
"resource://activity-stream/lib/RemoteL10n.jsm"
|
||||
);
|
||||
class MozTextParagraph extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this._content = null;
|
||||
}
|
||||
|
||||
get fluentAttributeValues() {
|
||||
const attributes = {};
|
||||
for (let name of this.getAttributeNames()) {
|
||||
if (name.startsWith("fluent-variable-")) {
|
||||
attributes[name.replace(/^fluent-variable-/, "")] = this.getAttribute(
|
||||
name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.getAttribute("fluent-remote-id") && this._content) {
|
||||
RemoteL10n.l10n.setAttributes(
|
||||
this._content,
|
||||
this.getAttribute("fluent-remote-id"),
|
||||
this.fluentAttributeValues
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static get observedAttributes() {
|
||||
return ["fluent-remote-id"];
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
this.render();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if (this.shadowRoot) {
|
||||
this.render();
|
||||
return;
|
||||
}
|
||||
|
||||
const shadowRoot = this.attachShadow({ mode: "open" });
|
||||
this._content = document.createElement("span");
|
||||
shadowRoot.appendChild(this._content);
|
||||
|
||||
this.render();
|
||||
RemoteL10n.l10n.translateFragment(this._content);
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("remote-text", MozTextParagraph);
|
||||
}
|
|
@ -26,6 +26,7 @@ browser.jar:
|
|||
res/activity-stream/data/content/tippytop/ (./data/content/tippytop/*)
|
||||
res/activity-stream/data/content/activity-stream.bundle.js (./data/content/activity-stream.bundle.js)
|
||||
res/activity-stream/data/content/newtab-render.js (./data/content/newtab-render.js)
|
||||
res/activity-stream/data/custom-elements/ (./components/CustomElements/*)
|
||||
#ifdef XP_MACOSX
|
||||
res/activity-stream/css/activity-stream.css (./css/activity-stream-mac.css)
|
||||
#elifdef XP_WIN
|
||||
|
|
|
@ -10,7 +10,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
Services: "resource://gre/modules/Services.jsm",
|
||||
EveryWindow: "resource:///modules/EveryWindow.jsm",
|
||||
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
|
||||
RemoteL10n: "resource://activity-stream/lib/RemoteL10n.jsm",
|
||||
});
|
||||
XPCOMUtils.defineLazyServiceGetter(
|
||||
this,
|
||||
|
@ -108,6 +107,15 @@ class _ToolbarPanelHub {
|
|||
win.MozXULElement.insertFTLIfNeeded("browser/branding/sync-brand.ftl");
|
||||
}
|
||||
|
||||
maybeLoadCustomElement(win) {
|
||||
if (!win.customElements.get("remote-text")) {
|
||||
Services.scriptloader.loadSubScript(
|
||||
"resource://activity-stream/data/custom-elements/paragraph.js",
|
||||
win
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Turns on the Appmenu (hamburger menu) button for all open windows and future windows.
|
||||
async enableAppmenuButton() {
|
||||
if ((await this.messages).length) {
|
||||
|
@ -170,6 +178,7 @@ class _ToolbarPanelHub {
|
|||
|
||||
// Render what's new messages into the panel.
|
||||
async renderMessages(win, doc, containerId, options = {}) {
|
||||
this.maybeLoadCustomElement(win);
|
||||
const messages =
|
||||
(options.force && options.messages) ||
|
||||
(await this.messages).sort(this._sortWhatsNewMessages);
|
||||
|
@ -178,17 +187,13 @@ class _ToolbarPanelHub {
|
|||
if (messages) {
|
||||
// Targeting attribute state might have changed making new messages
|
||||
// available and old messages invalid, we need to refresh
|
||||
for (const prevMessageEl of container.querySelectorAll(
|
||||
".whatsNew-message"
|
||||
)) {
|
||||
container.removeChild(prevMessageEl);
|
||||
}
|
||||
this.removeMessages(win, containerId);
|
||||
let previousDate = 0;
|
||||
// Get and store any variable part of the message content
|
||||
this.state.contentArguments = await this._contentArguments();
|
||||
for (let message of messages) {
|
||||
container.appendChild(
|
||||
await this._createMessageElements(win, doc, message, previousDate)
|
||||
this._createMessageElements(win, doc, message, previousDate)
|
||||
);
|
||||
previousDate = message.content.published_date;
|
||||
}
|
||||
|
@ -267,15 +272,15 @@ class _ToolbarPanelHub {
|
|||
});
|
||||
}
|
||||
|
||||
async _createMessageElements(win, doc, message, previousDate) {
|
||||
_createMessageElements(win, doc, message, previousDate) {
|
||||
const { content } = message;
|
||||
const messageEl = await this._createElement(doc, "div");
|
||||
const messageEl = this._createElement(doc, "div");
|
||||
messageEl.classList.add("whatsNew-message");
|
||||
|
||||
// Only render date if it is different from the one rendered before.
|
||||
if (content.published_date !== previousDate) {
|
||||
messageEl.appendChild(
|
||||
await this._createElement(doc, "p", {
|
||||
this._createElement(doc, "p", {
|
||||
classList: "whatsNew-message-date",
|
||||
content: new Date(content.published_date).toLocaleDateString(
|
||||
"default",
|
||||
|
@ -289,24 +294,28 @@ class _ToolbarPanelHub {
|
|||
);
|
||||
}
|
||||
|
||||
const wrapperEl = await this._createElement(doc, "button");
|
||||
const wrapperEl = this._createElement(doc, "button");
|
||||
wrapperEl.doCommand = () => this._dispatchUserAction(win, message);
|
||||
wrapperEl.classList.add("whatsNew-message-body");
|
||||
messageEl.appendChild(wrapperEl);
|
||||
|
||||
if (content.icon_url) {
|
||||
wrapperEl.classList.add("has-icon");
|
||||
const iconEl = await this._createElement(doc, "img");
|
||||
const iconEl = this._createElement(doc, "img");
|
||||
iconEl.src = content.icon_url;
|
||||
iconEl.classList.add("whatsNew-message-icon");
|
||||
await this._setTextAttribute(iconEl, "alt", content.icon_alt);
|
||||
if (content.icon_alt && content.icon_alt.string_id) {
|
||||
doc.l10n.setAttributes(iconEl, content.icon_alt.string_id);
|
||||
} else {
|
||||
iconEl.setAttribute("alt", content.icon_alt);
|
||||
}
|
||||
wrapperEl.appendChild(iconEl);
|
||||
}
|
||||
|
||||
wrapperEl.appendChild(await this._createMessageContent(win, doc, content));
|
||||
wrapperEl.appendChild(this._createMessageContent(win, doc, content));
|
||||
|
||||
if (content.link_text) {
|
||||
const anchorEl = await this._createElement(doc, "a", {
|
||||
const anchorEl = this._createElement(doc, "a", {
|
||||
classList: "text-link",
|
||||
content: content.link_text,
|
||||
});
|
||||
|
@ -323,11 +332,11 @@ class _ToolbarPanelHub {
|
|||
/**
|
||||
* Return message title (optional subtitle) and body
|
||||
*/
|
||||
async _createMessageContent(win, doc, content) {
|
||||
_createMessageContent(win, doc, content) {
|
||||
const wrapperEl = new win.DocumentFragment();
|
||||
|
||||
wrapperEl.appendChild(
|
||||
await this._createElement(doc, "h2", {
|
||||
this._createElement(doc, "h2", {
|
||||
classList: "whatsNew-message-title",
|
||||
content: content.title,
|
||||
})
|
||||
|
@ -335,14 +344,14 @@ class _ToolbarPanelHub {
|
|||
|
||||
switch (content.layout) {
|
||||
case "tracking-protections":
|
||||
await wrapperEl.appendChild(
|
||||
await this._createElement(doc, "h4", {
|
||||
wrapperEl.appendChild(
|
||||
this._createElement(doc, "h4", {
|
||||
classList: "whatsNew-message-subtitle",
|
||||
content: content.subtitle,
|
||||
})
|
||||
);
|
||||
wrapperEl.appendChild(
|
||||
await this._createElement(doc, "h2", {
|
||||
this._createElement(doc, "h2", {
|
||||
classList: "whatsNew-message-title-large",
|
||||
content: this.state.contentArguments[
|
||||
content.layout_title_content_variable
|
||||
|
@ -353,32 +362,40 @@ class _ToolbarPanelHub {
|
|||
}
|
||||
|
||||
wrapperEl.appendChild(
|
||||
await this._createElement(doc, "p", { content: content.body })
|
||||
this._createElement(doc, "p", {
|
||||
content: content.body,
|
||||
classList: "whatsNew-message-content",
|
||||
})
|
||||
);
|
||||
|
||||
return wrapperEl;
|
||||
}
|
||||
|
||||
async _createHeroElement(win, doc, message) {
|
||||
const messageEl = await this._createElement(doc, "div");
|
||||
_createHeroElement(win, doc, message) {
|
||||
this.maybeLoadCustomElement(win);
|
||||
|
||||
const messageEl = this._createElement(doc, "div");
|
||||
messageEl.setAttribute("id", "protections-popup-message");
|
||||
messageEl.classList.add("whatsNew-hero-message");
|
||||
const wrapperEl = await this._createElement(doc, "div");
|
||||
const wrapperEl = this._createElement(doc, "div");
|
||||
wrapperEl.classList.add("whatsNew-message-body");
|
||||
messageEl.appendChild(wrapperEl);
|
||||
|
||||
wrapperEl.appendChild(
|
||||
await this._createElement(doc, "h2", {
|
||||
this._createElement(doc, "h2", {
|
||||
classList: "whatsNew-message-title",
|
||||
content: message.content.title,
|
||||
})
|
||||
);
|
||||
wrapperEl.appendChild(
|
||||
await this._createElement(doc, "p", { content: message.content.body })
|
||||
this._createElement(doc, "p", {
|
||||
classList: "protections-popup-content",
|
||||
content: message.content.body,
|
||||
})
|
||||
);
|
||||
|
||||
if (message.content.link_text) {
|
||||
let linkEl = await this._createElement(doc, "a", {
|
||||
let linkEl = this._createElement(doc, "a", {
|
||||
classList: "text-link",
|
||||
content: message.content.link_text,
|
||||
});
|
||||
|
@ -392,14 +409,17 @@ class _ToolbarPanelHub {
|
|||
return messageEl;
|
||||
}
|
||||
|
||||
async _createElement(doc, elem, options = {}) {
|
||||
const node = doc.createElementNS("http://www.w3.org/1999/xhtml", elem);
|
||||
_createElement(doc, elem, options = {}) {
|
||||
let node;
|
||||
if (options.content && options.content.string_id) {
|
||||
node = doc.createElement("remote-text");
|
||||
} else {
|
||||
node = doc.createElementNS("http://www.w3.org/1999/xhtml", elem);
|
||||
}
|
||||
if (options.classList) {
|
||||
node.classList.add(options.classList);
|
||||
}
|
||||
if (options.content) {
|
||||
await this._setString(node, options.content);
|
||||
}
|
||||
this._setString(node, options.content);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
@ -447,41 +467,19 @@ class _ToolbarPanelHub {
|
|||
|
||||
// If `string_id` is present it means we are relying on fluent for translations.
|
||||
// Otherwise, we have a vanilla string.
|
||||
async _setString(el, stringObj) {
|
||||
_setString(el, stringObj) {
|
||||
if (stringObj && stringObj.string_id) {
|
||||
const [{ value }] = await RemoteL10n.l10n.formatMessages([
|
||||
{
|
||||
id: stringObj.string_id,
|
||||
// Pass all available arguments to Fluent
|
||||
args: this.state.contentArguments,
|
||||
},
|
||||
]);
|
||||
el.textContent = value;
|
||||
for (let [fluentId, value] of Object.entries(
|
||||
this.state.contentArguments || {}
|
||||
)) {
|
||||
el.setAttribute(`fluent-variable-${fluentId}`, value);
|
||||
}
|
||||
el.setAttribute("fluent-remote-id", stringObj.string_id);
|
||||
} else {
|
||||
el.textContent = stringObj;
|
||||
}
|
||||
}
|
||||
|
||||
// If `string_id` is present it means we are relying on fluent for translations.
|
||||
// Otherwise, we have a vanilla string.
|
||||
async _setTextAttribute(el, attr, stringObj) {
|
||||
if (stringObj && stringObj.string_id) {
|
||||
const [{ attributes }] = await RemoteL10n.l10n.formatMessages([
|
||||
{
|
||||
id: stringObj.string_id,
|
||||
// Pass all available arguments to Fluent
|
||||
args: this.state.contentArguments,
|
||||
},
|
||||
]);
|
||||
if (attributes) {
|
||||
const { value } = attributes.find(({ name }) => name === attr);
|
||||
el.setAttribute(attr, value);
|
||||
}
|
||||
} else {
|
||||
el.setAttribute(attr, stringObj);
|
||||
}
|
||||
}
|
||||
|
||||
async _showAppmenuButton(win) {
|
||||
this.maybeInsertFTL(win);
|
||||
await this._showElement(
|
||||
|
@ -505,10 +503,9 @@ class _ToolbarPanelHub {
|
|||
this._hideElement(win.browser.ownerDocument, TOOLBAR_BUTTON_ID);
|
||||
}
|
||||
|
||||
async _showElement(document, id, string_id) {
|
||||
_showElement(document, id, string_id) {
|
||||
const el = document.getElementById(id);
|
||||
await this._setTextAttribute(el, "label", { string_id });
|
||||
await this._setTextAttribute(el, "tooltiptext", { string_id });
|
||||
document.l10n.setAttributes(el, string_id);
|
||||
el.removeAttribute("hidden");
|
||||
}
|
||||
|
||||
|
@ -568,7 +565,7 @@ class _ToolbarPanelHub {
|
|||
triggerId: "protectionsPanelOpen",
|
||||
});
|
||||
if (message) {
|
||||
const messageEl = await this._createHeroElement(win, doc, message);
|
||||
const messageEl = this._createHeroElement(win, doc, message);
|
||||
container.appendChild(messageEl);
|
||||
infoButton.addEventListener("click", toggleMessage);
|
||||
this.sendUserEventTelemetry(win, "IMPRESSION", message);
|
||||
|
|
|
@ -77,6 +77,14 @@ add_task(async function test_with_rs_messages() {
|
|||
"The message container was not populated with the expected number of msgs"
|
||||
);
|
||||
|
||||
await BrowserTestUtils.waitForCondition(
|
||||
() =>
|
||||
document.querySelector(
|
||||
"#PanelUI-whatsNew-message-container .whatsNew-message-body remote-text"
|
||||
).shadowRoot.innerHTML,
|
||||
"Ensure messages have content"
|
||||
);
|
||||
|
||||
UITour.hideMenu(window, "appMenu");
|
||||
// Clean up and remove messages
|
||||
ToolbarPanelHub.disableAppmenuButton();
|
||||
|
|
|
@ -12,6 +12,7 @@ describe("ToolbarPanelHub", () => {
|
|||
let fakeWindow;
|
||||
let fakeElementById;
|
||||
let createdElements = [];
|
||||
let createdCustomElements = [];
|
||||
let eventListeners = {};
|
||||
let addObserverStub;
|
||||
let removeObserverStub;
|
||||
|
@ -24,6 +25,7 @@ describe("ToolbarPanelHub", () => {
|
|||
let getEventsByDateRangeStub;
|
||||
let handleUserActionStub;
|
||||
let defaultSearchStub;
|
||||
let scriptloaderStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
sandbox = sinon.createSandbox();
|
||||
|
@ -56,10 +58,34 @@ describe("ToolbarPanelHub", () => {
|
|||
},
|
||||
appendChild: sandbox.stub(),
|
||||
setAttribute: sandbox.stub(),
|
||||
textContent: "",
|
||||
};
|
||||
createdElements.push(element);
|
||||
return element;
|
||||
},
|
||||
createElement: tagName => {
|
||||
const element = {
|
||||
tagName,
|
||||
classList: {},
|
||||
addEventListener: (ev, fn) => {
|
||||
eventListeners[ev] = fn;
|
||||
},
|
||||
appendChild: sandbox.stub(),
|
||||
setAttribute: sandbox.stub(),
|
||||
textContent: "",
|
||||
};
|
||||
element.classList.add = sandbox.stub();
|
||||
element.classList.includes = className =>
|
||||
element.classList.add.firstCall.args[0] === className;
|
||||
createdCustomElements.push(element);
|
||||
return element;
|
||||
},
|
||||
l10n: {
|
||||
translateElements: sandbox.stub(),
|
||||
translateFragment: sandbox.stub(),
|
||||
formatMessages: sandbox.stub().resolves([{}]),
|
||||
setAttributes: sandbox.stub(),
|
||||
},
|
||||
};
|
||||
fakeWindow = {
|
||||
// eslint-disable-next-line object-shorthand
|
||||
|
@ -79,11 +105,13 @@ describe("ToolbarPanelHub", () => {
|
|||
panel: fakeElementById,
|
||||
whatsNewPanel: fakeElementById,
|
||||
},
|
||||
customElements: { get: sandbox.stub() },
|
||||
};
|
||||
everyWindowStub = {
|
||||
registerCallback: sandbox.stub(),
|
||||
unregisterCallback: sandbox.stub(),
|
||||
};
|
||||
scriptloaderStub = { loadSubScript: sandbox.stub() };
|
||||
addObserverStub = sandbox.stub();
|
||||
removeObserverStub = sandbox.stub();
|
||||
getBoolPrefStub = sandbox.stub();
|
||||
|
@ -108,6 +136,7 @@ describe("ToolbarPanelHub", () => {
|
|||
setBoolPref: setBoolPrefStub,
|
||||
},
|
||||
search: defaultSearchStub,
|
||||
scriptloader: scriptloaderStub,
|
||||
},
|
||||
PrivateBrowsingUtils: {
|
||||
isBrowserPrivate: isBrowserPrivateStub,
|
||||
|
@ -116,13 +145,6 @@ describe("ToolbarPanelHub", () => {
|
|||
getEarliestRecordedDate: getEarliestRecordedDateStub,
|
||||
getEventsByDateRange: getEventsByDateRangeStub,
|
||||
},
|
||||
RemoteL10n: {
|
||||
l10n: {
|
||||
translateElements: sandbox.stub(),
|
||||
translateFragment: sandbox.stub(),
|
||||
formatMessages: sandbox.stub().resolves([{}]),
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
afterEach(() => {
|
||||
|
@ -131,6 +153,7 @@ describe("ToolbarPanelHub", () => {
|
|||
globals.restore();
|
||||
eventListeners = {};
|
||||
createdElements = [];
|
||||
createdCustomElements = [];
|
||||
});
|
||||
it("should create an instance", () => {
|
||||
assert.ok(instance);
|
||||
|
@ -290,6 +313,32 @@ describe("ToolbarPanelHub", () => {
|
|||
handleUserAction: handleUserActionStub,
|
||||
});
|
||||
});
|
||||
it("should have correct state", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
);
|
||||
|
||||
getMessagesStub.returns(messages);
|
||||
const ev1 = sandbox.stub();
|
||||
ev1.withArgs("type").returns(1); // tracker
|
||||
ev1.withArgs("count").returns(4);
|
||||
const ev2 = sandbox.stub();
|
||||
ev2.withArgs("type").returns(4); // fingerprinter
|
||||
ev2.withArgs("count").returns(3);
|
||||
getEventsByDateRangeStub.returns([
|
||||
{ getResultByName: ev1 },
|
||||
{ getResultByName: ev2 },
|
||||
]);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.propertyVal(instance.state.contentArguments, "trackerCount", 4);
|
||||
assert.propertyVal(
|
||||
instance.state.contentArguments,
|
||||
"fingerprinterCount",
|
||||
3
|
||||
);
|
||||
});
|
||||
it("should render messages to the panel on renderMessages()", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
|
@ -311,19 +360,30 @@ describe("ToolbarPanelHub", () => {
|
|||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
for (let message of messages) {
|
||||
assert.ok(createdElements.find(el => el.tagName === "h2"));
|
||||
assert.ok(
|
||||
createdCustomElements.find(el =>
|
||||
el.classList.includes("whatsNew-message-title")
|
||||
)
|
||||
);
|
||||
if (message.content.layout === "tracking-protections") {
|
||||
assert.ok(createdElements.find(el => el.tagName === "h4"));
|
||||
assert.ok(
|
||||
createdCustomElements.find(el =>
|
||||
el.classList.includes("whatsNew-message-subtitle")
|
||||
)
|
||||
);
|
||||
}
|
||||
if (message.id === "WHATS_NEW_FINGERPRINTER_COUNTER_72") {
|
||||
assert.ok(createdElements.find(el => el.tagName === "h4"));
|
||||
assert.ok(
|
||||
createdElements.find(
|
||||
el => el.tagName === "h2" && el.textContent === 3
|
||||
)
|
||||
);
|
||||
}
|
||||
assert.ok(createdElements.find(el => el.tagName === "p"));
|
||||
assert.ok(
|
||||
createdCustomElements.find(el =>
|
||||
el.classList.includes("whatsNew-message-content")
|
||||
)
|
||||
);
|
||||
}
|
||||
// Call the click handler to make coverage happy.
|
||||
eventListeners.mouseup();
|
||||
|
@ -333,17 +393,18 @@ describe("ToolbarPanelHub", () => {
|
|||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
);
|
||||
const removeStub = sandbox.stub();
|
||||
fakeElementById.querySelectorAll.onCall(0).returns([]);
|
||||
fakeElementById.querySelectorAll.onCall(1).returns(["a", "b", "c"]);
|
||||
fakeElementById.querySelectorAll
|
||||
.onCall(1)
|
||||
.returns([{ remove: removeStub }, { remove: removeStub }]);
|
||||
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.calledThrice(fakeElementById.removeChild);
|
||||
assert.equal(fakeElementById.removeChild.firstCall.args[0], "a");
|
||||
assert.equal(fakeElementById.removeChild.secondCall.args[0], "b");
|
||||
assert.calledTwice(removeStub);
|
||||
});
|
||||
it("should sort based on order field value", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
|
@ -385,38 +446,7 @@ describe("ToolbarPanelHub", () => {
|
|||
"Firefox Send Logo"
|
||||
);
|
||||
});
|
||||
it("should accept fluent ids for image attributes", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.id === "WHATS_NEW_70_1"
|
||||
);
|
||||
messages[0].content.icon_alt = { string_id: "foo" };
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.calledWithExactly(global.RemoteL10n.l10n.formatMessages, [
|
||||
{
|
||||
id: "foo",
|
||||
args: instance.state.contentArguments,
|
||||
},
|
||||
]);
|
||||
});
|
||||
it("handle fluent attributes", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.id === "WHATS_NEW_70_1"
|
||||
);
|
||||
messages[0].content.icon_alt = { string_id: "foo" };
|
||||
getMessagesStub.returns(messages);
|
||||
global.RemoteL10n.l10n.formatMessages
|
||||
.withArgs([{ id: "foo", args: sinon.match.object }])
|
||||
.resolves([{ attributes: [{ name: "alt", value: "bar" }] }]);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
const imgEl = createdElements.find(e => e.tagName === "img");
|
||||
|
||||
assert.calledWithExactly(imgEl.setAttribute, "alt", "bar");
|
||||
});
|
||||
it("should accept fluent ids for elements attributes", async () => {
|
||||
it("should set state values as data-attribute", async () => {
|
||||
const [message] = (await PanelTestProvider.getMessages()).filter(
|
||||
m =>
|
||||
m.template === "whatsnew_panel_message" &&
|
||||
|
@ -427,102 +457,13 @@ describe("ToolbarPanelHub", () => {
|
|||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.calledWithExactly(global.RemoteL10n.l10n.formatMessages, [
|
||||
{
|
||||
id: message.content.subtitle.string_id,
|
||||
args: instance.state.contentArguments,
|
||||
},
|
||||
]);
|
||||
});
|
||||
it("should correctly compute blocker trackers and date", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
// Currently this.state.contentArguments has 9 different entries
|
||||
assert.callCount(createdCustomElements[0].setAttribute, 9);
|
||||
assert.calledWithExactly(
|
||||
createdCustomElements[0].setAttribute,
|
||||
"fluent-variable-searchEngineName",
|
||||
defaultSearchStub.defaultEngine.name
|
||||
);
|
||||
getMessagesStub.returns(messages);
|
||||
const ev1 = sandbox.stub();
|
||||
ev1.withArgs("type").returns(2); // cookie
|
||||
ev1.withArgs("count").returns(4);
|
||||
const ev2 = sandbox.stub();
|
||||
ev2.withArgs("type").returns(2); // cookie
|
||||
ev2.withArgs("count").returns(3);
|
||||
getEventsByDateRangeStub.returns([
|
||||
{ getResultByName: ev1 },
|
||||
{ getResultByName: ev2 },
|
||||
]);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.calledWithExactly(global.RemoteL10n.l10n.formatMessages, [
|
||||
{
|
||||
id: sinon.match.string,
|
||||
args: {
|
||||
blockedCount: 7,
|
||||
earliestDate: getEarliestRecordedDateStub(),
|
||||
cookieCount: 7,
|
||||
cryptominerCount: 0,
|
||||
socialCount: 0,
|
||||
trackerCount: 0,
|
||||
fingerprinterCount: 0,
|
||||
searchEngineName: Services.search.defaultEngine.name,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
it("should correctly compute event counts per type", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
);
|
||||
getMessagesStub.returns(messages);
|
||||
const ev1 = sandbox.stub();
|
||||
ev1.withArgs("type").returns(1); // tracker
|
||||
ev1.withArgs("count").returns(4);
|
||||
const ev2 = sandbox.stub();
|
||||
ev2.withArgs("type").returns(4); // fingerprinter
|
||||
ev2.withArgs("count").returns(3);
|
||||
getEventsByDateRangeStub.returns([
|
||||
{ getResultByName: ev1 },
|
||||
{ getResultByName: ev2 },
|
||||
]);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.calledWithExactly(global.RemoteL10n.l10n.formatMessages, [
|
||||
{
|
||||
id: sinon.match.string,
|
||||
args: {
|
||||
blockedCount: 7,
|
||||
earliestDate: getEarliestRecordedDateStub(),
|
||||
trackerCount: 4,
|
||||
fingerprinterCount: 3,
|
||||
cookieCount: 0,
|
||||
cryptominerCount: 0,
|
||||
socialCount: 0,
|
||||
searchEngineName: Services.search.defaultEngine.name,
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
it("should fallback to undefined search engine name", async () => {
|
||||
globals.set("Services", {
|
||||
...global.Services,
|
||||
search: { defaultEngine: null },
|
||||
});
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
m => m.template === "whatsnew_panel_message"
|
||||
);
|
||||
getMessagesStub.returns(messages);
|
||||
|
||||
await instance.renderMessages(fakeWindow, fakeDocument, "container-id");
|
||||
|
||||
assert.calledWithExactly(global.RemoteL10n.l10n.formatMessages, [
|
||||
{
|
||||
id: sinon.match.string,
|
||||
args: {
|
||||
...instance.state.contentArguments,
|
||||
searchEngineName: "undefined",
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
it("should only render unique dates (no duplicates)", async () => {
|
||||
const messages = (await PanelTestProvider.getMessages()).filter(
|
||||
|
@ -745,7 +686,6 @@ describe("ToolbarPanelHub", () => {
|
|||
it("should call removeMessages when forcing a message to show", () => {
|
||||
instance.forceShowMessage(browser, messages);
|
||||
|
||||
assert.calledOnce(removeMessagesSpy);
|
||||
assert.calledWithExactly(removeMessagesSpy, fakeWindow, panelSelector);
|
||||
});
|
||||
it("should call renderMessages when forcing a message to show", () => {
|
||||
|
|
|
@ -345,6 +345,7 @@ const TEST_GLOBAL = {
|
|||
},
|
||||
ww: { registerNotification() {}, unregisterNotification() {} },
|
||||
appinfo: { appBuildID: "20180710100040", version: "69.0a1" },
|
||||
scriptloader: { loadSubScript: () => {} },
|
||||
},
|
||||
XPCOMUtils: {
|
||||
defineLazyGetter(object, name, f) {
|
||||
|
|
|
@ -1854,6 +1854,11 @@ toolbarpaletteitem[place="menu-panel"] > .subviewbutton-nav::after {
|
|||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#protections-popup-message .protections-popup-content {
|
||||
display: block;
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
panelview[mainview] #PanelUI-whatsNew-content {
|
||||
height: 43em;
|
||||
}
|
||||
|
@ -1868,13 +1873,23 @@ panelview[mainview] #PanelUI-whatsNew-content {
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
#PanelUI-whatsNew .whatsNew-message:not(:first-child)::before {
|
||||
/* The following 2 rules show a 1 pixel line separator between What's New
|
||||
* messages while at the same time ensuring that the first message (which has
|
||||
* a date header) will not show the separator
|
||||
*/
|
||||
#PanelUI-whatsNew .whatsNew-message-body::before {
|
||||
content: "";
|
||||
display: block;
|
||||
height: 1px;
|
||||
width: 104%;
|
||||
margin-inline-start: -2%;
|
||||
background: var(--panel-separator-color);
|
||||
}
|
||||
|
||||
#PanelUI-whatsNew .whatsNew-message-date + .whatsNew-message-body::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#PanelUI-whatsNew .whatsNew-message-date {
|
||||
font-size: .85em;
|
||||
margin: 0 -12px;
|
||||
|
@ -1908,17 +1923,18 @@ panelview[mainview] #PanelUI-whatsNew-content {
|
|||
inset-inline-end: 6px;
|
||||
height: 32px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
top: 16px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
#PanelUI-whatsNew .whatsNew-message-title,
|
||||
#protections-popup-message .whatsNew-message-title {
|
||||
display: block;
|
||||
padding-inline-end: 46px;
|
||||
font-size: 1.3em;
|
||||
font-weight: 600;
|
||||
line-height: 1.4em;
|
||||
margin: 2px 0;
|
||||
margin: 8px 0 2px;
|
||||
}
|
||||
|
||||
#PanelUI-whatsNew .whatsNew-message-title-large {
|
||||
|
@ -1934,6 +1950,11 @@ panelview[mainview] #PanelUI-whatsNew-content {
|
|||
font-weight: normal;
|
||||
}
|
||||
|
||||
#PanelUI-whatsNew .whatsNew-message-content {
|
||||
display: block;
|
||||
margin: 13px 0;
|
||||
}
|
||||
|
||||
#PanelUI-whatsNew .text-link {
|
||||
background: none;
|
||||
border: 0;
|
||||
|
|
Загрузка…
Ссылка в новой задаче