| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * @fileoverview JavaScript implementation of the Payment Request API. Conforms |
| 7 * to the 18 July 2016 editor's draft at |
| 8 * https://w3c.github.io/browser-payment-api/. |
| 9 * |
| 10 * This is a minimal implementation that sends data to the app side to present |
| 11 * the user interface. When loaded, installs the API onto the window object. |
| 12 */ |
| 13 |
| 14 // Namespace for all PaymentRequest implementations. __gCrWeb must have already |
| 15 // been defined. |
| 16 __gCrWeb.paymentRequestManager = { |
| 17 /** |
| 18 * The pending PaymentRequest, if any. Used by the app side to invoke the |
| 19 * associated resolve or reject function. |
| 20 * @type {window.PaymentRequest} |
| 21 */ |
| 22 pendingRequest: null, |
| 23 |
| 24 /** |
| 25 * The pending PaymentResponse, if any. Used by the app side to invoke the |
| 26 * associated resolve or reject function. |
| 27 * @type {window.PaymentResponse} |
| 28 */ |
| 29 pendingResponse: null |
| 30 }; |
| 31 __gCrWeb['paymentRequestManager'] = __gCrWeb.paymentRequestManager; |
| 32 |
| 33 /** @typedef {{ |
| 34 * methodData: !Array.<window.PaymentMethodData>, |
| 35 * details: !window.PaymentDetails, |
| 36 * options: (window.PaymentOptions|undefined) |
| 37 * }} |
| 38 */ |
| 39 __gCrWeb.paymentRequestManager.SerializedPaymentRequest; |
| 40 |
| 41 /** @typedef {{ |
| 42 * methodName: string, |
| 43 * details: Object |
| 44 * }} |
| 45 */ |
| 46 __gCrWeb.paymentRequestManager.SerializedPaymentResponse; |
| 47 |
| 48 /** |
| 49 * A request to make a payment. |
| 50 * |
| 51 * @param {!Array.<window.PaymentMethodData>} methodData Payment method |
| 52 * identifiers for the payment methods that the web site accepts and any |
| 53 * associated payment method specific data. |
| 54 * @param {!window.PaymentDetails} details Information about the transaction |
| 55 * that the user is being asked to complete such as the line items in an |
| 56 * order. |
| 57 * @param {window.PaymentOptions=} opt_options Information about what |
| 58 * options the web page wishes to use from the payment request system. |
| 59 * @constructor |
| 60 * @implements {EventTarget} |
| 61 */ |
| 62 window.PaymentRequest = function(methodData, details, opt_options) { |
| 63 if (window.top != window.self) { |
| 64 throw new Error( |
| 65 'PaymentRequest can only be used in the top-level context.'); |
| 66 } |
| 67 |
| 68 if (methodData.length == 0) |
| 69 throw new Error('The length of the methodData parameter must be > 0.'); |
| 70 |
| 71 for (var i = 0; i < methodData.length; i++) { |
| 72 if (methodData[i].supportedMethods.length == 0) |
| 73 throw new Error( |
| 74 'The length of the supportedMethods parameter must be > 0.'); |
| 75 } |
| 76 |
| 77 // TODO(crbug.com/602666): Perform other validation per spec. |
| 78 |
| 79 /** |
| 80 * @type {!Array.<window.PaymentMethodData>} |
| 81 */ |
| 82 this.methodData = methodData; |
| 83 |
| 84 /** |
| 85 * @type {!window.PaymentDetails} |
| 86 */ |
| 87 this.details = details; |
| 88 |
| 89 /** |
| 90 * @type {?window.PaymentOptions} |
| 91 */ |
| 92 this.options = opt_options || null; |
| 93 |
| 94 /** |
| 95 * Shipping address selected by the user. |
| 96 * @type {?window.PaymentAddress} |
| 97 */ |
| 98 this.shippingAddress = null; |
| 99 |
| 100 /** |
| 101 * Shipping option selected by the user. |
| 102 * @type {?string} |
| 103 */ |
| 104 this.shippingOption = null; |
| 105 |
| 106 /** |
| 107 * The state of this request, used to govern its lifecycle. |
| 108 * TODO(crbug.com/602666): Implement state transitions per spec. |
| 109 * @type {string} |
| 110 * @private |
| 111 */ |
| 112 this.state = 'created'; |
| 113 |
| 114 /** |
| 115 * The pending resolve function provided to the Promise returned by show(). |
| 116 * @type {?function(window.PaymentResponse)} |
| 117 * @private |
| 118 */ |
| 119 this.resolve_ = null; |
| 120 |
| 121 /** |
| 122 * The pending reject function provided to the Promise returned by show(). |
| 123 * @type {?function(string)} |
| 124 * @private |
| 125 */ |
| 126 this.reject_ = null; |
| 127 }; |
| 128 |
| 129 // TODO(crbug.com/602666): Add the event handling logic. |
| 130 window.PaymentRequest.prototype.addEventListener = function(type, listener) { |
| 131 }; |
| 132 |
| 133 window.PaymentRequest.prototype.removeEventListener = function(type, listener) { |
| 134 }; |
| 135 |
| 136 window.PaymentRequest.prototype.dispatchEvent = function(event) { |
| 137 }; |
| 138 |
| 139 /** |
| 140 * Presents the PaymentRequest UI to the user. |
| 141 * @return {!Promise<window.PaymentResponse>} A promise to notify the caller of |
| 142 * whether the user accepted or rejected the request. |
| 143 */ |
| 144 window.PaymentRequest.prototype.show = function() { |
| 145 if (__gCrWeb['paymentRequestManager'].pendingRequest) { |
| 146 throw new Error('Only one PaymentRequest may be shown at a time.'); |
| 147 } |
| 148 __gCrWeb['paymentRequestManager'].pendingRequest = this; |
| 149 |
| 150 var message = { |
| 151 'command': 'paymentRequest.requestShow', |
| 152 'payment_request': this.serialize() |
| 153 }; |
| 154 __gCrWeb.message.invokeOnHost(message); |
| 155 |
| 156 var self = this; |
| 157 return new Promise(function(resolve, reject) { |
| 158 self.resolve_ = resolve; |
| 159 self.reject_ = reject; |
| 160 }); |
| 161 }; |
| 162 |
| 163 /** |
| 164 * Resolves the pending Promise. Should only be called by the app-side logic. |
| 165 * @param {!__gCrWeb.paymentRequestManager.SerializedPaymentResponse} |
| 166 * paymentResponseData The response to provide to the resolve function of |
| 167 * the Promise. |
| 168 */ |
| 169 window.PaymentRequest.prototype.resolve = function(paymentResponseData) { |
| 170 if (!paymentResponseData) { |
| 171 throw new Error("Internal PaymentRequest error: PaymentResponse missing."); |
| 172 } |
| 173 |
| 174 if (!this.resolve_) { |
| 175 throw new Error("Internal PaymentRequest error: resolve function missing."); |
| 176 } |
| 177 |
| 178 var paymentResponse = null; |
| 179 try { |
| 180 paymentResponse = window.PaymentResponse.parse(paymentResponseData); |
| 181 } catch (e) { |
| 182 throw new Error( |
| 183 "Internal PaymentRequest error: failed to parse PaymentResponse data."); |
| 184 } |
| 185 this.resolve_(paymentResponse); |
| 186 |
| 187 this.resolve_ = null; |
| 188 this.reject_ = null; |
| 189 __gCrWeb['paymentRequestManager'].pendingRequest = null; |
| 190 } |
| 191 |
| 192 /** |
| 193 * Rejects the pending Promise. Should only be called by the app-side logic. |
| 194 * @param {!string} message An error message explaining why the Promise is being |
| 195 * rejected. |
| 196 */ |
| 197 window.PaymentRequest.prototype.reject = function(message) { |
| 198 if (!this.reject_) { |
| 199 throw new Error("Internal PaymentRequest error: reject function missing."); |
| 200 } |
| 201 |
| 202 this.reject_(message); |
| 203 |
| 204 this.resolve_ = null; |
| 205 this.reject_ = null; |
| 206 __gCrWeb['paymentRequestManager'].pendingRequest = null; |
| 207 } |
| 208 |
| 209 /** |
| 210 * Returns a simple object representation of this payment request suitable for |
| 211 * sending to the app side. |
| 212 * @return {__gCrWeb.paymentRequestManager.SerializedPaymentRequest} |
| 213 */ |
| 214 window.PaymentRequest.prototype.serialize = function() { |
| 215 var serialized = { |
| 216 'methodData': this.methodData, |
| 217 'details': this.details, |
| 218 }; |
| 219 if (this.options) |
| 220 serialized['options'] = this.options; |
| 221 return serialized; |
| 222 }; |
| 223 |
| 224 /** @typedef {{ |
| 225 * supportedMethods: Array<string>, |
| 226 * data: (Object|undefined) |
| 227 * }} |
| 228 */ |
| 229 window.PaymentMethodData; |
| 230 |
| 231 /** @typedef {{ |
| 232 * currency: string, |
| 233 * value: string |
| 234 * }} |
| 235 */ |
| 236 window.PaymentCurrencyAmount; |
| 237 |
| 238 /** @typedef {{ |
| 239 * total: (window.PaymentItem|undefined), |
| 240 * displayItems: (Array<window.PaymentItem>|undefined), |
| 241 * shippingOptions: (Array<window.PaymentShippingOption>|undefined), |
| 242 * modifiers: (Array<window.PaymentDetailsModifier>|undefined) |
| 243 * }} |
| 244 */ |
| 245 window.PaymentDetails; |
| 246 |
| 247 /** @typedef {{ |
| 248 * supportedMethods: Array<string>, |
| 249 * total: (window.PaymentItem|undefined), |
| 250 * additionalDisplayItems: (Array<window.PaymentItem>|undefined) |
| 251 * }} |
| 252 */ |
| 253 window.PaymentDetailsModifier; |
| 254 |
| 255 /** @typedef {{ |
| 256 * requestPayerEmail: (boolean|undefined), |
| 257 * requestPayerPhone: (boolean|undefined), |
| 258 * requestShipping: (boolean|undefined) |
| 259 * }} |
| 260 */ |
| 261 window.PaymentOptions; |
| 262 |
| 263 /** @typedef {{ |
| 264 * label: string, |
| 265 * amount: window.PaymentCurrencyAmount |
| 266 * }} |
| 267 */ |
| 268 window.PaymentItem; |
| 269 |
| 270 // TODO(crbug.com/602666): Convert this to a class with readonly properties. |
| 271 /** @typedef {{ |
| 272 * country: string, |
| 273 * addressLine: Array<string>, |
| 274 * region: string, |
| 275 * city: string, |
| 276 * dependentLocality: string, |
| 277 * postalCode: string, |
| 278 * sortingCode: string, |
| 279 * languageCode: string, |
| 280 * organization: string, |
| 281 * recipient: string, |
| 282 * phone: string |
| 283 * }} |
| 284 */ |
| 285 window.PaymentAddress; |
| 286 |
| 287 /** @typedef {{ |
| 288 * id: string, |
| 289 * label: string, |
| 290 * amount: window.PaymentCurrencyAmount, |
| 291 * selected: boolean |
| 292 * }} |
| 293 */ |
| 294 window.PaymentShippingOption; |
| 295 |
| 296 /** |
| 297 * A response to a request to make a payment. Represents the choices made by the |
| 298 * user and provided to the web page through the resolve function of the Promise |
| 299 * returned by PaymentRequest.show(). |
| 300 * |
| 301 * @param {string} methodName The payment method identifier for the payment |
| 302 * method that the user selected to fulfil the transaction. |
| 303 * @param {Object} details An object that provides a payment method specific |
| 304 * message used by the merchant to process the transaction and determine |
| 305 * successful fund transfer. |
| 306 * @constructor |
| 307 * @private |
| 308 */ |
| 309 window.PaymentResponse = function(methodName, details) { |
| 310 /** |
| 311 * @type {string} |
| 312 */ |
| 313 this.methodName = methodName; |
| 314 |
| 315 /** |
| 316 * @type {Object} |
| 317 */ |
| 318 this.details = details; |
| 319 |
| 320 /** |
| 321 * The pending resolve function provided to the Promise returned by |
| 322 * complete(). |
| 323 * @type {?function()} |
| 324 * @private |
| 325 */ |
| 326 this.resolve_ = null; |
| 327 |
| 328 /** |
| 329 * The pending reject function provided to the Promise returned by complete(). |
| 330 * @type {?function(string)} |
| 331 * @private |
| 332 */ |
| 333 this.reject_ = null; |
| 334 }; |
| 335 |
| 336 /** |
| 337 * Communicates the result of processing the payment. |
| 338 * @param {boolean} success Indicates whether processing succeeded. |
| 339 * @return {!Promise} A promise to notify the caller when the user interface has |
| 340 * been closed. |
| 341 */ |
| 342 window.PaymentResponse.prototype.complete = function(success) { |
| 343 if (__gCrWeb['paymentRequestManager'].pendingResponse) { |
| 344 throw new Error( |
| 345 'Internal PaymentRequest error: A response is already pending.'); |
| 346 } |
| 347 __gCrWeb['paymentRequestManager'].pendingResponse = this; |
| 348 |
| 349 var message = { |
| 350 'command': 'paymentRequest.responseComplete' |
| 351 }; |
| 352 __gCrWeb.message.invokeOnHost(message); |
| 353 |
| 354 var self = this; |
| 355 return new Promise(function(resolve, reject) { |
| 356 self.resolve_ = resolve; |
| 357 self.reject_ = reject; |
| 358 }); |
| 359 }; |
| 360 |
| 361 /** |
| 362 * Resolves the pending Promise. Should only be called by the app-side logic. |
| 363 */ |
| 364 window.PaymentResponse.prototype.resolve = function() { |
| 365 if (!this.resolve_) { |
| 366 throw new Error("Internal PaymentRequest error: resolve function missing."); |
| 367 } |
| 368 |
| 369 this.resolve_(); |
| 370 |
| 371 this.resolve_ = null; |
| 372 this.reject_ = null; |
| 373 __gCrWeb['paymentRequestManager'].pendingResponse = null; |
| 374 } |
| 375 |
| 376 /** |
| 377 * Rejects the pending Promise. Should only be called by the app-side logic. |
| 378 * @param {!string} message An error message explaining why the Promise is being |
| 379 * rejected. |
| 380 */ |
| 381 window.PaymentResponse.prototype.reject = function(message) { |
| 382 if (!this.reject_) { |
| 383 throw new Error("Internal PaymentRequest error: reject function missing."); |
| 384 } |
| 385 |
| 386 this.reject_(message); |
| 387 |
| 388 this.resolve_ = null; |
| 389 this.reject_ = null; |
| 390 __gCrWeb['paymentRequestManager'].pendingResponse = null; |
| 391 } |
| 392 |
| 393 /** |
| 394 * Parses |paymentResponseData| into a PaymentResponse object. |
| 395 * @param {!__gCrWeb.paymentRequestManager.SerializedPaymentResponse} |
| 396 * paymentResponseData A simple object representation of a PaymentResponse. |
| 397 * @return {window.PaymentResponse} A PaymentResponse object. |
| 398 */ |
| 399 window.PaymentResponse.parse = function(paymentResponseData) { |
| 400 return new window.PaymentResponse(paymentResponseData['methodName'], |
| 401 paymentResponseData['details']); |
| 402 }; |
| OLD | NEW |