OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview JavaScript implementation of the Payment Request API. When | 6 * @fileoverview JavaScript implementation of the Payment Request API. When |
7 * loaded, installs the API onto the window object. Conforms | 7 * loaded, installs the API onto the window object. Conforms |
8 * to https://www.w3.org/TR/payment-request/. Note: This is a work in progress. | 8 * to https://www.w3.org/TR/payment-request/. Note: This is a work in progress. |
9 */ | 9 */ |
10 | 10 |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 * PaymentResponse.prototype.complete, if any. | 180 * PaymentResponse.prototype.complete, if any. |
181 * @type {window.PaymentRequest} | 181 * @type {window.PaymentRequest} |
182 */ | 182 */ |
183 __gCrWeb['paymentRequestManager'].responsePromiseResolver = null; | 183 __gCrWeb['paymentRequestManager'].responsePromiseResolver = null; |
184 | 184 |
185 /** | 185 /** |
186 * Parses |paymentResponseData| into a window.PaymentResponse object. | 186 * Parses |paymentResponseData| into a window.PaymentResponse object. |
187 * @param {!SerializedPaymentResponse} paymentResponseData | 187 * @param {!SerializedPaymentResponse} paymentResponseData |
188 * @return {window.PaymentResponse} | 188 * @return {window.PaymentResponse} |
189 */ | 189 */ |
190 var parsePaymentResponseData = function(paymentResponseData) { | 190 __gCrWeb['paymentRequestManager'].parsePaymentResponseData = function( |
| 191 paymentResponseData) { |
191 return new window.PaymentResponse( | 192 return new window.PaymentResponse( |
192 paymentResponseData['methodName'], paymentResponseData['details']); | 193 paymentResponseData['methodName'], paymentResponseData['details']); |
193 }; | 194 }; |
194 | 195 |
195 /** | 196 /** |
196 * The event that enables the web page to update the details of the payment | 197 * The event that enables the web page to update the details of the payment |
197 * request in response to a user interaction. | 198 * request in response to a user interaction. |
198 * @type {Event} | 199 * @type {Event} |
199 */ | 200 */ |
200 var updateEvent = null; | 201 __gCrWeb['paymentRequestManager'].updateEvent = null; |
201 | 202 |
202 /** | 203 /** |
203 * Handles invocation of updateWith() on the updateEvent object. Updates the | 204 * Handles invocation of updateWith() on the updateEvent object. Updates the |
204 * payment details when the |updateWithPromise| is resolved. Throws an error | 205 * payment details when the |updateWithPromise| is resolved. Throws an error |
205 * if |updateWithPromise| is not a valid instance of Promise or if it fulfills | 206 * if |updateWithPromise| is not a valid instance of Promise or if it fulfills |
206 * with an invalid instance of window.PaymentDetails. | 207 * with an invalid instance of window.PaymentDetails. |
207 * @param {?Promise<?window.PaymentDetails|undefined>|undefined} | 208 * @param {?Promise<?window.PaymentDetails|undefined>|undefined} |
208 * updateWithPromise | 209 * updateWithPromise |
209 */ | 210 */ |
210 var updateWith = function(updateWithPromise) { | 211 __gCrWeb['paymentRequestManager'].updateWith = function(updateWithPromise) { |
211 // Check to see |updateWithPromise| is an instance of Promise. | 212 // Check to see |updateWithPromise| is an instance of Promise. |
212 if (!updateWithPromise || !(updateWithPromise.then instanceof Function) || | 213 if (!updateWithPromise || !(updateWithPromise.then instanceof Function) || |
213 !(updateWithPromise.catch instanceof Function)) { | 214 !(updateWithPromise.catch instanceof Function)) { |
214 throw new TypeError('An instance of Promise must be provided'); | 215 throw new TypeError('An instance of Promise must be provided'); |
215 } | 216 } |
216 | 217 |
217 updateWithPromise | 218 updateWithPromise |
218 .then(function(paymentDetails) { | 219 .then(function(paymentDetails) { |
219 if (!paymentDetails) | 220 if (!paymentDetails) |
220 throw new TypeError( | 221 throw new TypeError( |
221 'An instance of PaymentDetails must be provided.'); | 222 'An instance of PaymentDetails must be provided.'); |
222 | 223 |
223 var message = { | 224 var message = { |
224 'command': 'paymentRequest.updatePaymentDetails', | 225 'command': 'paymentRequest.updatePaymentDetails', |
225 'payment_details': paymentDetails, | 226 'payment_details': paymentDetails, |
226 }; | 227 }; |
227 __gCrWeb.message.invokeOnHost(message); | 228 __gCrWeb.message.invokeOnHost(message); |
228 | 229 |
229 updateEvent = null; | 230 __gCrWeb['paymentRequestManager'].updateEvent = null; |
230 }) | 231 }) |
231 .catch(function() { | 232 .catch(function() { |
232 var message = { | 233 var message = { |
233 'command': 'paymentRequest.requestCancel', | 234 'command': 'paymentRequest.requestCancel', |
234 }; | 235 }; |
235 __gCrWeb.message.invokeOnHost(message); | 236 __gCrWeb.message.invokeOnHost(message); |
236 | 237 |
237 updateEvent = null; | 238 __gCrWeb['paymentRequestManager'].updateEvent = null; |
238 }); | 239 }); |
239 }; | 240 }; |
240 | 241 |
241 /** | 242 /** |
242 * Resolves the pending PaymentRequest. | 243 * Resolves the pending PaymentRequest. |
243 * @param {!SerializedPaymentResponse} paymentResponseData The response to | 244 * @param {!SerializedPaymentResponse} paymentResponseData The response to |
244 * provide to the resolve function of the Promise. | 245 * provide to the resolve function of the Promise. |
245 */ | 246 */ |
246 __gCrWeb['paymentRequestManager'].resolveRequestPromise = function( | 247 __gCrWeb['paymentRequestManager'].resolveRequestPromise = function( |
247 paymentResponseData) { | 248 paymentResponseData) { |
248 if (!__gCrWeb['paymentRequestManager'].requestPromiseResolver) { | 249 if (!__gCrWeb['paymentRequestManager'].requestPromiseResolver) { |
249 throw new Error('Internal PaymentRequest error: No Promise to resolve.'); | 250 throw new Error('Internal PaymentRequest error: No Promise to resolve.'); |
250 } | 251 } |
251 | 252 |
252 if (!paymentResponseData) { | 253 if (!paymentResponseData) { |
253 __gCrWeb['paymentRequestManager'].rejectRequestPromise( | 254 __gCrWeb['paymentRequestManager'].rejectRequestPromise( |
254 'Internal PaymentRequest error: PaymentResponse missing.'); | 255 'Internal PaymentRequest error: PaymentResponse missing.'); |
255 } | 256 } |
256 | 257 |
257 var paymentResponse = null; | 258 var paymentResponse = null; |
258 try { | 259 try { |
259 paymentResponse = parsePaymentResponseData(paymentResponseData); | 260 paymentResponse = |
| 261 __gCrWeb['paymentRequestManager'].parsePaymentResponseData( |
| 262 paymentResponseData); |
260 } catch (e) { | 263 } catch (e) { |
261 __gCrWeb['paymentRequestManager'].rejectRequestPromise( | 264 __gCrWeb['paymentRequestManager'].rejectRequestPromise( |
262 'Internal PaymentRequest error: failed to parse PaymentResponse.'); | 265 'Internal PaymentRequest error: failed to parse PaymentResponse.'); |
263 } | 266 } |
264 | 267 |
265 __gCrWeb['paymentRequestManager'].responsePromiseResolver = | 268 __gCrWeb['paymentRequestManager'].responsePromiseResolver = |
266 new __gCrWeb.PromiseResolver(); | 269 new __gCrWeb.PromiseResolver(); |
267 __gCrWeb['paymentRequestManager'].requestPromiseResolver.resolve( | 270 __gCrWeb['paymentRequestManager'].requestPromiseResolver.resolve( |
268 paymentResponse); | 271 paymentResponse); |
269 __gCrWeb['paymentRequestManager'].requestPromiseResolver = null; | 272 __gCrWeb['paymentRequestManager'].requestPromiseResolver = null; |
270 __gCrWeb['paymentRequestManager'].pendingRequest = null; | 273 __gCrWeb['paymentRequestManager'].pendingRequest = null; |
| 274 __gCrWeb['paymentRequestManager'].updateEvent = null; |
271 }; | 275 }; |
272 | 276 |
273 /** | 277 /** |
274 * Rejects the pending PaymentRequest. | 278 * Rejects the pending PaymentRequest. |
275 * @param {!string} message An error message explaining why the Promise is | 279 * @param {!string} message An error message explaining why the Promise is |
276 * being rejected. | 280 * being rejected. |
277 */ | 281 */ |
278 __gCrWeb['paymentRequestManager'].rejectRequestPromise = function(message) { | 282 __gCrWeb['paymentRequestManager'].rejectRequestPromise = function(message) { |
279 if (!__gCrWeb['paymentRequestManager'].requestPromiseResolver) { | 283 if (!__gCrWeb['paymentRequestManager'].requestPromiseResolver) { |
280 throw new Error( | 284 throw new Error( |
281 'Internal PaymentRequest error: No Promise to reject. ', | 285 'Internal PaymentRequest error: No Promise to reject. ', |
282 'Message was: ', message); | 286 'Message was: ', message); |
283 } | 287 } |
284 | 288 |
285 __gCrWeb['paymentRequestManager'].requestPromiseResolver.reject(message); | 289 __gCrWeb['paymentRequestManager'].requestPromiseResolver.reject(message); |
286 __gCrWeb['paymentRequestManager'].requestPromiseResolver = null; | 290 __gCrWeb['paymentRequestManager'].requestPromiseResolver = null; |
287 __gCrWeb['paymentRequestManager'].pendingRequest = null; | 291 __gCrWeb['paymentRequestManager'].pendingRequest = null; |
| 292 __gCrWeb['paymentRequestManager'].updateEvent = null; |
288 }; | 293 }; |
289 | 294 |
290 /** | 295 /** |
291 * Serializes |paymentRequest| to a SerializedPaymentRequest object. | 296 * Serializes |paymentRequest| to a SerializedPaymentRequest object. |
292 * @param {window.PaymentRequest} paymentRequest | 297 * @param {window.PaymentRequest} paymentRequest |
293 * @return {SerializedPaymentRequest} | 298 * @return {SerializedPaymentRequest} |
294 */ | 299 */ |
295 __gCrWeb['paymentRequestManager'].serializePaymentRequest = function( | 300 __gCrWeb['paymentRequestManager'].serializePaymentRequest = function( |
296 paymentRequest) { | 301 paymentRequest) { |
297 var serialized = { | 302 var serialized = { |
(...skipping 24 matching lines...) Expand all Loading... |
322 */ | 327 */ |
323 __gCrWeb['paymentRequestManager'].updateShippingOptionAndDispatchEvent = | 328 __gCrWeb['paymentRequestManager'].updateShippingOptionAndDispatchEvent = |
324 function(shippingOptionID) { | 329 function(shippingOptionID) { |
325 if (!__gCrWeb['paymentRequestManager'].pendingRequest) { | 330 if (!__gCrWeb['paymentRequestManager'].pendingRequest) { |
326 __gCrWeb['paymentRequestManager'].rejectRequestPromise( | 331 __gCrWeb['paymentRequestManager'].rejectRequestPromise( |
327 'Internal PaymentRequest error: No pending request.'); | 332 'Internal PaymentRequest error: No pending request.'); |
328 } | 333 } |
329 | 334 |
330 var pendingRequest = __gCrWeb['paymentRequestManager'].pendingRequest; | 335 var pendingRequest = __gCrWeb['paymentRequestManager'].pendingRequest; |
331 | 336 |
332 if (updateEvent) { | 337 if (__gCrWeb['paymentRequestManager'].updateEvent) { |
333 __gCrWeb['paymentRequestManager'].rejectRequestPromise( | 338 __gCrWeb['paymentRequestManager'].rejectRequestPromise( |
334 'Internal PaymentRequest error: Only one update may take ' + | 339 'Internal PaymentRequest error: Only one update may take ' + |
335 'place at a time.'); | 340 'place at a time.'); |
336 } | 341 } |
337 | 342 |
338 pendingRequest.shippingOption = shippingOptionID; | 343 pendingRequest.shippingOption = shippingOptionID; |
339 | 344 |
340 updateEvent = new Event( | 345 __gCrWeb['paymentRequestManager'].updateEvent = new Event( |
341 'shippingoptionchange', {'bubbles': true, 'cancelable': false}); | 346 'shippingoptionchange', {'bubbles': true, 'cancelable': false}); |
342 Object.defineProperty(updateEvent, 'updateWith', {value: updateWith}); | 347 |
| 348 Object.defineProperty(__gCrWeb['paymentRequestManager'].updateEvent, |
| 349 'updateWith', {value: __gCrWeb['paymentRequestManager'].updateWith}); |
343 | 350 |
344 // setTimeout() is used in order to return immediately. Otherwise the | 351 // setTimeout() is used in order to return immediately. Otherwise the |
345 // dispatchEvent call waits for all event handlers to return, which could | 352 // dispatchEvent call waits for all event handlers to return, which could |
346 // cause a ReentryGuard failure. | 353 // cause a ReentryGuard failure. |
347 window.setTimeout(function() { | 354 window.setTimeout(function() { |
348 pendingRequest.dispatchEvent(updateEvent); | 355 pendingRequest.dispatchEvent( |
| 356 __gCrWeb['paymentRequestManager'].updateEvent); |
349 }, 0); | 357 }, 0); |
350 }; | 358 }; |
351 | 359 |
352 /** | 360 /** |
353 * Updates the shipping_address property of the PaymentRequest object to | 361 * Updates the shipping_address property of the PaymentRequest object to |
354 * |shippingAddress| and dispatches a shippingaddresschange event. | 362 * |shippingAddress| and dispatches a shippingaddresschange event. |
355 * @param {!window.PaymentAddress} shippingAddress | 363 * @param {!window.PaymentAddress} shippingAddress |
356 */ | 364 */ |
357 __gCrWeb['paymentRequestManager'].updateShippingAddressAndDispatchEvent = | 365 __gCrWeb['paymentRequestManager'].updateShippingAddressAndDispatchEvent = |
358 function(shippingAddress) { | 366 function(shippingAddress) { |
359 if (!__gCrWeb['paymentRequestManager'].pendingRequest) { | 367 if (!__gCrWeb['paymentRequestManager'].pendingRequest) { |
360 __gCrWeb['paymentRequestManager'].rejectRequestPromise( | 368 __gCrWeb['paymentRequestManager'].rejectRequestPromise( |
361 'Internal PaymentRequest error: No pending request.'); | 369 'Internal PaymentRequest error: No pending request.'); |
362 } | 370 } |
363 | 371 |
364 var pendingRequest = __gCrWeb['paymentRequestManager'].pendingRequest; | 372 var pendingRequest = __gCrWeb['paymentRequestManager'].pendingRequest; |
365 | 373 |
366 if (updateEvent) { | 374 if (__gCrWeb['paymentRequestManager'].updateEvent) { |
367 __gCrWeb['paymentRequestManager'].rejectRequestPromise( | 375 __gCrWeb['paymentRequestManager'].rejectRequestPromise( |
368 'Internal PaymentRequest error: Only one update may take ' + | 376 'Internal PaymentRequest error: Only one update may take ' + |
369 'place at a time.'); | 377 'place at a time.'); |
370 } | 378 } |
371 | 379 |
372 pendingRequest.shippingAddress = shippingAddress; | 380 pendingRequest.shippingAddress = shippingAddress; |
373 | 381 |
374 updateEvent = new Event( | 382 __gCrWeb['paymentRequestManager'].updateEvent = new Event( |
375 'shippingaddresschange', {'bubbles': true, 'cancelable': false}); | 383 'shippingaddresschange', {'bubbles': true, 'cancelable': false}); |
376 Object.defineProperty(updateEvent, 'updateWith', {value: updateWith}); | 384 |
| 385 Object.defineProperty(__gCrWeb['paymentRequestManager'].updateEvent, |
| 386 'updateWith', {value: __gCrWeb['paymentRequestManager'].updateWith}); |
377 | 387 |
378 // setTimeout() is used in order to return immediately. Otherwise the | 388 // setTimeout() is used in order to return immediately. Otherwise the |
379 // dispatchEvent call waits for all event handlers to return, which could | 389 // dispatchEvent call waits for all event handlers to return, which could |
380 // cause a ReentryGuard failure. | 390 // cause a ReentryGuard failure. |
381 window.setTimeout(function() { | 391 window.setTimeout(function() { |
382 pendingRequest.dispatchEvent(updateEvent); | 392 pendingRequest.dispatchEvent( |
| 393 __gCrWeb['paymentRequestManager'].updateEvent); |
383 }, 0); | 394 }, 0); |
384 }; | 395 }; |
385 }()); // End of anonymous object | 396 }()); // End of anonymous object |
386 | 397 |
387 /** | 398 /** |
388 * A request to make a payment. | 399 * A request to make a payment. |
389 * @param {!Array<!window.PaymentMethodData>} methodData Payment method | 400 * @param {!Array<!window.PaymentMethodData>} methodData Payment method |
390 * identifiers for the payment methods that the web site accepts and any | 401 * identifiers for the payment methods that the web site accepts and any |
391 * associated payment method specific data. | 402 * associated payment method specific data. |
392 * @param {!window.PaymentDetails} details Information about the transaction | 403 * @param {!window.PaymentDetails} details Information about the transaction |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
580 */ | 591 */ |
581 this.methodName = methodName; | 592 this.methodName = methodName; |
582 | 593 |
583 /** | 594 /** |
584 * @type {Object} | 595 * @type {Object} |
585 */ | 596 */ |
586 this.details = details; | 597 this.details = details; |
587 }; | 598 }; |
588 | 599 |
589 /** | 600 /** |
| 601 * Contains the possible values for the string argument accepted by |
| 602 * window.PaymentResponse.prototype.complete. |
| 603 * @enum {string} |
| 604 */ |
| 605 var PaymentComplete = { |
| 606 SUCCESS: 'success', |
| 607 FAIL: 'fail', |
| 608 UNKNOWN: 'unknown' |
| 609 }; |
| 610 |
| 611 /** |
590 * Communicates the result of processing the payment. | 612 * Communicates the result of processing the payment. |
591 * @param {boolean} success Indicates whether processing succeeded. | 613 * @param {PaymentComplete=} opt_result Indicates whether payment was |
| 614 * successfully processed. |
592 * @return {!Promise} A promise to notify the caller when the user interface has | 615 * @return {!Promise} A promise to notify the caller when the user interface has |
593 * been closed. | 616 * been closed. |
594 */ | 617 */ |
595 window.PaymentResponse.prototype.complete = function(success) { | 618 window.PaymentResponse.prototype.complete = function(opt_result) { |
| 619 if (opt_result != PaymentComplete.UNKNOWN && |
| 620 opt_result != PaymentComplete.SUCCESS && |
| 621 opt_result != PaymentComplete.FAIL) { |
| 622 opt_result = PaymentComplete.UNKNOWN; |
| 623 } |
| 624 |
596 if (!__gCrWeb['paymentRequestManager'].responsePromiseResolver) { | 625 if (!__gCrWeb['paymentRequestManager'].responsePromiseResolver) { |
597 throw new Error('Internal PaymentRequest error: No Promise to return.'); | 626 throw new Error('Internal PaymentRequest error: No Promise to return.'); |
598 } | 627 } |
599 | 628 |
600 var message = { | 629 var message = { |
601 'command': 'paymentRequest.responseComplete' | 630 'command': 'paymentRequest.responseComplete', |
| 631 'result': opt_result, |
602 }; | 632 }; |
603 __gCrWeb.message.invokeOnHost(message); | 633 __gCrWeb.message.invokeOnHost(message); |
604 | 634 |
605 return __gCrWeb['paymentRequestManager'].responsePromiseResolver.promise; | 635 return __gCrWeb['paymentRequestManager'].responsePromiseResolver.promise; |
606 }; | 636 }; |
OLD | NEW |