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 id24459
push useremorley@mozilla.com
push dateWed, 20 Mar 2013 11:46:36 +0000
treeherdermozilla-central@1d6fe70c79c5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs840124
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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.">