From e03638d32984214008d0ab898618f8e9002ece8b Mon Sep 17 00:00:00 2001 From: Ian Bicking Date: Thu, 26 Jul 2018 12:41:28 -0500 Subject: [PATCH] Start #41, put in an interstitial template selector This puts the selector into the gmail compose window itself as an overlay. For now rendering of the templates stays in the background process, but arguably it should be moved into the compose window. --- addon/background.js | 47 ++++++++----------------------- addon/gmail-iframe.html | 20 ++++++++++++++ addon/popup.jsx | 61 +---------------------------------------- addon/set-html-email.js | 52 +++++++++++++++++++++++++++-------- 4 files changed, 74 insertions(+), 106 deletions(-) diff --git a/addon/background.js b/addon/background.js index 4cdb092..ca4256f 100644 --- a/addon/background.js +++ b/addon/background.js @@ -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(); diff --git a/addon/gmail-iframe.html b/addon/gmail-iframe.html index 71602c6..fb2abaa 100644 --- a/addon/gmail-iframe.html +++ b/addon/gmail-iframe.html @@ -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 @@ + + diff --git a/addon/popup.jsx b/addon/popup.jsx index b9722d8..77806b5 100644 --- a/addon/popup.jsx +++ b/addon/popup.jsx @@ -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 { this.allCheckbox = allCheckbox} type="checkbox" id="allCheckbox" onChange={this.onClickCheckAll.bind(this)} /> Select All -
@@ -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 ; - }); - return
-
    - { templates } -
-
- -
-
; - } - - onCancel() { - isChoosingTemplate = false; - render(); - } -} - -class TemplateItem extends React.Component { - render() { - let className = ""; - if (this.props.selected) { - className += " selected"; - } - return
  • - -
  • ; - } - - 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 = ; - } else { - page = ; - } + let page = ; 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); } diff --git a/addon/set-html-email.js b/addon/set-html-email.js index f3c122d..dab8d4d 100644 --- a/addon/set-html-email.js +++ b/addon/set-html-email.js @@ -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(); });