michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: "use strict"; michael@0: michael@0: const { interfaces: Ci, utils: Cu } = Components; michael@0: michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Cu.import("resource://gre/modules/Services.jsm"); michael@0: michael@0: XPCOMUtils.defineLazyServiceGetter(this, "cpmm", michael@0: "@mozilla.org/childprocessmessagemanager;1", michael@0: "nsIMessageSender"); michael@0: michael@0: function paymentSuccess(aRequestId) { michael@0: return function(aResult) { michael@0: closePaymentWindow(aRequestId, function() { michael@0: cpmm.sendAsyncMessage("Payment:Success", { requestId: aRequestId, michael@0: result: aResult }); michael@0: }); michael@0: }; michael@0: } michael@0: michael@0: function paymentFailed(aRequestId) { michael@0: return function(aErrorMsg) { michael@0: closePaymentWindow(aRequestId, function() { michael@0: cpmm.sendAsyncMessage("Payment:Failed", { requestId: aRequestId, michael@0: errorMsg: aErrorMsg }); michael@0: }); michael@0: }; michael@0: } michael@0: michael@0: let payments = {}; michael@0: michael@0: function closePaymentWindow(aId, aCallback) { michael@0: if (payments[aId]) { michael@0: payments[aId].handled = true; michael@0: payments[aId].win.close(); michael@0: payments[aId] = null; michael@0: } michael@0: michael@0: aCallback(); michael@0: } michael@0: michael@0: function PaymentUI() {} michael@0: michael@0: PaymentUI.prototype = { michael@0: classID: Components.ID("{ede1124f-72e8-4a31-9567-3270d46f21fb}"), michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIPaymentUIGlue]), michael@0: michael@0: confirmPaymentRequest: function(aRequestId, aRequests, aSuccessCb, aErrorCb) { michael@0: // If there's only one payment provider that will work, just move on michael@0: // without prompting the user. michael@0: if (aRequests.length == 1) { michael@0: aSuccessCb.onresult(aRequestId, aRequests[0].type); michael@0: return; michael@0: } michael@0: michael@0: let items = []; michael@0: michael@0: // Otherwise, let the user select a payment provider from a list. michael@0: for (let i = 0; i < aRequests.length; i++) { michael@0: let request = aRequests[i]; michael@0: let requestText = request.providerName; michael@0: if (request.productPrice && Array.isArray(request.productPrice)) { michael@0: // We should guess the user currency and use that instead. michael@0: requestText += " (" + request.productPrice[0].amount + " " + michael@0: request.productPrice[0].currency + ")"; michael@0: } michael@0: items.push(requestText); michael@0: } michael@0: michael@0: let selected = {}; michael@0: michael@0: let bundle = Services.strings. michael@0: createBundle("chrome://webapprt/locale/webapp.properties"); michael@0: let result = Services.prompt. michael@0: select(null, bundle.GetStringFromName("paymentDialog.title"), michael@0: bundle.GetStringFromName("paymentDialog.message"), michael@0: items.length, items, selected); michael@0: if (result) { michael@0: aSuccessCb.onresult(aRequestId, michael@0: aRequests[selected.value].type); michael@0: } else { michael@0: aErrorCb.onresult(aRequestId, "USER_CANCELLED"); michael@0: } michael@0: }, michael@0: michael@0: showPaymentFlow: function(aRequestId, aPaymentFlowInfo, aErrorCb) { michael@0: let win = Services.ww. michael@0: openWindow(null, michael@0: "chrome://webapprt/content/webapp.xul", michael@0: "_blank", michael@0: "chrome,dialog=no,resizable,scrollbars,centerscreen", michael@0: null); michael@0: michael@0: // Store a reference to the window so that we can close it when the payment michael@0: // succeeds or fails. michael@0: payments[aRequestId] = { win: win, handled: false }; michael@0: michael@0: // Inject paymentSuccess and paymentFailed methods into the document after michael@0: // its loaded. michael@0: win.addEventListener("DOMContentLoaded", function onDOMContentLoaded() { michael@0: win.removeEventListener("DOMContentLoaded", onDOMContentLoaded); michael@0: michael@0: let browserElement = win.document.getElementById("content"); michael@0: browserElement. michael@0: setAttribute("src", aPaymentFlowInfo.uri + aPaymentFlowInfo.jwt); michael@0: michael@0: browserElement.addEventListener("DOMWindowCreated", michael@0: function onDOMWindowCreated() { michael@0: browserElement.removeEventListener("DOMWindowCreated", michael@0: onDOMWindowCreated); michael@0: michael@0: michael@0: win.document.getElementById("content").contentDocument.defaultView michael@0: .wrappedJSObject.mozPaymentProvider = { michael@0: __exposedProps__: { michael@0: paymentSuccess: 'r', michael@0: paymentFailed: 'r' michael@0: }, michael@0: paymentSuccess: paymentSuccess(aRequestId), michael@0: paymentFailed: paymentFailed(aRequestId) michael@0: }; michael@0: }, true); michael@0: }); michael@0: michael@0: let winObserver = function(aClosedWin, aTopic) { michael@0: if (aTopic == "domwindowclosed") { michael@0: // Fail the payment if the window is closed. michael@0: if (aClosedWin == win) { michael@0: Services.ww.unregisterNotification(winObserver); michael@0: if (payments[aRequestId] && !payments[aRequestId].handled) { michael@0: aErrorCb.onresult(aRequestId, "USER_CANCELLED"); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: Services.ww.registerNotification(winObserver); michael@0: }, michael@0: michael@0: cleanup: function() { michael@0: }, michael@0: } michael@0: michael@0: this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PaymentUI]);