зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1408334 - add form to subscribe to mozilla developer newsletter in about:devtools;r=nchevobbe
MozReview-Commit-ID: JuJqNS3r6NH --HG-- extra : rebase_source : 20b9f294cb60873bfa6edc975d4688c1a2365eef
This commit is contained in:
Родитель
d39f5742f5
Коммит
10e099779f
|
@ -1,3 +1,7 @@
|
|||
/* 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/. */
|
||||
|
||||
:root {
|
||||
/* Photon color variables used on the aboutdevtools page */
|
||||
--blue-60: #0060df;
|
||||
|
@ -8,7 +12,14 @@
|
|||
--grey-90-alpha-10: rgba(12, 12, 13, 0.1);
|
||||
--grey-90-alpha-20: rgba(12, 12, 13, 0.2);
|
||||
--grey-90-alpha-30: rgba(12, 12, 13, 0.3);
|
||||
--grey-90-alpha-40: rgba(12, 12, 13, 0.4);
|
||||
--grey-90-alpha-50: rgba(12, 12, 13, 0.5);
|
||||
--teal-60: #00c8d7;
|
||||
--red-50: #ff0039;
|
||||
--white: #ffffff;
|
||||
|
||||
/* Shared variables */
|
||||
--line-height: 1.5em;
|
||||
}
|
||||
|
||||
html, body {
|
||||
|
@ -17,16 +28,15 @@ html, body {
|
|||
}
|
||||
|
||||
p {
|
||||
line-height: 1.5em;
|
||||
line-height: var(--line-height);
|
||||
}
|
||||
|
||||
.box {
|
||||
width: 100%;
|
||||
max-width: 850px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 400px;
|
||||
flex-shrink: 0;
|
||||
padding: 34px 0 50px 0;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
|
@ -38,19 +48,16 @@ p {
|
|||
}
|
||||
|
||||
.left-pane {
|
||||
width: 360px;
|
||||
height: 100%;
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
margin-inline-end: 20px;
|
||||
background-image: url(images/otter.svg);
|
||||
background-size: 80%;
|
||||
background-size: 100%;
|
||||
background-position: 50%;
|
||||
background-repeat: no-repeat;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.right-pane {
|
||||
height: 250px;
|
||||
}
|
||||
|
||||
.features {
|
||||
max-width: 980px;
|
||||
border-top: 1px solid var(--grey-30);
|
||||
|
@ -129,7 +136,7 @@ p {
|
|||
}
|
||||
|
||||
button {
|
||||
margin: 2em 0 0 0;
|
||||
margin: 20px 0 0 0;
|
||||
padding: 10px 20px;
|
||||
|
||||
border: none;
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>a
|
||||
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools-shim/content/aboutdevtools/aboutdevtools.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://devtools-shim/content/aboutdevtools/subscribe.css" type="text/css"/>
|
||||
<script type="application/javascript" src="chrome://devtools-shim/content/aboutdevtools/aboutdevtools.js"></script>
|
||||
<script type="application/javascript" src="chrome://devtools-shim/content/aboutdevtools/subscribe.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="install-page" class="wrapper" hidden="true">
|
||||
|
@ -48,6 +50,33 @@
|
|||
<div class="right-pane">
|
||||
<h1 class="title" >&aboutDevtools.welcome.title;</h1>
|
||||
<p id="welcome-message">&aboutDevtools.welcome.message;</p>
|
||||
|
||||
<!-- Form dedicated to the newsletter subscription -->
|
||||
<div class="newsletter">
|
||||
<h2 class="newsletter-title">&aboutDevtools.newsletter.title;</h2>
|
||||
<p>&aboutDevtools.newsletter.message;</p>
|
||||
|
||||
<form id="newsletter-form" name="newsletter-form" action="https://www.mozilla.org/en-US/newsletter/" method="post">
|
||||
<!-- "H" stands for the HTML format (->fmt). Alternative is T for text. -->
|
||||
<input type="hidden" id="fmt" name="fmt" value="H" />
|
||||
<!-- "app-dev" is the id of the Mozilla Developper newsletter -->
|
||||
<input type="hidden" id="newsletters" name="newsletters" value="app-dev" />
|
||||
<div id="newsletter-errors"></div>
|
||||
<section id="newsletter-email" class="newsletter-form-section">
|
||||
<input type="email" id="email" name="email" required="true" placeholder="&aboutDevtools.newsletter.email.placeholder;" />
|
||||
</section>
|
||||
|
||||
<section id="newsletter-privacy" class="newsletter-form-section">
|
||||
<input type="checkbox" id="privacy" name="privacy" required="true" />
|
||||
<label for="privacy">&aboutDevtools.newsletter.privacy.label;</label>
|
||||
</section>
|
||||
<button type="submit" id="newsletter-submit" class="primary-button">&aboutDevtools.newsletter.subscribe.label;</button>
|
||||
</form>
|
||||
<div id="newsletter-thanks">
|
||||
<h2>&aboutDevtools.newsletter.thanks.title;</h2>
|
||||
<p>&aboutDevtools.newsletter.thanks.message;</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
/* 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/. */
|
||||
|
||||
/**
|
||||
* This file contains the styles for the newsletter subscription form on about:devtools.
|
||||
* It is largely inspired from https://mozilla.github.io/basket-example/
|
||||
*/
|
||||
|
||||
#newsletter-errors {
|
||||
/* Hidden by default */
|
||||
display: none;
|
||||
|
||||
margin-bottom: 20px;
|
||||
padding: 10px;
|
||||
border-radius: 2px;
|
||||
|
||||
background-color: var(--red-50);
|
||||
color: var(--white);
|
||||
}
|
||||
|
||||
#newsletter-errors.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#newsletter-errors .error {
|
||||
margin: 0;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
#newsletter-errors .error:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#newsletter-thanks {
|
||||
/* Hidden by default */
|
||||
display: none;
|
||||
}
|
||||
|
||||
#newsletter-thanks.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.newsletter-form-section {
|
||||
display: block;
|
||||
margin-bottom: 20px;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
#newsletter-privacy {
|
||||
display: flex;
|
||||
|
||||
/* The privacy section is hidden by default and only displayed on focus */
|
||||
height: 0;
|
||||
margin-bottom: -20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#newsletter-privacy.animate {
|
||||
transition: all 0.25s cubic-bezier(.15,.75,.35,.9);
|
||||
}
|
||||
|
||||
#newsletter-privacy label {
|
||||
line-height: var(--line-height);
|
||||
}
|
||||
|
||||
#privacy {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 2px;
|
||||
margin-inline-end: 10px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#email {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 12px 15px;
|
||||
}
|
||||
|
||||
#newsletter-form input {
|
||||
border-color: var(--grey-90-alpha-30);
|
||||
}
|
||||
|
||||
#newsletter-form input:hover {
|
||||
border-color: var(--grey-90-alpha-50);
|
||||
}
|
||||
|
||||
#newsletter-form input:focus {
|
||||
border-color: var(--teal-60);
|
||||
box-shadow: 0 0 2px 0 var(--teal-60);
|
||||
}
|
||||
|
||||
#newsletter-form::placeholder {
|
||||
color: var(--grey-90-alpha-40);
|
||||
}
|
||||
|
||||
#newsletter-submit {
|
||||
display: block;
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/* 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 file handles the newsletter subscription form on about:devtools.
|
||||
* It is largely inspired from https://mozilla.github.io/basket-example/
|
||||
*/
|
||||
|
||||
window.addEventListener("load", function () {
|
||||
const { utils: Cu } = Components;
|
||||
const { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||
|
||||
// Timeout for the subscribe XHR.
|
||||
const REQUEST_TIMEOUT = 5000;
|
||||
|
||||
const ABOUTDEVTOOLS_STRINGS = "chrome://devtools-shim/locale/aboutdevtools.properties";
|
||||
const aboutDevtoolsBundle = Services.strings.createBundle(ABOUTDEVTOOLS_STRINGS);
|
||||
|
||||
let emailInput = document.getElementById("email");
|
||||
let newsletterErrors = document.getElementById("newsletter-errors");
|
||||
let newsletterForm = document.getElementById("newsletter-form");
|
||||
let newsletterPrivacySection = document.getElementById("newsletter-privacy");
|
||||
let newsletterThanks = document.getElementById("newsletter-thanks");
|
||||
|
||||
/**
|
||||
* Update the error panel to display the provided errors. If the argument is null or
|
||||
* empty, a default error message will be displayed.
|
||||
*
|
||||
* @param {Array} errors
|
||||
* Array of strings, each item being an error message to display.
|
||||
*/
|
||||
function updateErrorPanel(errors) {
|
||||
clearErrorPanel();
|
||||
|
||||
if (!errors || errors.length == 0) {
|
||||
errors = [aboutDevtoolsBundle.GetStringFromName("newsletter.error.unknown")];
|
||||
}
|
||||
|
||||
// Create errors markup.
|
||||
let fragment = document.createDocumentFragment();
|
||||
for (let error of errors) {
|
||||
let item = document.createElement("p");
|
||||
item.classList.add("error");
|
||||
item.appendChild(document.createTextNode(error));
|
||||
fragment.appendChild(item);
|
||||
}
|
||||
|
||||
newsletterErrors.appendChild(fragment);
|
||||
newsletterErrors.classList.add("show");
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the error panel and remove all errors.
|
||||
*/
|
||||
function clearErrorPanel() {
|
||||
newsletterErrors.classList.remove("show");
|
||||
newsletterErrors.innerHTML = "";
|
||||
}
|
||||
|
||||
// Show the additional form fields on focus of the email input.
|
||||
function onEmailInputFocus() {
|
||||
// Create a hidden measuring container, append it to the parent of the privacy section
|
||||
let container = document.createElement("div");
|
||||
container.style.cssText = "visibility: hidden; overflow: hidden; position: absolute";
|
||||
newsletterPrivacySection.parentNode.appendChild(container);
|
||||
|
||||
// Clone the privacy section, append the clone to the measuring container.
|
||||
let clone = newsletterPrivacySection.cloneNode(true);
|
||||
container.appendChild(clone);
|
||||
|
||||
// Measure the target height of the privacy section.
|
||||
clone.style.height = "auto";
|
||||
let height = clone.offsetHeight;
|
||||
|
||||
// Cleanup the measuring container.
|
||||
container.remove();
|
||||
|
||||
// Set the animate class and set the height to the measured height.
|
||||
newsletterPrivacySection.classList.add("animate");
|
||||
newsletterPrivacySection.style.cssText = `height: ${height}px; margin-bottom: 0;`;
|
||||
}
|
||||
|
||||
// XHR subscribe; handle errors; display thanks message on success.
|
||||
function onFormSubmit(evt) {
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
// New submission, clear old errors
|
||||
clearErrorPanel();
|
||||
|
||||
let xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.onload = function (r) {
|
||||
if (r.target.status >= 200 && r.target.status < 300) {
|
||||
let {response} = r.target;
|
||||
|
||||
if (response.success === true) {
|
||||
// Hide form and show success message.
|
||||
newsletterForm.style.display = "none";
|
||||
newsletterThanks.classList.add("show");
|
||||
} else {
|
||||
// We trust the error messages from the service to be meaningful for the user.
|
||||
updateErrorPanel(response.errors);
|
||||
}
|
||||
} else {
|
||||
let {status, statusText} = r.target;
|
||||
let statusInfo = `${status} - ${statusText}`;
|
||||
let error = aboutDevtoolsBundle
|
||||
.formatStringFromName("newsletter.error.common", [statusInfo], 1);
|
||||
updateErrorPanel([error]);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = () => {
|
||||
updateErrorPanel();
|
||||
};
|
||||
|
||||
xhr.ontimeout = () => {
|
||||
let error = aboutDevtoolsBundle.GetStringFromName("newsletter.error.timeout");
|
||||
updateErrorPanel([error]);
|
||||
};
|
||||
|
||||
let url = newsletterForm.getAttribute("action");
|
||||
|
||||
xhr.open("POST", url, true);
|
||||
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
|
||||
xhr.timeout = REQUEST_TIMEOUT;
|
||||
xhr.responseType = "json";
|
||||
|
||||
// Create form data.
|
||||
let formData = new FormData(newsletterForm);
|
||||
formData.append("source_url", document.location.href);
|
||||
|
||||
let params = new URLSearchParams(formData);
|
||||
|
||||
// Send the request.
|
||||
xhr.send(params.toString());
|
||||
}
|
||||
|
||||
// Attach event listeners.
|
||||
newsletterForm.addEventListener("submit", onFormSubmit);
|
||||
emailInput.addEventListener("focus", onEmailInputFocus);
|
||||
}, { once: true });
|
|
@ -22,4 +22,14 @@
|
|||
<!ENTITY aboutDevtools.enable.installButton "Enable Developer Tools">
|
||||
<!ENTITY aboutDevtools.enable.closeButton "Close this page">
|
||||
<!ENTITY aboutDevtools.welcome.title "Welcome to Firefox Developer Tools!">
|
||||
<!ENTITY aboutDevtools.welcome.message "You’ve successfully enabled DevTools! To get started, explore the Web Developer menu or open the tools with ##INSPECTOR_SHORTCUT##.">
|
||||
<!ENTITY aboutDevtools.welcome.message "You’ve successfully enabled DevTools! To get started, explore the Web Developer menu or open the tools with ##INSPECTOR_SHORTCUT##.">
|
||||
|
||||
<!ENTITY aboutDevtools.newsletter.title "Mozilla Developer Newsletter">
|
||||
<!ENTITY aboutDevtools.newsletter.message "Get developer news, tricks and resources sent straight to your inbox.">
|
||||
<!ENTITY aboutDevtools.newsletter.email.placeholder "Email">
|
||||
<!ENTITY aboutDevtools.newsletter.privacy.label "I'm okay with Mozilla handling my info as explained in this <a class='external' href='https://www.mozilla.org/privacy/'>Privacy Policy</a>.">
|
||||
<!ENTITY aboutDevtools.newsletter.subscribe.label "Subscribe">
|
||||
|
||||
<!ENTITY aboutDevtools.newsletter.thanks.title "Thanks!">
|
||||
<!ENTITY aboutDevtools.newsletter.thanks.message "If you haven’t previously confirmed a subscription to a Mozilla-related newsletter you may have to do so. Please check your inbox or your spam filter for an email from us.">
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ devtools-shim.jar:
|
|||
content/aboutdevtools/aboutdevtools.xhtml (aboutdevtools/aboutdevtools.xhtml)
|
||||
content/aboutdevtools/aboutdevtools.css (aboutdevtools/aboutdevtools.css)
|
||||
content/aboutdevtools/aboutdevtools.js (aboutdevtools/aboutdevtools.js)
|
||||
content/aboutdevtools/subscribe.css (aboutdevtools/subscribe.css)
|
||||
content/aboutdevtools/subscribe.js (aboutdevtools/subscribe.js)
|
||||
|
||||
content/aboutdevtools/images/otter.svg (aboutdevtools/images/otter.svg)
|
||||
|
||||
|
|
|
@ -35,3 +35,16 @@ features.performance.desc=Unblock bottlenecks, streamline processes, optimize as
|
|||
|
||||
features.memory.title=Memory
|
||||
features.memory.desc=Find memory leaks and make your application zippy.
|
||||
|
||||
# LOCALIZATION NOTE (newsletter.error.common): error text displayed when the newsletter
|
||||
# subscription failed. The argument will be replaced with request's status code and status
|
||||
# text (e.g. "404 - Not Found")
|
||||
newsletter.error.common=Subscription request failed (%S).
|
||||
|
||||
# LOCALIZATION NOTE (newsletter.error.unknown): error text displayed when the newsletter
|
||||
# subscription failed for an unexpected reason.
|
||||
newsletter.error.unknown=An unexpected error occurred.
|
||||
|
||||
# LOCALIZATION NOTE (newsletter.error.timeout): error text displayed when the newsletter
|
||||
# subscription timed out.
|
||||
newsletter.error.timeout=Subscription request timed out.
|
||||
|
|
Загрузка…
Ссылка в новой задаче