зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1571022 - Conditional rendering for CFR feature recommendations r=k88hudson
Differential Revision: https://phabricator.services.mozilla.com/D43630 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
8682c94a42
Коммит
95146c9c2f
|
@ -1346,7 +1346,7 @@ class _ASRouter {
|
|||
} else {
|
||||
CFRPageActions.addRecommendation(
|
||||
target,
|
||||
trigger.param.host,
|
||||
trigger.param && trigger.param.host,
|
||||
message,
|
||||
this.dispatch
|
||||
);
|
||||
|
|
|
@ -126,6 +126,7 @@ const CFR_MESSAGES = [
|
|||
id: "FACEBOOK_CONTAINER_3",
|
||||
template: "cfr_doorhanger",
|
||||
content: {
|
||||
layout: "addon_recommendation",
|
||||
category: "cfrAddons",
|
||||
bucket_id: "CFR_M1",
|
||||
notification_text: { string_id: "cfr-doorhanger-extension-notification" },
|
||||
|
@ -194,6 +195,7 @@ const CFR_MESSAGES = [
|
|||
id: "GOOGLE_TRANSLATE_3",
|
||||
template: "cfr_doorhanger",
|
||||
content: {
|
||||
layout: "addon_recommendation",
|
||||
category: "cfrAddons",
|
||||
bucket_id: "CFR_M1",
|
||||
notification_text: { string_id: "cfr-doorhanger-extension-notification" },
|
||||
|
@ -263,6 +265,7 @@ const CFR_MESSAGES = [
|
|||
id: "YOUTUBE_ENHANCE_3",
|
||||
template: "cfr_doorhanger",
|
||||
content: {
|
||||
layout: "addon_recommendation",
|
||||
category: "cfrAddons",
|
||||
bucket_id: "CFR_M1",
|
||||
notification_text: { string_id: "cfr-doorhanger-extension-notification" },
|
||||
|
@ -333,6 +336,7 @@ const CFR_MESSAGES = [
|
|||
template: "cfr_doorhanger",
|
||||
exclude: true,
|
||||
content: {
|
||||
layout: "addon_recommendation",
|
||||
category: "cfrAddons",
|
||||
bucket_id: "CFR_M1",
|
||||
notification_text: { string_id: "cfr-doorhanger-extension-notification" },
|
||||
|
@ -406,6 +410,7 @@ const CFR_MESSAGES = [
|
|||
template: "cfr_doorhanger",
|
||||
exclude: true,
|
||||
content: {
|
||||
layout: "addon_recommendation",
|
||||
category: "cfrAddons",
|
||||
bucket_id: "CFR_M1",
|
||||
notification_text: { string_id: "cfr-doorhanger-extension-notification" },
|
||||
|
@ -475,6 +480,7 @@ const CFR_MESSAGES = [
|
|||
id: "PIN_TAB",
|
||||
template: "cfr_doorhanger",
|
||||
content: {
|
||||
layout: "message_and_animation",
|
||||
category: "cfrFeatures",
|
||||
bucket_id: "CFR_PIN_TAB",
|
||||
notification_text: { string_id: "cfr-doorhanger-extension-notification" },
|
||||
|
@ -526,6 +532,78 @@ const CFR_MESSAGES = [
|
|||
frequency: { lifetime: 3 },
|
||||
trigger: { id: "frequentVisits", params: PINNED_TABS_TARGET_SITES },
|
||||
},
|
||||
{
|
||||
id: "SAVE_LOGIN",
|
||||
frequency: {
|
||||
lifetime: 3,
|
||||
},
|
||||
targeting: "usesFirefoxSync == false",
|
||||
template: "cfr_doorhanger",
|
||||
last_modified: 1565907636313,
|
||||
content: {
|
||||
layout: "icon_and_message",
|
||||
text: {
|
||||
string_id: "cfr-doorhanger-sync-logins-body",
|
||||
},
|
||||
icon: "chrome://browser/content/aboutlogins/icons/intro-illustration.svg",
|
||||
buttons: {
|
||||
secondary: [
|
||||
{
|
||||
label: {
|
||||
string_id: "cfr-doorhanger-extension-cancel-button",
|
||||
},
|
||||
action: {
|
||||
type: "CANCEL",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: {
|
||||
string_id: "cfr-doorhanger-extension-never-show-recommendation",
|
||||
},
|
||||
},
|
||||
{
|
||||
label: {
|
||||
string_id: "cfr-doorhanger-extension-manage-settings-button",
|
||||
},
|
||||
action: {
|
||||
type: "OPEN_PREFERENCES_PAGE",
|
||||
data: {
|
||||
category: "general-cfrfeatures",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
primary: {
|
||||
label: {
|
||||
string_id: "cfr-doorhanger-sync-logins-ok-button",
|
||||
},
|
||||
action: {
|
||||
type: "OPEN_PREFERENCES_PAGE",
|
||||
data: {
|
||||
category: "sync",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
bucket_id: "CFR_SAVE_LOGIN",
|
||||
heading_text: {
|
||||
string_id: "cfr-doorhanger-sync-logins-header",
|
||||
},
|
||||
info_icon: {
|
||||
label: {
|
||||
string_id: "cfr-doorhanger-extension-sumo-link",
|
||||
},
|
||||
sumo_path: "extensionrecommendations",
|
||||
},
|
||||
notification_text: {
|
||||
string_id: "cfr-doorhanger-extension-notification",
|
||||
},
|
||||
category: "cfrFeatures",
|
||||
},
|
||||
trigger: {
|
||||
id: "newSavedLogin",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const CFRMessageProvider = {
|
||||
|
|
|
@ -428,6 +428,7 @@ class PageAction {
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-statements
|
||||
async _renderPopup(message, browser) {
|
||||
const { id, content } = message;
|
||||
|
||||
|
@ -451,12 +452,6 @@ class PageAction {
|
|||
let options = {};
|
||||
let panelTitle;
|
||||
|
||||
// Use the message category as a CSS selector to hide different parts of the
|
||||
// notification template markup
|
||||
this.window.document
|
||||
.getElementById("contextual-feature-recommendation-notification")
|
||||
.setAttribute("data-notification-category", message.content.category);
|
||||
|
||||
headerLabel.value = await this.getStrings(content.heading_text);
|
||||
headerLink.setAttribute(
|
||||
"href",
|
||||
|
@ -473,12 +468,80 @@ class PageAction {
|
|||
bucket_id: content.bucket_id,
|
||||
event: "RATIONALE",
|
||||
});
|
||||
// Use the message layout as a CSS selector to hide different parts of the
|
||||
// notification template markup
|
||||
this.window.document
|
||||
.getElementById("contextual-feature-recommendation-notification")
|
||||
.setAttribute("data-notification-category", content.layout);
|
||||
|
||||
switch (content.layout) {
|
||||
case "icon_and_message":
|
||||
const author = this.window.document.getElementById(
|
||||
"cfr-notification-author"
|
||||
);
|
||||
author.textContent = await this.getStrings(content.text);
|
||||
primaryActionCallback = () => {
|
||||
this._blockMessage(id);
|
||||
this.dispatchUserAction(primary.action);
|
||||
this.hideAddressBarNotifier();
|
||||
this._sendTelemetry({
|
||||
message_id: id,
|
||||
bucket_id: content.bucket_id,
|
||||
event: "ENABLE",
|
||||
});
|
||||
RecommendationMap.delete(browser);
|
||||
};
|
||||
panelTitle = await this.getStrings(content.heading_text);
|
||||
options = {
|
||||
popupIconURL: content.icon,
|
||||
popupIconClass: "cfr-doorhanger-large-icon",
|
||||
};
|
||||
break;
|
||||
case "message_and_animation":
|
||||
footerText.textContent = await this.getStrings(content.text);
|
||||
const stepsContainerId = "cfr-notification-feature-steps";
|
||||
let stepsContainer = this.window.document.getElementById(
|
||||
stepsContainerId
|
||||
);
|
||||
primaryActionCallback = () => {
|
||||
this._blockMessage(id);
|
||||
this.dispatchUserAction(primary.action);
|
||||
this.hideAddressBarNotifier();
|
||||
this._sendTelemetry({
|
||||
message_id: id,
|
||||
bucket_id: content.bucket_id,
|
||||
event: "PIN",
|
||||
});
|
||||
RecommendationMap.delete(browser);
|
||||
};
|
||||
panelTitle = await this.getStrings(content.heading_text);
|
||||
|
||||
if (content.addon) {
|
||||
await this._setAddonAuthorAndRating(this.window.document, content);
|
||||
if (content.descriptionDetails) {
|
||||
if (stepsContainer) {
|
||||
// If it exists we need to empty it
|
||||
stepsContainer.remove();
|
||||
stepsContainer = stepsContainer.cloneNode(false);
|
||||
} else {
|
||||
stepsContainer = this.window.document.createXULElement("vbox");
|
||||
stepsContainer.setAttribute("id", stepsContainerId);
|
||||
}
|
||||
footerText.parentNode.appendChild(stepsContainer);
|
||||
for (let step of content.descriptionDetails.steps) {
|
||||
// This li is a generic xul element with custom styling
|
||||
const li = this.window.document.createXULElement("li");
|
||||
this._l10n.setAttributes(li, step.string_id);
|
||||
stepsContainer.appendChild(li);
|
||||
}
|
||||
await this._l10n.translateElements([...stepsContainer.children]);
|
||||
}
|
||||
|
||||
await this._renderPinTabAnimation();
|
||||
break;
|
||||
default:
|
||||
panelTitle = await this.getStrings(content.addon.title);
|
||||
await this._setAddonAuthorAndRating(this.window.document, content);
|
||||
// Main body content of the dropdown
|
||||
footerText.textContent = await this.getStrings(content.text);
|
||||
options = { popupIconURL: content.addon.icon };
|
||||
|
||||
footerLink.value = await this.getStrings({
|
||||
|
@ -507,42 +570,6 @@ class PageAction {
|
|||
});
|
||||
RecommendationMap.delete(browser);
|
||||
};
|
||||
} else {
|
||||
const stepsContainerId = "cfr-notification-feature-steps";
|
||||
let stepsContainer = this.window.document.getElementById(
|
||||
stepsContainerId
|
||||
);
|
||||
primaryActionCallback = () => {
|
||||
this._blockMessage(id);
|
||||
this.dispatchUserAction(primary.action);
|
||||
this.hideAddressBarNotifier();
|
||||
this._sendTelemetry({
|
||||
message_id: id,
|
||||
bucket_id: content.bucket_id,
|
||||
event: "PIN",
|
||||
});
|
||||
RecommendationMap.delete(browser);
|
||||
};
|
||||
panelTitle = await this.getStrings(content.heading_text);
|
||||
|
||||
if (stepsContainer) {
|
||||
// If it exists we need to empty it
|
||||
stepsContainer.remove();
|
||||
stepsContainer = stepsContainer.cloneNode(false);
|
||||
} else {
|
||||
stepsContainer = this.window.document.createXULElement("vbox");
|
||||
stepsContainer.setAttribute("id", stepsContainerId);
|
||||
}
|
||||
footerText.parentNode.appendChild(stepsContainer);
|
||||
for (let step of content.descriptionDetails.steps) {
|
||||
// This li is a generic xul element with custom styling
|
||||
const li = this.window.document.createXULElement("li");
|
||||
this._l10n.setAttributes(li, step.string_id);
|
||||
stepsContainer.appendChild(li);
|
||||
}
|
||||
await this._l10n.translateElements([...stepsContainer.children]);
|
||||
|
||||
await this._renderPinTabAnimation();
|
||||
}
|
||||
|
||||
const primaryBtnStrings = await this.getStrings(primary.label);
|
||||
|
@ -749,7 +776,8 @@ const CFRPageActions = {
|
|||
}
|
||||
if (
|
||||
browser !== win.gBrowser.selectedBrowser ||
|
||||
!isHostMatch(browser, host)
|
||||
// We can have recommendations without URL restrictions
|
||||
(host && !isHostMatch(browser, host))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -8,8 +8,14 @@ const { ASRouter } = ChromeUtils.import(
|
|||
"resource://activity-stream/lib/ASRouter.jsm"
|
||||
);
|
||||
|
||||
const createDummyRecommendation = ({ action, category, heading_text }) => ({
|
||||
const createDummyRecommendation = ({
|
||||
action,
|
||||
category,
|
||||
heading_text,
|
||||
layout,
|
||||
}) => ({
|
||||
content: {
|
||||
layout: layout || "addon_recommendation",
|
||||
category,
|
||||
notification_text: "Mochitest",
|
||||
heading_text: heading_text || "Mochitest",
|
||||
|
@ -63,9 +69,10 @@ const createDummyRecommendation = ({ action, category, heading_text }) => ({
|
|||
|
||||
function checkCFRFeaturesElements(notification) {
|
||||
Assert.ok(notification.hidden === false, "Panel should be visible");
|
||||
Assert.ok(
|
||||
notification.getAttribute("data-notification-category") === "cfrFeatures",
|
||||
"Panel have corret data attribute"
|
||||
Assert.equal(
|
||||
notification.getAttribute("data-notification-category"),
|
||||
"message_and_animation",
|
||||
"Panel have correct data attribute"
|
||||
);
|
||||
Assert.ok(
|
||||
notification.querySelector(
|
||||
|
@ -81,9 +88,10 @@ function checkCFRFeaturesElements(notification) {
|
|||
|
||||
function checkCFRAddonsElements(notification) {
|
||||
Assert.ok(notification.hidden === false, "Panel should be visible");
|
||||
Assert.ok(
|
||||
notification.getAttribute("data-notification-category") === "cfrAddons",
|
||||
"Panel have corret data attribute"
|
||||
Assert.equal(
|
||||
notification.getAttribute("data-notification-category"),
|
||||
"addon_recommendation",
|
||||
"Panel have correct data attribute"
|
||||
);
|
||||
Assert.ok(
|
||||
notification.querySelector("#cfr-notification-footer-text-and-addon-info"),
|
||||
|
@ -115,13 +123,19 @@ function clearNotifications() {
|
|||
function trigger_cfr_panel(
|
||||
browser,
|
||||
trigger,
|
||||
{ action = { type: "FOO" }, heading_text, category = "cfrAddons" } = {}
|
||||
{
|
||||
action = { type: "FOO" },
|
||||
heading_text,
|
||||
category = "cfrAddons",
|
||||
layout,
|
||||
} = {}
|
||||
) {
|
||||
// a fake action type will result in the action being ignored
|
||||
const recommendation = createDummyRecommendation({
|
||||
action,
|
||||
category,
|
||||
heading_text,
|
||||
layout,
|
||||
});
|
||||
if (category !== "cfrAddons") {
|
||||
delete recommendation.content.addon;
|
||||
|
@ -340,6 +354,7 @@ add_task(async function test_cfr_pin_tab_notification_show() {
|
|||
const response = await trigger_cfr_panel(browser, "example.com", {
|
||||
action: { type: "PIN_CURRENT_TAB" },
|
||||
category: "cfrFeatures",
|
||||
layout: "message_and_animation",
|
||||
});
|
||||
Assert.ok(
|
||||
response,
|
||||
|
@ -395,6 +410,7 @@ add_task(async function test_cfr_features_and_addon_show() {
|
|||
let response = await trigger_cfr_panel(browser, "example.com", {
|
||||
action: { type: "PIN_CURRENT_TAB" },
|
||||
category: "cfrFeatures",
|
||||
layout: "message_and_animation",
|
||||
});
|
||||
Assert.ok(
|
||||
response,
|
||||
|
@ -522,7 +538,7 @@ add_task(async function test_cfr_addon_and_features_show() {
|
|||
// Trigger Addon CFR
|
||||
response = await trigger_cfr_panel(browser, "example.com", {
|
||||
action: { type: "PIN_CURRENT_TAB" },
|
||||
category: "cfrFeatures",
|
||||
category: "cfrAddons",
|
||||
});
|
||||
Assert.ok(
|
||||
response,
|
||||
|
@ -542,7 +558,7 @@ add_task(async function test_cfr_addon_and_features_show() {
|
|||
.hidden === false,
|
||||
"Panel should be visible"
|
||||
);
|
||||
checkCFRFeaturesElements(
|
||||
checkCFRAddonsElements(
|
||||
document.getElementById("contextual-feature-recommendation-notification")
|
||||
);
|
||||
|
||||
|
|
|
@ -238,6 +238,11 @@
|
|||
margin-inline-end: 4px;
|
||||
}
|
||||
|
||||
#contextual-feature-recommendation-notification .cfr-doorhanger-large-icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
#contextual-feature-recommendation-notification .popup-notification-body-container {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
@ -257,12 +262,35 @@
|
|||
font-size: 13px;
|
||||
}
|
||||
|
||||
#contextual-feature-recommendation-notification[data-notification-category="cfrFeatures"] .popup-notification-body-container,
|
||||
#contextual-feature-recommendation-notification[data-notification-category="cfrFeatures"] #cfr-notification-footer-addon-info,
|
||||
#contextual-feature-recommendation-notification[data-notification-category="cfrAddons"] #cfr-notification-feature-steps {
|
||||
#contextual-feature-recommendation-notification[data-notification-category="message_and_animation"] .popup-notification-body-container,
|
||||
#contextual-feature-recommendation-notification[data-notification-category="message_and_animation"] #cfr-notification-footer-addon-info,
|
||||
#contextual-feature-recommendation-notification[data-notification-category="addon_recommendation"] #cfr-notification-feature-steps,
|
||||
#contextual-feature-recommendation-notification[data-notification-category="icon_and_message"] .popup-notification-footer-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/*
|
||||
* `icon_and_message` CFR doorhanger with: icon, title and subtitle.
|
||||
* No panel header is shown
|
||||
*/
|
||||
#contextual-feature-recommendation-notification[data-notification-category="icon_and_message"] #cfr-notification-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#contextual-feature-recommendation-notification[data-notification-category="icon_and_message"] .popup-notification-description {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
#contextual-feature-recommendation-notification[data-notification-category="icon_and_message"] popupnotificationcontent {
|
||||
display: block; /* This forces the subtitle content to wrap */
|
||||
}
|
||||
|
||||
#contextual-feature-recommendation-notification[data-notification-category="icon_and_message"] .popup-notification-body-container {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
#cfr-notification-feature-steps {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
@ -284,7 +312,7 @@
|
|||
inset-inline-start: 0;
|
||||
}
|
||||
|
||||
#contextual-feature-recommendation-notification[data-notification-category="cfrFeatures"] #cfr-notification-footer-text {
|
||||
#contextual-feature-recommendation-notification[data-notification-category="message_and_animation"] #cfr-notification-footer-text {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
@ -370,7 +398,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
#contextual-feature-recommendation-notification[data-notification-category="cfrAddons"] #cfr-notification-footer-pintab-animation-container {
|
||||
#contextual-feature-recommendation-notification[data-notification-category="addon_recommendation"] #cfr-notification-footer-pintab-animation-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче