Bug 840124 - implement postMessage API for remote report (code), r=jaws, f=gps+gavin
--- a/browser/base/content/abouthealthreport/abouthealth.css
+++ b/browser/base/content/abouthealthreport/abouthealth.css
@@ -2,139 +2,14 @@
margin: 0;
padding: 0;
}
html, body {
height: 100%;
}
-body {
- background-color: window;
- color: windowtext;
- font-family: "Trebuchet MS", "Helvetica";
-}
-
-#about-header {
- padding: 6px 20px;
- min-height: 60px;
- border-bottom: 1px solid #999999;
- margin-bottom: 12px;
- display: flex;
- align-items: center;
- justify-content: space-between;
- background-image: linear-gradient(to bottom, #E66000, #BB2200);
- color: #FFFFFF;
-}
-
-#control-container {
- display: flex;
- align-items: center;
-}
-
-#content-line {
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-#content {
- display: flex;
- flex-direction: column;
-}
-
-#state-intro {
- background-image: linear-gradient(to bottom, #EAEFF2, #D4DDE4);
- border: 1px solid #999999;
- border-radius: 6px;
- margin: 12px;
- padding: 12px;
-}
-
-#settings-controls {
- padding-top: 15px;
-}
-
-#control-container {
- padding-top: 15px;
-}
-
-#content[state="default"] #details-hide,
-#content[state="default"] #btn-optin,
-#content[state="default"] #intro-disabled {
- display: none;
-}
-
-#content[state="showDetails"] #details-show,
-#content[state="showDetails"] #btn-optin,
-#content[state="showDetails"] #intro-disabled {
- display: none;
-}
-
-#content[state="showReport"] #details-hide,
-#content[state="showReport"] #report-show,
-#content[state="showReport"] #btn-optin,
-#content[state="showReport"] #intro-disabled {
- display: none;
-}
-
-#content[state="disabled"] #details-hide,
-#content[state="disabled"] #details-show,
-#content[state="disabled"] #btn-optout,
-#content[state="disabled"] #intro-enabled {
- display: none;
-}
-
-#details-view,
-#report-view {
- display: none;
-}
-
-#data-view {
- height: auto;
- margin-top: 8px;
- align-items: center;
- justify-content: center;
- border: 1px solid #999999;
- border-radius: 6px;
- margin: 12px;
-}
-
-#remote-report,
-#report-view {
+#remote-report {
width: 100%;
height: 100%;
- min-height: 600px;
-}
-
-#report-show {
+ border: 0;
display: flex;
- width: 100%;
- height: 100%;
- min-height: 60px;
- font-size: 18px;
- font-weight: bold;
- background-image: linear-gradient(to bottom, #80BB2E, #547D1C);
- color: #ffffff;
- border-radius: 6px;
}
-
-#details-view {
- border: 1px solid #999999;
- border-radius: 6px;
- margin: 12px;
- padding: 12px;
-}
-
-#content[state="showDetails"],
-#content[state="showReport"],
-#content[state="showDetails"] #details-view,
-#content[state="showReport"] #report-view {
- display: block;
-}
-
-#content[state="showReport"] #report-show {
- display: none;
-}
-#content[state="showReport"] #report-view,
-#remote-report {
- border: 0;
-}
--- a/browser/base/content/abouthealthreport/abouthealth.js
+++ b/browser/base/content/abouthealthreport/abouthealth.js
@@ -2,115 +2,131 @@
* 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";
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://services-common/preferences.js");
+Cu.import("resource://gre/modules/Services.jsm");
const reporter = Cc["@mozilla.org/datareporting/service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject
.healthReporter;
const policy = Cc["@mozilla.org/datareporting/service;1"]
.getService(Ci.nsISupports)
.wrappedJSObject
.policy;
-const prefs = new Preferences("datareporting.healthreport.about.");
+const prefs = new Preferences("datareporting.healthreport.");
+
+
+let healthReportWrapper = {
+ init: function () {
+ reporter.onInit().then(healthReportWrapper.refreshPayload,
+ healthReportWrapper.handleInitFailure);
-function getLocale() {
- return Cc["@mozilla.org/chrome/chrome-registry;1"]
- .getService(Ci.nsIXULChromeRegistry)
- .getSelectedLocale("global");
-}
+ let iframe = document.getElementById("remote-report");
+ iframe.addEventListener("load", healthReportWrapper.initRemotePage, false);
+ let report = Services.io.newURI(prefs.get("about.reportUrl"), null, null);
+ iframe.src = report.spec;
+ prefs.observe("uploadEnabled", this.updatePrefState, healthReportWrapper);
+ },
-function init() {
- refreshWithDataSubmissionFlag(policy.healthReportUploadEnabled);
- refreshJSONPayload();
- document.getElementById("details-link").href = prefs.get("glossaryUrl");
-}
+ onOptIn: function () {
+ policy.recordHealthReportUploadEnabled(true,
+ "Health report page sent opt-in command.");
+ this.updatePrefState();
+ },
+
+ onOptOut: function () {
+ policy.recordHealthReportUploadEnabled(false,
+ "Health report page sent opt-out command.");
+ this.updatePrefState();
+ },
-/**
- * Update the state of the page to reflect the current data submission state.
- *
- * @param enabled
- * (bool) Whether data submission is enabled.
- */
-function refreshWithDataSubmissionFlag(enabled) {
- if (!enabled) {
- updateView("disabled");
- } else {
- updateView("default");
- }
-}
+ updatePrefState: function () {
+ try {
+ let prefs = {
+ enabled: policy.healthReportUploadEnabled,
+ }
+ this.injectData("prefs", prefs);
+ } catch (e) {
+ this.reportFailure(this.ERROR_PREFS_FAILED);
+ }
+ },
-function updateView(state="default") {
- let content = document.getElementById("content");
- let controlContainer = document.getElementById("control-container");
- content.setAttribute("state", state);
- controlContainer.setAttribute("state", state);
-}
+ refreshPayload: function () {
+ reporter.collectAndObtainJSONPayload().then(healthReportWrapper.updatePayload,
+ healthReportWrapper.handlePayloadFailure);
+ },
-function refreshDataView(data) {
- let noData = document.getElementById("data-no-data");
- let dataEl = document.getElementById("raw-data");
+ updatePayload: function (data) {
+ healthReportWrapper.injectData("payload", data);
+ },
- noData.style.display = data ? "none" : "inline";
- dataEl.style.display = data ? "block" : "none";
- if (data) {
- dataEl.textContent = JSON.stringify(data, null, 2);
- }
-}
+ injectData: function (type, content) {
+ let report = Services.io.newURI(prefs.get("about.reportUrl"), null, null);
+
+ // file URIs can't be used for targetOrigin, so we use "*" for this special case
+ // in all other cases, pass in the URL to the report so we properly restrict the message dispatch
+ let reportUrl = report.scheme == "file" ? "*" : report.spec;
-/**
- * Ensure the page has the latest version of the uploaded JSON payload.
- */
-function refreshJSONPayload() {
- reporter.getLastPayload().then(refreshDataView);
-}
+ let data = {
+ type: type,
+ content: content
+ }
+
+ let iframe = document.getElementById("remote-report");
+ iframe.contentWindow.postMessage(data, reportUrl);
+ },
-function onOptInClick() {
- policy.recordHealthReportUploadEnabled(true,
- "Clicked opt in button on about page.");
- refreshWithDataSubmissionFlag(true);
-}
-
-function onOptOutClick() {
- let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"]
- .getService(Ci.nsIPromptService);
-
- let messages = document.getElementById("optout-confirmationPrompt");
- let title = messages.getAttribute("confirmationPrompt_title");
- let message = messages.getAttribute("confirmationPrompt_message");
-
- if (!prompts.confirm(window, title, message)) {
- return;
- }
+ handleRemoteCommand: function (evt) {
+ switch (evt.detail.command) {
+ case "DisableDataSubmission":
+ this.onOptOut();
+ break;
+ case "EnableDataSubmission":
+ this.onOptIn();
+ break;
+ case "RequestCurrentPrefs":
+ this.updatePrefState();
+ break;
+ case "RequestCurrentPayload":
+ this.refreshPayload();
+ break;
+ default:
+ Cu.reportError("Unexpected remote command received: " + evt.detail.command + ". Ignoring command.");
+ break;
+ }
+ },
- policy.recordHealthReportUploadEnabled(false,
- "Clicked opt out button on about page.");
- refreshWithDataSubmissionFlag(false);
- updateView("disabled");
-}
+ initRemotePage: function () {
+ let iframe = document.getElementById("remote-report").contentDocument;
+ iframe.addEventListener("RemoteHealthReportCommand",
+ function onCommand(e) {healthReportWrapper.handleRemoteCommand(e);},
+ false);
+ healthReportWrapper.updatePrefState();
+ },
-function onShowRawDataClick() {
- updateView("showDetails");
- refreshJSONPayload();
-}
+ // error handling
+ ERROR_INIT_FAILED: 1,
+ ERROR_PAYLOAD_FAILED: 2,
+ ERROR_PREFS_FAILED: 3,
-function onHideRawDataClick() {
- updateView("default");
-}
+ reportFailure: function (error) {
+ let details = {
+ errorType: error,
+ }
+ healthReportWrapper.injectData("error", details);
+ },
-function onShowReportClick() {
- updateView("showReport");
- document.getElementById("remote-report").src = prefs.get("reportUrl");
-}
+ handleInitFailure: function () {
+ healthReportWrapper.reportFailure(healthReportWrapper.ERROR_INIT_FAILED);
+ },
-function onHideReportClick() {
- updateView("default");
- document.getElementById("remote-report").src = "";
+ handlePayloadFailure: function () {
+ healthReportWrapper.reportFailure(healthReportWrapper.ERROR_PAYLOAD_FAILED);
+ },
}
-
--- a/browser/base/content/abouthealthreport/abouthealth.xhtml
+++ b/browser/base/content/abouthealthreport/abouthealth.xhtml
@@ -17,55 +17,13 @@
<head>
<title>&abouthealth.pagetitle;</title>
<link rel="stylesheet"
href="chrome://browser/content/abouthealthreport/abouthealth.css"
type="text/css" />
<script type="text/javascript;version=1.8"
src="chrome://browser/content/abouthealthreport/abouthealth.js" />
</head>
- <body dir="&abouthealth.locale-direction;" class="aboutPageWideContainer" onload="init();">
- <div id="about-header">
- <h1>&abouthealth.header;</h1>
- <img src="chrome://branding/content/icon48.png"/>
- </div>
-
- <div id="content">
- <div id="state-intro">
- <h3>&abouthealth.intro.title;</h3>
- <div id="content-line">
- <p id="intro-enabled">&abouthealth.intro-enabled;</p>
- <p id="intro-disabled">&abouthealth.intro-disabled;</p>
- <div id="control-container">
- <button id="btn-optin" onclick="onOptInClick();">&abouthealth.optin;</button>
- <button id="btn-optout" onclick="onOptOutClick();">&abouthealth.optout;</button>
-
- <button id="details-show" onclick="onShowRawDataClick()">&abouthealth.show-raw-data;</button>
- <button id="details-hide" onclick="onHideRawDataClick()">&abouthealth.hide-raw-data;</button>
- </div>
- </div>
- </div>
- <div id="details-view">
- <p id="details-description">
- &abouthealth.details.description-start;
- <a id="details-link">&abouthealth.details-link;</a>
- &abouthealth.details.description-end;
- </p>
-
- <p id="data-no-data">&abouthealth.no-data-available;</p>
- <pre id="raw-data" style="display: none"></pre>
- </div>
-
- <div id="data-view">
- <button id="report-show" onclick="onShowReportClick()">&abouthealth.show-report;</button>
- <div id="report-view">
- <iframe id="remote-report"/>
- </div>
- </div>
- </div>
-
- <input type="hidden" id="optout-confirmationPrompt"
- confirmationPrompt_title="&abouthealth.optout.confirmationPrompt.title;"
- confirmationPrompt_message="&abouthealth.optout.confirmationPrompt.message;"
- />
+ <body onload="healthReportWrapper.init();">
+ <iframe id="remote-report"/>
</body>
</html>
--- a/browser/locales/en-US/chrome/browser/aboutHealthReport.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutHealthReport.dtd
@@ -1,31 +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/. -->
-<!-- metrics.locale-direction instead of the usual local.dir entity, so RTL can skip translating page. -->
-<!ENTITY abouthealth.locale-direction "ltr">
-
<!-- LOCALIZATION NOTE (abouthealth.pagetitle): Firefox Health Report is a proper noun in en-US, please keep this in mind. -->
<!ENTITY abouthealth.pagetitle "&brandShortName; Health Report">
-<!ENTITY abouthealth.header "&brandFullName; Health Report">
-
-<!ENTITY abouthealth.intro.title "What is &brandShortName; Health Report?">
-
-<!ENTITY abouthealth.intro-enabled "&brandFullName; collects some data about your computer and usage in order to provide you with a better browser experience.">
-<!ENTITY abouthealth.intro-disabled "You are currently not submitting usage data to &vendorShortName;. You can help us make &brandShortName; better by clicking the "&abouthealth.optin;" button.">
-
-<!ENTITY abouthealth.optin "Help make &brandShortName; better">
-<!ENTITY abouthealth.optout "Turn Off Reporting">
-
-<!ENTITY abouthealth.optout.confirmationPrompt.title "Stop data submission?">
-<!ENTITY abouthealth.optout.confirmationPrompt.message "Are you sure you want to opt out and delete all your anonymous product data stored on &vendorShortName; servers?">
-
-<!ENTITY abouthealth.show-raw-data "Show Details">
-<!ENTITY abouthealth.hide-raw-data "Hide Details">
-
-<!ENTITY abouthealth.show-report "Show &brandShortName; Report">
-
-<!ENTITY abouthealth.details.description-start "This is the data &brandFullName; is submitting in order for &brandShortName; Health Report to function. You can ">
-<!ENTITY abouthealth.details-link "learn more">
-<!ENTITY abouthealth.details.description-end " about what we collect and submit.">
-<!ENTITY abouthealth.no-data-available "There is no previous submission to display. Please check back later.">