2012-08-29 14:41:35 -07:00
|
|
|
/* 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/. */
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|
|
|
|
|
|
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
|
|
|
|
|
|
// JS shim that contains the callback functions to be triggered from the
|
|
|
|
// payment provider's code in order to fire DOMRequest events.
|
|
|
|
const kPaymentShimFile = "chrome://browser/content/payment.js";
|
|
|
|
|
|
|
|
// Type of MozChromEvents to handle payment dialogs.
|
|
|
|
const kOpenPaymentConfirmationEvent = "open-payment-confirmation-dialog";
|
|
|
|
const kOpenPaymentFlowEvent = "open-payment-flow-dialog";
|
|
|
|
|
2013-09-06 09:43:54 -07:00
|
|
|
const PREF_DEBUG = "dom.payment.debug";
|
|
|
|
|
2012-08-29 14:41:35 -07:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
|
|
|
|
"@mozilla.org/uuid-generator;1",
|
|
|
|
"nsIUUIDGenerator");
|
|
|
|
|
|
|
|
function PaymentUI() {
|
2013-09-06 09:43:54 -07:00
|
|
|
try {
|
|
|
|
this._debug =
|
|
|
|
Services.prefs.getPrefType(PREF_DEBUG) == Ci.nsIPrefBranch.PREF_BOOL
|
|
|
|
&& Services.prefs.getBoolPref(PREF_DEBUG);
|
|
|
|
} catch(e) {
|
|
|
|
this._debug = false;
|
|
|
|
}
|
2012-08-29 14:41:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PaymentUI.prototype = {
|
|
|
|
|
2012-12-03 12:44:58 -08:00
|
|
|
confirmPaymentRequest: function confirmPaymentRequest(aRequestId,
|
|
|
|
aRequests,
|
2012-08-29 14:41:35 -07:00
|
|
|
aSuccessCb,
|
|
|
|
aErrorCb) {
|
2012-10-16 02:28:30 -07:00
|
|
|
let _error = function _error(errorMsg) {
|
|
|
|
if (aErrorCb) {
|
2012-12-03 12:44:58 -08:00
|
|
|
aErrorCb.onresult(aRequestId, errorMsg);
|
2012-10-16 02:28:30 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-08-29 14:41:35 -07:00
|
|
|
let browser = Services.wm.getMostRecentWindow("navigator:browser");
|
|
|
|
let content = browser.getContentWindow();
|
2012-10-16 02:28:30 -07:00
|
|
|
if (!content) {
|
|
|
|
_error("NO_CONTENT_WINDOW");
|
2012-08-29 14:41:35 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The UI should listen for mozChromeEvent 'open-payment-confirmation-dialog'
|
|
|
|
// type in order to create and show the payment request confirmation frame
|
|
|
|
// embeded within a trusted dialog.
|
|
|
|
let id = kOpenPaymentConfirmationEvent + "-" + this.getRandomId();
|
|
|
|
let detail = {
|
|
|
|
type: kOpenPaymentConfirmationEvent,
|
|
|
|
id: id,
|
2013-01-22 03:29:54 -08:00
|
|
|
requestId: aRequestId,
|
2012-08-29 14:41:35 -07:00
|
|
|
paymentRequests: aRequests
|
|
|
|
};
|
|
|
|
|
|
|
|
// Once the user confirm the payment request and makes his choice, we get
|
|
|
|
// back to the DOM part to get the appropriate payment flow information
|
|
|
|
// based on the selected payment provider.
|
2013-11-26 03:13:57 -08:00
|
|
|
this._handleSelection = (function _handleSelection(evt) {
|
2012-08-29 14:41:35 -07:00
|
|
|
let msg = evt.detail;
|
|
|
|
if (msg.id != id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg.userSelection && aSuccessCb) {
|
2012-12-03 12:44:58 -08:00
|
|
|
aSuccessCb.onresult(aRequestId, msg.userSelection);
|
2012-10-16 02:28:30 -07:00
|
|
|
} else if (msg.errorMsg) {
|
|
|
|
_error(msg.errorMsg);
|
2012-08-29 14:41:35 -07:00
|
|
|
}
|
|
|
|
|
2013-11-26 03:13:57 -08:00
|
|
|
content.removeEventListener("mozContentEvent", this._handleSelection);
|
|
|
|
this._handleSelection = null;
|
|
|
|
}).bind(this);
|
|
|
|
content.addEventListener("mozContentEvent", this._handleSelection);
|
2012-08-29 14:41:35 -07:00
|
|
|
|
|
|
|
browser.shell.sendChromeEvent(detail);
|
|
|
|
},
|
|
|
|
|
2012-12-03 12:44:58 -08:00
|
|
|
showPaymentFlow: function showPaymentFlow(aRequestId,
|
|
|
|
aPaymentFlowInfo,
|
|
|
|
aErrorCb) {
|
2012-10-16 02:28:30 -07:00
|
|
|
let _error = function _error(errorMsg) {
|
|
|
|
if (aErrorCb) {
|
2012-12-03 12:44:58 -08:00
|
|
|
aErrorCb.onresult(aRequestId, errorMsg);
|
2012-10-16 02:28:30 -07:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-08-29 14:41:35 -07:00
|
|
|
// We ask the UI to browse to the selected payment flow.
|
|
|
|
let browser = Services.wm.getMostRecentWindow("navigator:browser");
|
|
|
|
let content = browser.getContentWindow();
|
2012-10-16 02:28:30 -07:00
|
|
|
if (!content) {
|
|
|
|
_error("NO_CONTENT_WINDOW");
|
2012-08-29 14:41:35 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let id = kOpenPaymentFlowEvent + "-" + this.getRandomId();
|
|
|
|
let detail = {
|
|
|
|
type: kOpenPaymentFlowEvent,
|
|
|
|
id: id,
|
2013-01-22 03:29:54 -08:00
|
|
|
requestId: aRequestId,
|
2012-08-29 14:41:35 -07:00
|
|
|
uri: aPaymentFlowInfo.uri,
|
|
|
|
method: aPaymentFlowInfo.requestMethod,
|
|
|
|
jwt: aPaymentFlowInfo.jwt
|
|
|
|
};
|
|
|
|
|
|
|
|
// At some point the UI would send the created iframe back so the
|
|
|
|
// callbacks for firing DOMRequest events can be loaded on its
|
|
|
|
// content.
|
2013-11-26 03:13:57 -08:00
|
|
|
this._loadPaymentShim = (function _loadPaymentShim(evt) {
|
|
|
|
let msg = evt.detail;
|
|
|
|
if (msg.id != id) {
|
2012-08-29 14:41:35 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-26 03:13:57 -08:00
|
|
|
if (msg.errorMsg) {
|
|
|
|
content.removeEventListener("mozContentEvent", this._loadPaymentShim);
|
|
|
|
this._loadPaymentShim = null;
|
|
|
|
_error("ERROR_LOADING_PAYMENT_SHIM: " + msg.errorMsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!msg.frame) {
|
|
|
|
content.removeEventListener("mozContentEvent", this._loadPaymentShim);
|
|
|
|
this._loadPaymentShim = null;
|
2012-10-16 02:28:30 -07:00
|
|
|
_error("ERROR_LOADING_PAYMENT_SHIM");
|
|
|
|
return;
|
|
|
|
}
|
2013-11-26 03:13:57 -08:00
|
|
|
|
|
|
|
// Try to load the payment shim file containing the payment callbacks
|
|
|
|
// in the content script.
|
|
|
|
let frame = msg.frame;
|
2012-08-29 14:41:35 -07:00
|
|
|
let frameLoader = frame.QueryInterface(Ci.nsIFrameLoaderOwner)
|
2013-11-26 03:13:57 -08:00
|
|
|
.frameLoader;
|
2012-08-29 14:41:35 -07:00
|
|
|
let mm = frameLoader.messageManager;
|
|
|
|
try {
|
2013-12-03 19:44:28 -08:00
|
|
|
mm.loadFrameScript(kPaymentShimFile, true);
|
2012-12-03 12:44:58 -08:00
|
|
|
mm.sendAsyncMessage("Payment:LoadShim", { requestId: aRequestId });
|
2012-08-29 14:41:35 -07:00
|
|
|
} catch (e) {
|
2013-09-06 09:43:54 -07:00
|
|
|
if (this._debug) {
|
|
|
|
this.LOG("Error loading " + kPaymentShimFile + " as a frame script: "
|
|
|
|
+ e);
|
|
|
|
}
|
2012-10-16 02:28:30 -07:00
|
|
|
_error("ERROR_LOADING_PAYMENT_SHIM");
|
2012-08-29 14:41:35 -07:00
|
|
|
} finally {
|
2013-11-26 03:13:57 -08:00
|
|
|
content.removeEventListener("mozContentEvent", this._loadPaymentShim);
|
|
|
|
this._loadPaymentShim = null;
|
2012-08-29 14:41:35 -07:00
|
|
|
}
|
2013-11-26 03:13:57 -08:00
|
|
|
}).bind(this);
|
|
|
|
content.addEventListener("mozContentEvent", this._loadPaymentShim);
|
2012-10-16 02:28:30 -07:00
|
|
|
|
|
|
|
// We also listen for UI notifications about a closed payment flow. The UI
|
|
|
|
// should provide the reason of the closure within the 'errorMsg' parameter
|
2013-11-26 03:13:57 -08:00
|
|
|
this._notifyPayFlowClosed = (function _notifyPayFlowClosed(evt) {
|
|
|
|
let msg = evt.detail;
|
|
|
|
if (msg.id != id) {
|
2012-10-16 02:28:30 -07:00
|
|
|
return;
|
|
|
|
}
|
2013-11-26 03:13:57 -08:00
|
|
|
|
|
|
|
if (msg.type != 'cancel') {
|
2012-10-16 02:28:30 -07:00
|
|
|
return;
|
|
|
|
}
|
2013-11-26 03:13:57 -08:00
|
|
|
|
|
|
|
if (msg.errorMsg) {
|
|
|
|
_error(msg.errorMsg);
|
|
|
|
}
|
|
|
|
content.removeEventListener("mozContentEvent",
|
|
|
|
this._notifyPayFlowClosed);
|
|
|
|
this._notifyPayFlowClosed = null;
|
|
|
|
}).bind(this);
|
2012-10-16 02:28:30 -07:00
|
|
|
content.addEventListener("mozContentEvent",
|
2013-11-26 03:13:57 -08:00
|
|
|
this._notifyPayFlowClosed);
|
2012-08-29 14:41:35 -07:00
|
|
|
|
|
|
|
browser.shell.sendChromeEvent(detail);
|
|
|
|
},
|
|
|
|
|
2012-10-16 02:28:30 -07:00
|
|
|
cleanup: function cleanup() {
|
|
|
|
let browser = Services.wm.getMostRecentWindow("navigator:browser");
|
|
|
|
let content = browser.getContentWindow();
|
|
|
|
if (!content) {
|
|
|
|
return;
|
|
|
|
}
|
2013-11-26 03:13:57 -08:00
|
|
|
|
|
|
|
if (this._handleSelection) {
|
|
|
|
content.removeEventListener("mozContentEvent", this._handleSelection);
|
|
|
|
this._handleSelection = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this._notifyPayFlowClosed) {
|
|
|
|
content.removeEventListener("mozContentEvent", this._notifyPayFlowClosed);
|
|
|
|
this._notifyPayFlowClosed = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this._loadPaymentShim) {
|
|
|
|
content.removeEventListener("mozContentEvent", this._loadPaymentShim);
|
|
|
|
this._loadPaymentShim = null;
|
|
|
|
}
|
2012-10-16 02:28:30 -07:00
|
|
|
},
|
|
|
|
|
2012-08-29 14:41:35 -07:00
|
|
|
getRandomId: function getRandomId() {
|
|
|
|
return uuidgen.generateUUID().toString();
|
|
|
|
},
|
|
|
|
|
2013-09-06 09:43:54 -07:00
|
|
|
LOG: function LOG(s) {
|
|
|
|
if (!this._debug) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dump("-*- PaymentGlue: " + s + "\n");
|
|
|
|
},
|
|
|
|
|
2012-08-29 14:41:35 -07:00
|
|
|
classID: Components.ID("{8b83eabc-7929-47f4-8b48-4dea8d887e4b}"),
|
|
|
|
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue])
|
|
|
|
}
|
|
|
|
|
2012-10-31 09:13:28 -07:00
|
|
|
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentUI]);
|