Bug 1402210 - Add payment UI documentation and do minor code cleanup. r=marcosc
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Thu, 21 Sep 2017 21:35:24 -0700
changeset 382559 fd4b9c72b832951abf946c050d4760c8d0b4944c
parent 382558 5870f25b4a832dccf8277548eaa83c8d80edc4a6
child 382560 7f3101566d6fc77216dd8e01e962b48fedaa18e8
push id51910
push usermozilla@noorenberghe.ca
push dateFri, 22 Sep 2017 23:31:48 +0000
treeherderautoland@fd4b9c72b832 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarcosc
bugs1402210
milestone58.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 1402210 - Add payment UI documentation and do minor code cleanup. r=marcosc MozReview-Commit-ID: Cpn5mKcEZGo
toolkit/components/payments/content/paymentDialog.js
toolkit/components/payments/content/paymentDialogFrameScript.js
toolkit/components/payments/docs/index.rst
toolkit/components/payments/moz.build
toolkit/components/payments/paymentUIService.js
toolkit/components/payments/res/paymentRequest.js
--- a/toolkit/components/payments/content/paymentDialog.js
+++ b/toolkit/components/payments/content/paymentDialog.js
@@ -1,12 +1,17 @@
 /* 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/. */
 
+/**
+ * Runs in the privileged outer dialog. Each dialog loads this script in its
+ * own scope.
+ */
+
 "use strict";
 
 const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"]
                      .getService(Ci.nsIPaymentRequestService);
 
 let PaymentDialog = {
   componentsLoaded: new Map(),
--- a/toolkit/components/payments/content/paymentDialogFrameScript.js
+++ b/toolkit/components/payments/content/paymentDialogFrameScript.js
@@ -1,37 +1,42 @@
 /* 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/. */
 
+/**
+ * This frame script only exists to mediate communications between the
+ * unprivileged frame in a content process and the privileged dialog wrapper
+ * in the UI process on the main thread.
+ *
+ * `paymentChromeToContent` messages from the privileged wrapper are converted
+ * into DOM events of the same name.
+ * `paymentContentToChrome` custom DOM events from the unprivileged frame are
+ * converted into messages of the same name.
+ *
+ * Business logic should stay out of this shim.
+ */
+
 "use strict";
 
 /* eslint-env mozilla/frame-script */
 
 const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 let PaymentFrameScript = {
   init() {
     this.defineLazyLogGetter(this, "frameScript");
     addEventListener("paymentContentToChrome", this, false, true);
 
     addMessageListener("paymentChromeToContent", this);
   },
 
   handleEvent(event) {
-    switch (event.type) {
-      case "paymentContentToChrome": {
-        this.sendToChrome(event);
-        break;
-      }
-      default: {
-        throw new Error("Unexpected event type");
-      }
-    }
+    this.sendToChrome(event);
   },
 
   receiveMessage({data: {messageType, data}}) {
     this.sendToContent(messageType, data);
   },
 
   sendToChrome({detail}) {
     let {messageType, requestId} = detail;
new file mode 100644
--- /dev/null
+++ b/toolkit/components/payments/docs/index.rst
@@ -0,0 +1,38 @@
+==============
+WebPayments UI
+==============
+
+User Interface for the WebPayments `Payment Request API <https://w3c.github.io/browser-payment-api/>`_ and `Payment Handler API <https://w3c.github.io/payment-handler/>`_.
+
+JSDoc style comments are used within the JS files of the component. This document will focus on higher-level and shared concepts.
+
+.. toctree::
+   :maxdepth: 5
+
+Debugging
+=========
+
+Set the pref ``dom.payments.loglevel`` to "Debug".
+
+
+Communication with the DOM
+==========================
+
+Communication from the DOM to the UI happens via the `paymentUIService.js` (implementing ``nsIPaymentUIService``).
+The UI talks to the DOM code via the ``nsIPaymentRequestService`` interface.
+
+
+Dialog Architecture
+===================
+
+Privileged wrapper XHTML document (paymentDialog.xhtml) containing a remote ``<iframe mozbrowser="true" remote="true">`` containing unprivileged XHTML (paymentRequest.xhtml).
+Keeping the dialog contents unprivileged is useful since the dialog will render payment line items and shipping options that are provided by web developers and should therefore be considered untrusted.
+In order to communicate across the process boundary a privileged frame script (`paymentDialogFrameScript.js`) is loaded into the iframe to relay messages.
+This is because the unprivileged document cannot access message managers.
+Instead, all communication across the privileged/unprivileged boundary is done via custom DOM events:
+
+* A ``paymentContentToChrome`` event is dispatched when the dialog contents want to communicate with the privileged dialog wrapper.
+* A ``paymentChromeToContent`` event is dispatched on the ``document`` with the ``detail`` property populated when the privileged dialog wrapper communicates with the unprivileged dialog.
+
+These events are converted to/from message manager messages of the same name to communicate to the other process.
+The purpose of `paymentDialogFrameScript.js` is to simply convert unprivileged DOM events to/from messages from the other process.
--- a/toolkit/components/payments/moz.build
+++ b/toolkit/components/payments/moz.build
@@ -1,16 +1,21 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 BROWSER_CHROME_MANIFESTS += ['test/browser/browser.ini']
 
+with Files('**'):
+    BUG_COMPONENT = ('Toolkit', 'WebPayments UI')
+
 EXTRA_COMPONENTS += [
     'payments.manifest',
     'paymentUIService.js',
 ]
 
 EXTRA_JS_MODULES += []
 
 JAR_MANIFESTS += ['jar.mn']
+
+SPHINX_TREES['docs'] = 'docs'
--- a/toolkit/components/payments/paymentUIService.js
+++ b/toolkit/components/payments/paymentUIService.js
@@ -1,17 +1,26 @@
 /* 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/. */
 
+/**
+ * Singleton service acting as glue between the DOM APIs and the payment dialog UI.
+ *
+ * Communication from the DOM to the UI happens via the nsIPaymentUIService interface.
+ * The UI talks to the DOM code via the nsIPaymentRequestService interface.
+ * PaymentUIService is started by the DOM code lazily.
+ *
+ * For now the UI is shown in a native dialog but that is likely to change.
+ * Tests should try to avoid relying on that implementation detail.
+ */
+
 "use strict";
 
 const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
-// eslint-disable-next-line no-unused-vars
-const DIALOG_URL = "chrome://payments/content/paymentDialog.xhtml";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this,
                                    "paymentSrv",
                                    "@mozilla.org/dom/payments/payment-request-service;1",
                                    "nsIPaymentRequestService");
@@ -30,22 +39,25 @@ function PaymentUIService() {
   this.wrappedJSObject = this;
   defineLazyLogGetter(this, "Payment UI Service");
   this.log.debug("constructor");
 }
 
 PaymentUIService.prototype = {
   classID: Components.ID("{01f8bd55-9017-438b-85ec-7c15d2b35cdc}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIService]),
+  DIALOG_URL: "chrome://payments/content/paymentDialog.xhtml",
   REQUEST_ID_PREFIX: "paymentRequest-",
 
+  // nsIPaymentUIService implementation:
+
   showPayment(requestId) {
-    this.log.debug("showPayment");
+    this.log.debug(`showPayment: ${requestId}`);
     let chromeWindow = Services.wm.getMostRecentWindow("navigator:browser");
-    chromeWindow.openDialog(DIALOG_URL,
+    chromeWindow.openDialog(this.DIALOG_URL,
                             `${this.REQUEST_ID_PREFIX}${requestId}`,
                             "modal,dialog,centerscreen",
                             {requestId});
   },
 
   abortPayment(requestId) {
     this.log.debug(`abortPayment: ${requestId}`);
     let abortResponse = Cc["@mozilla.org/dom/payments/payment-abort-action-response;1"]
@@ -67,23 +79,25 @@ PaymentUIService.prototype = {
       Ci.nsIPaymentActionResponse.ABORT_SUCCEEDED :
       Ci.nsIPaymentActionResponse.ABORT_FAILED;
 
     abortResponse.init(requestId, response);
     paymentSrv.respondPayment(abortResponse);
   },
 
   completePayment(requestId) {
+    this.log.debug(`completePayment: ${requestId}`);
     let completeResponse = Cc["@mozilla.org/dom/payments/payment-complete-action-response;1"]
                              .createInstance(Ci.nsIPaymentCompleteActionResponse);
     completeResponse.init(requestId, Ci.nsIPaymentActionResponse.COMPLTETE_SUCCEEDED);
     paymentSrv.respondPayment(completeResponse.QueryInterface(Ci.nsIPaymentActionResponse));
   },
 
   updatePayment(requestId) {
+    this.log.debug(`updatePayment: ${requestId}`);
   },
 
   // other helper methods
 
   requestIdForWindow(window) {
     let windowName = window.name;
 
     return windowName.startsWith(this.REQUEST_ID_PREFIX) ?
--- a/toolkit/components/payments/res/paymentRequest.js
+++ b/toolkit/components/payments/res/paymentRequest.js
@@ -1,12 +1,18 @@
 /* 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/. */
 
+/**
+ * Loaded in the unprivileged frame of each payment dialog.
+ *
+ * Communicates with privileged code via DOM Events.
+ */
+
 "use strict";
 
 let PaymentRequest = {
   requestId: null,
 
   init() {
     // listen to content
     window.addEventListener("paymentChromeToContent", this);