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";
|
|
|
|
|
|
|
|
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
|
|
|
|
"@mozilla.org/uuid-generator;1",
|
|
|
|
"nsIUUIDGenerator");
|
|
|
|
|
|
|
|
function debug (s) {
|
|
|
|
//dump("-*- PaymentGlue: " + s + "\n");
|
|
|
|
};
|
|
|
|
|
|
|
|
function PaymentUI() {
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
content.addEventListener("mozContentEvent", function handleSelection(evt) {
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
content.removeEventListener("mozContentEvent", handleSelection);
|
|
|
|
});
|
|
|
|
|
|
|
|
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.
|
2012-10-16 02:28:30 -07:00
|
|
|
content.addEventListener("mozContentEvent", (function loadPaymentShim(evt) {
|
|
|
|
if (evt.detail.id != id) {
|
2012-08-29 14:41:35 -07:00
|
|
|
content.removeEventListener("mozContentEvent", loadPaymentShim);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to load the payment shim file containing the payment callbacks
|
|
|
|
// in the content script.
|
2012-10-16 02:28:30 -07:00
|
|
|
if (!evt.detail.frame && !evt.detail.errorMsg) {
|
|
|
|
_error("ERROR_LOADING_PAYMENT_SHIM");
|
|
|
|
return;
|
|
|
|
}
|
2012-08-29 14:41:35 -07:00
|
|
|
let frame = evt.detail.frame;
|
|
|
|
let frameLoader = frame.QueryInterface(Ci.nsIFrameLoaderOwner)
|
|
|
|
.frameLoader;
|
|
|
|
let mm = frameLoader.messageManager;
|
|
|
|
try {
|
|
|
|
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) {
|
|
|
|
debug("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 {
|
|
|
|
content.removeEventListener("mozContentEvent", loadPaymentShim);
|
|
|
|
}
|
2012-10-16 02:28:30 -07:00
|
|
|
}).bind(this));
|
|
|
|
|
|
|
|
// We also listen for UI notifications about a closed payment flow. The UI
|
|
|
|
// should provide the reason of the closure within the 'errorMsg' parameter
|
|
|
|
this._notifyPayFlowClosed = function _notifyPayFlowClosed (evt) {
|
|
|
|
if (evt.detail.id != id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (evt.detail.errorMsg) {
|
|
|
|
_error(evt.detail.errorMsg);
|
|
|
|
content.removeEventListener("mozContentEvent",
|
|
|
|
this._notifyPayFlowClosed);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
content.addEventListener("mozContentEvent",
|
|
|
|
this._notifyPayFlowClosed.bind(this));
|
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;
|
|
|
|
}
|
|
|
|
content.removeEventListener("mozContentEvent", this._notifyPayFlowClosed);
|
|
|
|
},
|
|
|
|
|
2012-08-29 14:41:35 -07:00
|
|
|
getRandomId: function getRandomId() {
|
|
|
|
return uuidgen.generateUUID().toString();
|
|
|
|
},
|
|
|
|
|
|
|
|
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]);
|