Merge pull request #100 from mozilla/interstitial-template-select

Start #41, put in an interstitial template selector
This commit is contained in:
Dave Justice 2018-07-30 18:58:57 -04:00 коммит произвёл GitHub
Родитель 5817aec421 2de2066af2
Коммит b376196e63
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
5 изменённых файлов: 76 добавлений и 108 удалений

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

@ -1,6 +1,4 @@
/* globals TestPilotGA, emailTemplates, templateMetadata */
let selectedTemplate = templateMetadata.defaultTemplateName;
browser.runtime.onMessage.addListener((message, source) => {
if (message.type === "sendEmail") {
sendEmail(message.tabIds).catch((e) => {
@ -25,10 +23,8 @@ browser.runtime.onMessage.addListener((message, source) => {
delete message.type;
sendEvent(message);
return Promise.resolve(null);
} else if (message.type === "setSelectedTemplate") {
return setSelectedTemplate(message.name);
} else if (message.type === "getSelectedTemplate") {
return Promise.resolve(selectedTemplate);
} else if (message.type === "renderTemplate") {
return renderTabs(message.tabInfo, message.selectedTemplate);
}
console.error("Unexpected message type:", message.type);
return null;
@ -94,16 +90,14 @@ async function getTabInfo(tabIds, {wantsScreenshots, wantsReadability}) {
return tabIds.map(id => tabInfo[id]);
}
async function renderTabs(tabIds, templateName) {
let { wantsScreenshots, wantsReadability } = templateMetadata.getTemplate(templateName);
let tabInfo = await getTabInfo(tabIds, {wantsScreenshots, wantsReadability});
async function renderTabs(tabInfo, templateName) {
let TemplateComponent = emailTemplates[templateMetadata.getTemplate(templateName).componentName];
if (!TemplateComponent) {
throw new Error(`No component found for template: ${templateName}`);
}
let html = emailTemplates.renderEmail(tabInfo, TemplateComponent);
let subject = emailTemplates.renderSubject(tabInfo);
return { html, tabInfo, subject };
return { html, subject };
}
async function sendEmail(tabIds) {
@ -126,22 +120,25 @@ async function sendEmail(tabIds) {
loginInterrupt();
}
}, 1000);
let { html, tabInfo, subject } = await renderTabs(tabIds, selectedTemplate);
let tabInfo = await getTabInfo(tabIds, {wantsScreenshots: true, wantsReadability: true});
await browser.tabs.executeScript(newTab.id, {
file: "templateMetadata.js",
runAt: "document_start",
});
await browser.tabs.executeScript(newTab.id, {
file: "set-html-email.js",
runAt: "document_start",
});
await browser.tabs.sendMessage(newTab.id, {
type: "setHtml",
html,
subject,
type: "sendTabInfo",
thisTabId: newTab.id,
tabInfo
});
}
async function copyTabHtml(tabIds) {
let { html } = await renderTabs(tabIds, selectedTemplate);
let tabInfo = await getTabInfo(tabIds, {wantsScreenshots: false, wantsReadability: false});
let { html } = await renderTabs(tabInfo, "just_links");
copyHtmlToClipboard(html);
}
@ -195,23 +192,3 @@ async function closeManyTabs(composeTabId, otherTabInfo) {
}
await browser.tabs.remove(toClose);
}
async function setSelectedTemplate(newName) {
selectedTemplate = newName;
await browser.storage.local.set({selectedTemplate: newName});
}
async function init() {
let result = await browser.storage.local.get(["selectedTemplate"]);
if (result && result.selectedTemplate) {
try {
// Checks that the template really exists:
templateMetadata.getTemplate(result.selectedTemplate);
selectedTemplate = result.selectedTemplate;
} catch (e) {
console.error("Could not set template", result.selectedTemplate, "to:", String(e));
}
}
}
init();

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

@ -73,6 +73,15 @@
box-shadow: 0 2px 8px rgba(12, 12, 13, 0.1);
}
.big-container {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.8);
}
#loading-container {
width: 100%;
height: 100%;
@ -213,5 +222,16 @@
</div>
</div>
<div id="choose-template" class="container big-container" style="display: none">
<div class="template-template" style="display: none">
<button>
Use <span data-substitute="title"></span>
</button>
</div>
<div id="choose-template-container" class="card-container">
<button id="choose-template-cancel">Cancel</button>
</div>
</div>
</body>
</html>

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

@ -137,13 +137,13 @@ supply a favicon */
.feedback-link {
font-size: 11px;
color: #4A4A4F;
color: #4a4a4f;
letter-spacing: -0.08px;
padding: 2px 10px;
}
.feedback-link a {
color: #0A84FF;
color: #0a84ff;
text-decoration: none;
}

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

@ -2,8 +2,6 @@
let activeTabLi;
let selected = new Map();
let isChoosingTemplate = false;
let selectedTemplate = templateMetadata.defaultTemplateName;
const LOGIN_ERROR_TIME = 90 * 1000; // 90 seconds
class Tab extends React.Component {
@ -78,7 +76,6 @@ class Popup extends React.Component {
<input checked={allChecked} ref={allCheckbox => this.allCheckbox = allCheckbox} type="checkbox" id="allCheckbox" onChange={this.onClickCheckAll.bind(this)} />
Select All
</label>
<button onClick={this.chooseTemplate.bind(this)}>Change template ({selectedTemplate})</button>
</div>
</div>
<div className="separator"></div>
@ -143,10 +140,6 @@ class Popup extends React.Component {
}, 300);
}
chooseTemplate() {
isChoosingTemplate = true;
render();
}
}
class LoginError extends React.Component {
@ -158,47 +151,6 @@ class LoginError extends React.Component {
}
}
class TemplateChooser extends React.Component {
render() {
let templates = templateMetadata.metadata.map(template => {
return <TemplateItem key={template.name} selected={template.name === selectedTemplate} {...template} />;
});
return <div>
<ul>
{ templates }
</ul>
<footer className="panel-footer toggle-enabled">
<button onClick={this.onCancel.bind(this)}>
Cancel
</button>
</footer>
</div>;
}
onCancel() {
isChoosingTemplate = false;
render();
}
}
class TemplateItem extends React.Component {
render() {
let className = "";
if (this.props.selected) {
className += " selected";
}
return <li className={className}>
<button onClick={this.selectTemplate.bind(this)}>{this.props.title}</button>
</li>;
}
selectTemplate() {
setSelectedTemplate(this.props.name);
isChoosingTemplate = false;
render();
}
}
async function render(firstRun) {
let tabs = await browser.tabs.query({currentWindow: true});
if (firstRun) {
@ -214,12 +166,7 @@ async function render(firstRun) {
if (Date.now() - showLoginError > LOGIN_ERROR_TIME) {
showLoginError = 0;
}
let page;
if (isChoosingTemplate) {
page = <TemplateChooser />;
} else {
page = <Popup selected={selected} tabs={tabs} showLoginError={showLoginError} />;
}
let page = <Popup selected={selected} tabs={tabs} showLoginError={showLoginError} />;
ReactDOM.render(page, document.getElementById("panel"));
if (firstRun) {
activeTabLi.scrollIntoView({
@ -296,13 +243,7 @@ for (let eventName of ["onAttached", "onCreated", "onDetached", "onMoved", "onUp
browser.tabs.onRemoved.addListener(renderWithDelay);
async function setSelectedTemplate(name) {
selectedTemplate = name;
await browser.runtime.sendMessage({type: "setSelectedTemplate", name});
}
async function init() {
selectedTemplate = await browser.runtime.sendMessage({type: "getSelectedTemplate"});
render(true);
}

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

@ -1,20 +1,18 @@
/* globals cloneInto */
/* globals cloneInto, templateMetadata */
browser.runtime.onMessage.addListener((message) => {
try {
thisTabId = message.thisTabId;
closeTabInfo = message.tabInfo;
setSubject(message.subject);
setHtml(message.html);
tabInfo = message.tabInfo;
} catch (e) {
console.error("Unable to setHtml:", String(e), e.stack);
console.error("Error getting tabInfo:", String(e), e.stack);
throw e;
}
});
let completed = false;
let thisTabId;
let closeTabInfo;
let tabInfo;
window.addEventListener("beforeunload", () => {
if (completed) {
@ -28,7 +26,6 @@ window.addEventListener("beforeunload", () => {
browser.runtime.sendMessage({
type: "sendFailed"
});
console.error("beforeunload");
});
function setSubject(subject) {
@ -116,7 +113,7 @@ function showCloseButtons() {
let done = iframeDocument.querySelector("#done");
let doneMsg = iframeDocument.querySelector("#done-message");
let closeAllTabs = iframeDocument.querySelector("#close-all-tabs");
let numTabs = closeTabInfo.length;
let numTabs = tabInfo.length;
if (numTabs === 1) {
closeAllTabs.textContent = closeAllTabs.getAttribute("data-one-tab");
doneMsg.textContent = doneMsg.getAttribute("data-one-tab");
@ -133,7 +130,7 @@ function showCloseButtons() {
closeAllTabs.addEventListener("click", async () => {
await browser.runtime.sendMessage({
type: "closeTabs",
closeTabInfo,
closeTabInfo: tabInfo,
composeTabId: thisTabId
});
});
@ -143,6 +140,39 @@ function showLoading() {
showIframe("#loading-container");
}
function showTemplateSelector() {
showIframe("#choose-template");
let cancel = iframeDocument.querySelector("#choose-template-cancel");
cancel.addEventListener("click", async () => {
completed = true;
await browser.runtime.sendMessage({
type: "closeComposeTab",
tabId: thisTabId,
});
});
let elTemplate = iframeDocument.querySelector(".template-template");
for (let template of templateMetadata.metadata) {
let instance = elTemplate.cloneNode(true);
instance.style.display = "";
instance.classList.remove("template-template");
for (let el of instance.querySelectorAll("*[data-substitute]")) {
el.textContent = template[el.getAttribute("data-substitute")];
el.removeAttribute("data-substitute");
}
instance.addEventListener("click", async () => {
showLoading();
let { html, subject } = await browser.runtime.sendMessage({
type: "renderTemplate",
selectedTemplate: template.name,
tabInfo,
});
setSubject(subject);
setHtml(html);
});
cancel.parentNode.insertBefore(instance, cancel);
}
}
let iframe = null;
let initPromise;
let iframeDocument = null;
@ -182,7 +212,7 @@ function createIframe() {
}
function showIframe(container) {
let containers = ["#loading-container", "#done-container"];
let containers = ["#loading-container", "#done-container", "#choose-template"];
if (!containers.includes(container)) {
throw new Error(`Unexpected container: ${container}`);
}
@ -203,5 +233,5 @@ function hideIframe() {
createIframe();
initPromise.then(() => {
showLoading();
showTemplateSelector();
});