/* globals log, catcher, onboardingHtml, onboardingCss, util, shooter, callBackground, assertIsTrusted, assertIsBlankDocument */ "use strict"; this.slides = (function() { let exports = {}; const { watchFunction } = catcher; let iframe; let doc; let currentSlide = 1; let numberOfSlides; let callbacks; exports.display = function(addCallbacks) { if (iframe) { throw new Error("Attemted to call slides.display() twice"); } return new Promise((resolve, reject) => { callbacks = addCallbacks; // FIXME: a lot of this iframe logic is in ui.js; maybe move to util.js iframe = document.createElement("iframe"); iframe.src = browser.extension.getURL("blank.html"); iframe.id = "firefox-screenshots-onboarding-iframe"; iframe.style.zIndex = "99999999999"; iframe.style.border = "none"; iframe.style.position = "fixed"; iframe.style.top = "0"; iframe.style.left = "0"; iframe.style.margin = "0"; iframe.scrolling = "no"; updateIframeSize(); let html = onboardingHtml.replace('', ``); html = html.replace(/MOZ_EXTENSION([^"]+)/g, (match, filename) => { return browser.extension.getURL(filename); }); iframe.addEventListener("load", catcher.watchFunction(() => { doc = iframe.contentDocument; assertIsBlankDocument(doc); let parsedDom = (new DOMParser()).parseFromString( html, "text/html" ); doc.replaceChild( doc.adoptNode(parsedDom.documentElement), doc.documentElement ); doc.addEventListener("keyup", onKeyUp); doc.documentElement.dir = browser.i18n.getMessage("@@bidi_dir"); doc.documentElement.lang = browser.i18n.getMessage("@@ui_locale"); localizeText(doc); activateSlide(doc); resolve(); }), {once: true}); document.body.appendChild(iframe); iframe.focus(); window.addEventListener("resize", onResize); }); }; exports.remove = exports.unload = function() { window.removeEventListener("resize", onResize); if (doc) { doc.removeEventListener("keyup", onKeyUp); } util.removeNode(iframe); iframe = doc = null; currentSlide = 1; numberOfSlides = undefined; callbacks = undefined; }; function localizeText(doc) { let els = doc.querySelectorAll("[data-l10n-id]"); for (let el of els) { let id = el.getAttribute("data-l10n-id"); let text = browser.i18n.getMessage(id); el.textContent = text; } els = doc.querySelectorAll("[data-l10n-label-id]"); for (let el of els) { let id = el.getAttribute("data-l10n-label-id"); let text = browser.i18n.getMessage(id); el.setAttribute("aria-label", text); } // termsAndPrivacyNoticeCloudServices is a more complicated substitution: let termsContainer = doc.querySelector(".onboarding-legal-notice"); termsContainer.innerHTML = ""; let termsSentinel = "__TERMS__"; let privacySentinel = "__PRIVACY__"; let sentinelSplitter = "!!!"; let linkTexts = { [termsSentinel]: browser.i18n.getMessage("termsAndPrivacyNoticeTermsLink"), [privacySentinel]: browser.i18n.getMessage("termsAndPrivacyNoticyPrivacyLink") }; let linkUrls = { [termsSentinel]: "https://www.mozilla.org/about/legal/terms/services/", [privacySentinel]: "https://www.mozilla.org/privacy/firefox/" }; let text = browser.i18n.getMessage( "termsAndPrivacyNotice2", [sentinelSplitter + termsSentinel + sentinelSplitter, sentinelSplitter + privacySentinel + sentinelSplitter]); let parts = text.split(sentinelSplitter); for (let part of parts) { let el; if (part === termsSentinel || part === privacySentinel) { el = doc.createElement("a"); el.href = linkUrls[part]; el.textContent = linkTexts[part]; el.target = "_blank"; el.id = (part === termsSentinel) ? "terms" : "privacy"; } else { el = doc.createTextNode(part); } termsContainer.appendChild(el); } } function activateSlide(doc) { numberOfSlides = parseInt(doc.querySelector("[data-number-of-slides]").getAttribute("data-number-of-slides"), 10); doc.querySelector("#next").addEventListener("click", watchFunction(assertIsTrusted(() => { shooter.sendEvent("navigate-slide", "next"); next(); }))); doc.querySelector("#prev").addEventListener("click", watchFunction(assertIsTrusted(() => { shooter.sendEvent("navigate-slide", "prev"); prev(); }))); for (let el of doc.querySelectorAll(".goto-slide")) { el.addEventListener("click", watchFunction(assertIsTrusted((event) => { shooter.sendEvent("navigate-slide", "goto"); let el = event.target; let index = parseInt(el.getAttribute("data-number"), 10); setSlide(index); }))); } doc.querySelector("#skip").addEventListener("click", watchFunction(assertIsTrusted((event) => { shooter.sendEvent("cancel-slides", "skip"); callbacks.onEnd(); }))); doc.querySelector("#done").addEventListener("click", watchFunction(assertIsTrusted((event) => { shooter.sendEvent("finish-slides", "done"); callbacks.onEnd(); }))); // Note: e10s breaks the terms and privacy anchor tags. Work around this by // manually opening the correct URLs on click until bug 1357589 is fixed. doc.querySelector("#terms").addEventListener("click", watchFunction(assertIsTrusted((event) => { event.preventDefault(); callBackground("openTermsPage"); }))); doc.querySelector("#privacy").addEventListener("click", watchFunction(assertIsTrusted((event) => { event.preventDefault(); callBackground("openPrivacyPage"); }))); doc.querySelector("#slide-overlay").addEventListener("click", watchFunction(assertIsTrusted((event) => { if (event.target == doc.querySelector("#slide-overlay")) { shooter.sendEvent("cancel-slides", "background-click"); callbacks.onEnd(); } }))); setSlide(1); } function next() { setSlide(currentSlide + 1); } function prev() { setSlide(currentSlide - 1); } const onResize = catcher.watchFunction(function() { if (!iframe) { log.warn("slides onResize called when iframe is not setup"); return; } updateIframeSize(); }); function updateIframeSize() { iframe.style.height = window.innerHeight + "px"; iframe.style.width = window.innerWidth + "px"; } const onKeyUp = catcher.watchFunction(assertIsTrusted(function(event) { if ((event.key || event.code) === "Escape") { shooter.sendEvent("cancel-slides", "keyboard-escape"); callbacks.onEnd(); } if ((event.key || event.code) === "ArrowRight") { shooter.sendEvent("navigate-slide", "keyboard-arrowright"); next(); } if ((event.key || event.code) === "ArrowLeft") { shooter.sendEvent("navigate-slide", "keyboard-arrowleft"); prev(); } })); function setSlide(index) { if (index < 1) { index = 1; } if (index > numberOfSlides) { index = numberOfSlides; } shooter.sendEvent("visited-slide", `slide-${index}`); currentSlide = index; let slideEl = doc.querySelector("#slide-container"); for (let i = 1; i <= numberOfSlides; i++) { let className = `active-slide-${i}`; if (i == currentSlide) { slideEl.classList.add(className); } else { slideEl.classList.remove(className); } } } return exports; })(); null;