Bug 1770447 - Create moz-support-link component. r=hjones,eemeli
This adds the <moz-support-link> custom element as well as stories and tests for this reusable component. The purpose of this component is to replace individual implementations of the "Learn more" links present in Firefox, specifically in about:preferences and about:addons. See Bug 1801927 for an instance of using this component to refactor the "Learn more" links in about:preferences#general. Differential Revision: https://phabricator.services.mozilla.com/D164131
This commit is contained in:
@@ -297,6 +297,10 @@ var whitelist = [
|
||||
|
||||
// References to esm generated from jsm programmatically
|
||||
{ file: "resource://gre/modules/LangPackMatcher.sys.mjs" },
|
||||
|
||||
// FIXME: Bug 1770447 - The moz-support-link component isn't in use yet.
|
||||
// This entry will be removed as part of Bug 1804695 or Bug 1804695.
|
||||
{ file: "chrome://global/content/elements/moz-support-link.mjs" },
|
||||
];
|
||||
|
||||
if (AppConstants.NIGHTLY_BUILD && AppConstants.platform != "win") {
|
||||
|
||||
6
browser/locales-preview/moz-support-link-storybook.ftl
Normal file
6
browser/locales-preview/moz-support-link-storybook.ftl
Normal file
@@ -0,0 +1,6 @@
|
||||
# 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/.
|
||||
|
||||
storybook-amo-test = Learn more about add-ons
|
||||
storybook-fluent-test = Learn more
|
||||
@@ -0,0 +1,5 @@
|
||||
# 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/.
|
||||
|
||||
moz-support-link-text = Learn more
|
||||
@@ -95,6 +95,7 @@ toolkit.jar:
|
||||
content/global/elements/moz-button-group.css (widgets/moz-button-group/moz-button-group.css)
|
||||
content/global/elements/moz-button-group.mjs (widgets/moz-button-group/moz-button-group.mjs)
|
||||
content/global/elements/moz-input-box.js (widgets/moz-input-box.js)
|
||||
content/global/elements/moz-support-link.mjs (widgets/moz-support-link/moz-support-link.mjs)
|
||||
content/global/elements/named-deck.js (widgets/named-deck.js)
|
||||
content/global/elements/notificationbox.js (widgets/notificationbox.js)
|
||||
content/global/elements/panel.js (widgets/panel.js)
|
||||
|
||||
@@ -8,6 +8,8 @@ support-files =
|
||||
window_label_checkbox.xhtml
|
||||
window_menubar.xhtml
|
||||
seek_with_sound.ogg
|
||||
prefs =
|
||||
app.support.baseURL='https://support.mozilla.org/'
|
||||
|
||||
[test_contextmenu_nested.xhtml]
|
||||
skip-if = os == 'linux' # Bug 1116215
|
||||
@@ -24,6 +26,7 @@ run-if = os == "mac" && os_version != "10.15" # Mac only feature, requires > 10.
|
||||
[test_menubar.xhtml]
|
||||
skip-if = os == 'mac'
|
||||
[test_moz_button_group.html]
|
||||
[test_moz_support_link.html]
|
||||
[test_popupanchor.xhtml]
|
||||
skip-if = os == 'linux' || (verify && (os == 'win')) # Bug 1335894 perma-fail on linux 16.04
|
||||
[test_popupreflows.xhtml]
|
||||
|
||||
83
toolkit/content/tests/widgets/test_moz_support_link.html
Normal file
83
toolkit/content/tests/widgets/test_moz_support_link.html
Normal file
@@ -0,0 +1,83 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>MozSupportLink tests</title>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<!-- TODO: Bug 1798404 - in-content/common.css can be removed once we have a better
|
||||
solution for token variables for the new widgets -->
|
||||
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
|
||||
<script type="module" src="chrome://global/content/elements/moz-support-link.mjs"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
<a
|
||||
id="testElement"
|
||||
is="moz-support-link"
|
||||
data-l10n-id="test"
|
||||
support-page="support-test"
|
||||
>testElement</a>
|
||||
|
||||
<a
|
||||
id="testElement2"
|
||||
is="moz-support-link"
|
||||
data-l10n-id="test2"
|
||||
support-page="support-test"
|
||||
utm-content="utmcontent-test"
|
||||
>testElement2</a>
|
||||
</div>
|
||||
<pre id="test"></pre>
|
||||
<script>
|
||||
const { Assert } = ChromeUtils.import("resource://testing-common/Assert.jsm");
|
||||
add_task(async function test_component_declaration() {
|
||||
let mozSupportLink = customElements.get("moz-support-link");
|
||||
let supportUrl = mozSupportLink.SUPPORT_URL;
|
||||
|
||||
// Ensure all the semantics of the primary link are present
|
||||
let supportLink = document.getElementById("testElement");
|
||||
is(supportLink.tagName, "A", "tagName should be 'A'");
|
||||
is(supportLink.getAttribute("is"), "moz-support-link", "Generated anchor should be a 'moz-support-link'");
|
||||
is(supportLink.getAttribute("data-l10n-id"), "test", "data-l10n-id should be 'test'");
|
||||
is(supportLink.getAttribute("support-page"), "support-test", "support-page should be 'support-test");
|
||||
is(supportLink.target, "_blank", "support link should open a new window");
|
||||
is(supportLink.href, `${supportUrl}support-test`, "href should be generated SUPPORT_URL plus support-test");
|
||||
|
||||
// Ensure AMO support link has the correct values
|
||||
let supportLinkAMO = document.getElementById("testElement2");
|
||||
is(supportLinkAMO.getAttribute("data-l10n-id"), "test2", "data-l10n-id should be 'test2'");
|
||||
is(supportLinkAMO.getAttribute("support-page"), "support-test", "support-page should be 'support-test");
|
||||
is(supportLinkAMO.getAttribute("utm-content"), "utmcontent-test", "utm-content should be 'utmcontent-test");
|
||||
is(supportLinkAMO.target, "_blank", "support link should open a new window");
|
||||
let expectedHref = `${supportUrl}support-test?utm_source=firefox-browser&utm_medium=firefox-browser&utm_content=utmcontent-test`;
|
||||
is(supportLinkAMO.href, expectedHref, "href should be generated SUPPORT_URL");
|
||||
});
|
||||
|
||||
add_task(async function test_creating_component() {
|
||||
// Ensure created support link behaves as expected
|
||||
let mozSupportLink = customElements.get("moz-support-link");
|
||||
let supportUrl = mozSupportLink.SUPPORT_URL;
|
||||
let content = document.getElementById("content");
|
||||
let utmSupportLink = document.createElement("a", {is: "moz-support-link"});
|
||||
utmSupportLink.id = "testElement3";
|
||||
utmSupportLink.innerText = "testElement3";
|
||||
document.l10n.setAttributes(utmSupportLink, "testElement3");
|
||||
content.appendChild(utmSupportLink);
|
||||
|
||||
is(utmSupportLink.target, "_blank", "support link should open a new window");
|
||||
is(utmSupportLink.href, supportUrl, "href should be the base SUPPORT_URL");
|
||||
is(utmSupportLink.getAttribute("data-l10n-id"), "testElement3", "data-l10n-id should be 'testElement3'");
|
||||
|
||||
// Set href via "support-page" after creating the element
|
||||
utmSupportLink.setAttribute("support-page", "created-page");
|
||||
is(utmSupportLink.href, `${supportUrl}created-page`, "href should be updated after setting the 'support-page' attribute");
|
||||
|
||||
// Set href via "utm-content"
|
||||
utmSupportLink.href = "";
|
||||
utmSupportLink.setAttribute("utm-content", "created-content");
|
||||
is(utmSupportLink.href, `${supportUrl}created-page?utm_source=firefox-browser&utm_medium=firefox-browser&utm_content=created-content`, "href should be updated after setting the 'utm-content' attribute");
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,92 @@
|
||||
/* 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/. */
|
||||
|
||||
MozXULElement.insertFTLIfNeeded("browser/components/mozSupportLink.ftl");
|
||||
|
||||
export default class MozSupportLink extends HTMLAnchorElement {
|
||||
static SUPPORT_URL = "https://www.mozilla.org/";
|
||||
static get observedAttributes() {
|
||||
return ["support-page", "utm-content", "data-l10n-id"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles setting up the SUPPORT_URL preference getter.
|
||||
* Without this, the tests for this component may not behave
|
||||
* as expected.
|
||||
* @private
|
||||
* @memberof MozSupportLink
|
||||
*/
|
||||
#register() {
|
||||
if (!window.IS_STORYBOOK) {
|
||||
let { XPCOMUtils } = window.XPCOMUtils
|
||||
? window
|
||||
: ChromeUtils.importESModule(
|
||||
"resource://gre/modules/XPCOMUtils.sys.mjs"
|
||||
);
|
||||
XPCOMUtils.defineLazyPreferenceGetter(
|
||||
MozSupportLink,
|
||||
"SUPPORT_URL",
|
||||
"app.support.baseURL",
|
||||
"",
|
||||
null,
|
||||
val => Services.urlFormatter.formatURL(val)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.#register();
|
||||
this.#setHref();
|
||||
this.setAttribute("target", "_blank");
|
||||
if (!this.getAttribute("data-l10n-id")) {
|
||||
document.l10n.setAttributes(this, "moz-support-link-text");
|
||||
document.l10n.translateFragment(this);
|
||||
}
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldVal, newVal) {
|
||||
if (name === "support-page" || name === "utm-content") {
|
||||
this.#setHref();
|
||||
}
|
||||
}
|
||||
|
||||
#setHref() {
|
||||
let supportPage = this.getAttribute("support-page") ?? "";
|
||||
let base = MozSupportLink.SUPPORT_URL + supportPage;
|
||||
this.href = this.hasAttribute("utm-content")
|
||||
? formatUTMParams(this.getAttribute("utm-content"), base)
|
||||
: base;
|
||||
}
|
||||
}
|
||||
customElements.define("moz-support-link", MozSupportLink, { extends: "a" });
|
||||
|
||||
/**
|
||||
* Adds UTM parameters to a given URL, if it is an AMO URL.
|
||||
*
|
||||
* @param {string} contentAttribute
|
||||
* Identifies the part of the UI with which the link is associated.
|
||||
* @param {string} url
|
||||
* @returns {string}
|
||||
* The url with UTM parameters if it is an AMO URL.
|
||||
* Otherwise the url in unmodified form.
|
||||
*/
|
||||
export function formatUTMParams(contentAttribute, url) {
|
||||
if (!contentAttribute) {
|
||||
return url;
|
||||
}
|
||||
let parsedUrl = new URL(url);
|
||||
let domain = `.${parsedUrl.hostname}`;
|
||||
if (
|
||||
!domain.endsWith(".mozilla.org") &&
|
||||
// For testing: addons-dev.allizom.org and addons.allizom.org
|
||||
!domain.endsWith(".allizom.org")
|
||||
) {
|
||||
return url;
|
||||
}
|
||||
|
||||
parsedUrl.searchParams.set("utm_source", "firefox-browser");
|
||||
parsedUrl.searchParams.set("utm_medium", "firefox-browser");
|
||||
parsedUrl.searchParams.set("utm_content", contentAttribute);
|
||||
return parsedUrl.href;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/* 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/. */
|
||||
|
||||
import { html, ifDefined } from "../vendor/lit.all.mjs";
|
||||
// eslint-disable-next-line import/no-unassigned-import
|
||||
import "./moz-support-link.mjs";
|
||||
|
||||
MozXULElement.insertFTLIfNeeded(
|
||||
"locales-preview/moz-support-link-storybook.ftl"
|
||||
);
|
||||
MozXULElement.insertFTLIfNeeded("browser/components/mozSupportLink.ftl");
|
||||
|
||||
const fluentStrings = [
|
||||
"storybook-amo-test",
|
||||
"storybook-fluent-test",
|
||||
"moz-support-link-text",
|
||||
];
|
||||
|
||||
export default {
|
||||
title: "Design System/Experiments/MozSupportLink",
|
||||
argTypes: {
|
||||
dataL10nId: {
|
||||
type: "string",
|
||||
options: [fluentStrings[0], fluentStrings[1], fluentStrings[2]],
|
||||
control: { type: "select" },
|
||||
description: "Fluent ID used to generate the text content.",
|
||||
},
|
||||
supportPage: {
|
||||
type: "string",
|
||||
description:
|
||||
"Short-hand string from SUMO to the specific support page. **Note:** changing this will not create a valid URL since we don't have access to the generated support link used in Firefox",
|
||||
},
|
||||
utmContent: {
|
||||
type: "string",
|
||||
description:
|
||||
"UTM parameter for a URL, if it is an AMO URL. **Note:** changing this will not create a valid URL since we don't have access to the generated support link used in Firefox",
|
||||
},
|
||||
onClick: { action: "clicked" },
|
||||
},
|
||||
};
|
||||
|
||||
const Template = ({ dataL10nId, supportPage, utmContent }) => html`
|
||||
<a
|
||||
is="moz-support-link"
|
||||
data-l10n-id=${ifDefined(dataL10nId)}
|
||||
support-page=${ifDefined(supportPage)}
|
||||
utm-content=${ifDefined(utmContent)}
|
||||
>
|
||||
</a>
|
||||
`;
|
||||
|
||||
export const withAMOUrl = Template.bind({});
|
||||
withAMOUrl.args = {
|
||||
dataL10nId: fluentStrings[0],
|
||||
supportPage: "addons",
|
||||
utmContent: "promoted-addon-badge",
|
||||
};
|
||||
|
||||
export const Primary = Template.bind({});
|
||||
Primary.args = {
|
||||
supportPage: "preferences",
|
||||
};
|
||||
|
||||
export const withFluentId = Template.bind({});
|
||||
withFluentId.args = {
|
||||
dataL10nId: fluentStrings[1],
|
||||
supportPage: "preferences",
|
||||
};
|
||||
Reference in New Issue
Block a user