Bug 840124 - implement postMessage API for remote report (code), r=jaws, f=gps+gavin

--HG--
extra : rebase_source : d2ea2c4d5e237695d0f51ad35e5e3ad4dc263b61
This commit is contained in:
Mike Connor 2013-03-14 21:25:04 -04:00
parent 090ba15099
commit f7719bcd8d
4 changed files with 115 additions and 291 deletions

View File

@ -7,134 +7,9 @@ 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 {
width: 100%;
height: 100%;
min-height: 600px;
}
#report-show {
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 {
width: 100%;
height: 100%;
border: 0;
display: flex;
}

View File

@ -7,6 +7,7 @@
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)
@ -18,99 +19,114 @@ const policy = Cc["@mozilla.org/datareporting/service;1"]
.wrappedJSObject
.policy;
const prefs = new Preferences("datareporting.healthreport.about.");
const prefs = new Preferences("datareporting.healthreport.");
function getLocale() {
return Cc["@mozilla.org/chrome/chrome-registry;1"]
.getService(Ci.nsIXULChromeRegistry)
.getSelectedLocale("global");
let healthReportWrapper = {
init: function () {
reporter.onInit().then(healthReportWrapper.refreshPayload,
healthReportWrapper.handleInitFailure);
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);
},
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();
},
updatePrefState: function () {
try {
let prefs = {
enabled: policy.healthReportUploadEnabled,
}
this.injectData("prefs", prefs);
} catch (e) {
this.reportFailure(this.ERROR_PREFS_FAILED);
}
},
refreshPayload: function () {
reporter.collectAndObtainJSONPayload().then(healthReportWrapper.updatePayload,
healthReportWrapper.handlePayloadFailure);
},
updatePayload: function (data) {
healthReportWrapper.injectData("payload", data);
},
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;
let data = {
type: type,
content: content
}
let iframe = document.getElementById("remote-report");
iframe.contentWindow.postMessage(data, reportUrl);
},
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;
}
},
initRemotePage: function () {
let iframe = document.getElementById("remote-report").contentDocument;
iframe.addEventListener("RemoteHealthReportCommand",
function onCommand(e) {healthReportWrapper.handleRemoteCommand(e);},
false);
healthReportWrapper.updatePrefState();
},
// error handling
ERROR_INIT_FAILED: 1,
ERROR_PAYLOAD_FAILED: 2,
ERROR_PREFS_FAILED: 3,
reportFailure: function (error) {
let details = {
errorType: error,
}
healthReportWrapper.injectData("error", details);
},
handleInitFailure: function () {
healthReportWrapper.reportFailure(healthReportWrapper.ERROR_INIT_FAILED);
},
handlePayloadFailure: function () {
healthReportWrapper.reportFailure(healthReportWrapper.ERROR_PAYLOAD_FAILED);
},
}
function init() {
refreshWithDataSubmissionFlag(policy.healthReportUploadEnabled);
refreshJSONPayload();
document.getElementById("details-link").href = prefs.get("glossaryUrl");
}
/**
* 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");
}
}
function updateView(state="default") {
let content = document.getElementById("content");
let controlContainer = document.getElementById("control-container");
content.setAttribute("state", state);
controlContainer.setAttribute("state", state);
}
function refreshDataView(data) {
let noData = document.getElementById("data-no-data");
let dataEl = document.getElementById("raw-data");
noData.style.display = data ? "none" : "inline";
dataEl.style.display = data ? "block" : "none";
if (data) {
dataEl.textContent = JSON.stringify(data, null, 2);
}
}
/**
* Ensure the page has the latest version of the uploaded JSON payload.
*/
function refreshJSONPayload() {
reporter.getLastPayload().then(refreshDataView);
}
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;
}
policy.recordHealthReportUploadEnabled(false,
"Clicked opt out button on about page.");
refreshWithDataSubmissionFlag(false);
updateView("disabled");
}
function onShowRawDataClick() {
updateView("showDetails");
refreshJSONPayload();
}
function onHideRawDataClick() {
updateView("default");
}
function onShowReportClick() {
updateView("showReport");
document.getElementById("remote-report").src = prefs.get("reportUrl");
}
function onHideReportClick() {
updateView("default");
document.getElementById("remote-report").src = "";
}

View File

@ -22,50 +22,8 @@
<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>

View File

@ -2,30 +2,5 @@
- 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.">