Bug 840124 - implement postMessage API for remote report (code), r=jaws, f=gps+gavin
☠☠ backed out by 5c46d8839b7f ☠ ☠
authorMike Connor <mconnor@mozilla.com>
Thu, 14 Mar 2013 21:25:04 -0400
changeset 125517 59ef39cbab731e14dd2e2c4fe627b0693c020c6b
parent 125516 1356923ff93edb11b68682f4836d631c39ce3908
child 125518 12e2ef135ea80a3eab2b93fb7493e5a94e30c191
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersjaws
bugs840124
milestone22.0a1
Bug 840124 - implement postMessage API for remote report (code), r=jaws, f=gps+gavin
browser/base/content/abouthealthreport/abouthealth.css
browser/base/content/abouthealthreport/abouthealth.js
browser/base/content/abouthealthreport/abouthealth.xhtml
browser/locales/en-US/chrome/browser/aboutHealthReport.dtd
--- 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 &quot;&abouthealth.optin;&quot; 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.">