diff --git a/index.html b/index.html index 8ca237c5..fb013ee0 100644 --- a/index.html +++ b/index.html @@ -67,6 +67,7 @@ caniuse: "payment-request", lint: { "check-punctuation": true, + "wpt-tests-exist": true, }, doJsonLd: true, xref: "web-platform", @@ -112,53 +113,14 @@
- Substantive changes to the Payment Request API since the 9 July 2018 - version are as follows. The complete list of changes, including all - editorial changes, is viewable in the commit history. Key set of changes are viewable in the Changelog.
-@@ -349,44 +306,20 @@
- Here we see an example of how to add two shipping options to the - |details|. -
-- const shippingOptions = [ - { - id: "standard", - // Shipping by truck, 2 days - label: "🚛 Envío por camión (2 dias)", - amount: { currency: "EUR", value: "5.00" }, - selected: true, - }, - { - id: "drone", - // Drone shipping, 2 hours - label: "🚀 Drone Express (2 horas)", - amount: { currency: "EUR", value: "25.00" } - }, - ]; - Object.assign(details, { shippingOptions }); --
- Some financial transactions require a user to provide specific - information in order for a merchant to fulfill a purchase (e.g., the - user's shipping address, in case a physical good needs to be - shipped). To request this information, a merchant can pass a third - optional argument (|options|) to the {{PaymentRequest}} constructor - indicating what information they require. When the payment request is - shown, the user agent will request this information from the end user - and return it to the merchant when the user accepts the payment - request. -
-- const options = { - requestPayerEmail: false, - requestPayerName: true, - requestPayerPhone: false, - requestShipping: true, - } --
PaymentRequest
@@ -458,9 +367,6 @@ - Prior to the user accepting to make payment, the site is given an - opportunity to update the payment request in response to user input. - This can include, for example, providing additional shipping options - (or modifying their cost), removing items that cannot ship to a - particular address, etc. -
-- const request = new PaymentRequest(methodData, details, options); - // Async update to details - request.onshippingaddresschange = ev => { - ev.updateWith(checkShipping(request)); - }; - // Sync update to the total - request.onshippingoptionchange = ev => { - // selected shipping option - const { shippingOption } = request; - const newTotal = { - currency: "USD", - label: "Total due", - value: calculateNewTotal(shippingOption), - }; - ev.updateWith({ total: newTotal }); - }; - async function checkShipping(request) { - try { - const json = request.shippingAddress.toJSON(); - - await ensureCanShipTo(json); - const { shippingOptions, total } = await calculateShipping(json); - - return { shippingOptions, total }; - } catch (err) { - return { error: `Sorry! we can't ship to your address.` }; - } - } --
- A developer can use the - {{PaymentDetailsUpdate/shippingAddressErrors}} member of the - {{PaymentDetailsUpdate}} dictionary to indicate that there are - validation errors with specific attributes of a {{PaymentAddress}}. - The {{PaymentDetailsUpdate/shippingAddressErrors}} member is a - {{AddressErrors}} dictionary, whose members specifically demarcate - the fields of a physical address that are erroneous while also - providing helpful error messages to be displayed to the end user. -
-- request.onshippingaddresschange = ev => { - ev.updateWith(validateAddress(request.shippingAddress)); - }; - function validateAddress(shippingAddress) { - const error = "Can't ship to this address."; - const shippingAddressErrors = { - city: "FarmVille is not a real place.", - postalCode: "Unknown postal code for your country.", - }; - // Empty shippingOptions implies that we can't ship - // to this address. - const shippingOptions = []; - return { error, shippingAddressErrors, shippingOptions }; - } --
- The {{PaymentRequest/shippingAddress}}, - {{PaymentRequest/shippingOption}}, and - {{PaymentRequest/shippingType}} attributes are populated during - processing if the {{PaymentOptions/requestShipping}} member is set. -
A |request|'s payment-relevant browsing context is that @@ -685,15 +506,14 @@
The {{PaymentRequest}} is constructed using the supplied sequence of PaymentMethodData |methodData| including any payment - method specific {{PaymentMethodData/data}}, the - PaymentDetailsInit |details|, and the {{PaymentOptions}} - |options|. + method specific {{PaymentMethodData/data}}, and the + PaymentDetailsInit |details|.
+ "payment-request-constructor.https.sub.html, payment-request-insecure.http.html">
The PaymentRequest(|methodData|,
- |details|, |options|)
constructor MUST act as follows:
+ |details|) constructor MUST act as follows:
sequence
<{{PaymentShippingOption}}>.
- PaymentRequest
's details
algorithm with |detailsPromise|, |request|, and null.
@@ -1391,69 +1155,11 @@ - A {{PaymentRequest}}'s {{PaymentRequest/shippingAddress}} attribute - is populated when the user provides a shipping address. It is null by - default. When a user provides a shipping address, the shipping - address changed algorithm runs. -
-- A {{PaymentRequest}}'s {{PaymentRequest/shippingType}} attribute is - the type of shipping used to fulfill the transaction. Its value is - either a {{PaymentShippingType}} enum value, or null if none is - provided by the developer during - [=PaymentRequest.PaymentRequest()|construction=] (see - {{PaymentOptions}}'s {{PaymentOptions/shippingType}} member). -
-- A {{PaymentRequest}}'s {{PaymentRequest/onshippingaddresschange}} - attribute is an {{EventHandler}} for a {{PaymentRequestUpdateEvent}} - named shippingaddresschange. -
-- A {{PaymentRequest}}'s {{PaymentRequest/shippingOption}} attribute is - populated when the user chooses a shipping option. It is null by - default. When a user chooses a shipping option, the shipping - option changed algorithm runs. -
-- A {{PaymentRequest}}'s {{PaymentRequest/onshippingoptionchange}} - attribute is an {{EventHandler}} for a {{PaymentRequestUpdateEvent}} - named shippingoptionchange. -
-+
A {{PaymentRequest}}'s {{PaymentRequest/onpaymentmethodchange}} attribute is an {{EventHandler}} for a {{PaymentMethodChangeEvent}} named "paymentmethodchange". @@ -1516,15 +1222,6 @@
dictionary PaymentDetailsBase { sequence<PaymentItem> displayItems; - sequence<PaymentShippingOption> shippingOptions; sequence<PaymentDetailsModifier> modifiers; };@@ -1839,41 +1535,6 @@
- A sequence containing the different shipping options for the user - to choose from. -
-- If an item in the sequence has the - {{PaymentShippingOption/selected}} member set to true, then this - is the shipping option that will be used by default and - {{PaymentRequest/shippingOption}} will be set to the - {{PaymentShippingOption/id}} of this option without running the - shipping option changed algorithm. If more than one item - in the sequence has {{PaymentShippingOption/selected}} set to - true, then the user agent selects the last one in the - sequence. -
-- The {{PaymentDetailsBase/shippingOptions}} member is only used if - the {{PaymentRequest}} was constructed with {{PaymentOptions}} - and {{PaymentOptions/requestShipping}} set to true. -
- -dictionary PaymentDetailsUpdate : PaymentDetailsBase { - DOMString error; PaymentItem total; - AddressErrors shippingAddressErrors; - PayerErrors payerErrors; object paymentMethodErrors; };@@ -1954,21 +1612,6 @@
- enum PaymentShippingType { - "shipping", - "delivery", - "pickup" - }; --
- dictionary PaymentOptions { - boolean requestPayerName = false; - boolean requestBillingAddress = false; - boolean requestPayerEmail = false; - boolean requestPayerPhone = false; - boolean requestShipping = false; - PaymentShippingType shippingType = "shipping"; - }; --
- The {{PaymentOptions}} dictionary is passed to the {{PaymentRequest}} - constructor and provides information about the options desired for the - payment request. -
-- The {{PaymentOptions/shippingType}} member only affects the user - interface for the payment request. -
-- A physical address is composed of the following parts. -
-+ enum PaymentComplete { + "fail", + "success", + "unknown" + }; ++
- [SecureContext, Exposed=(Window)] - interface PaymentAddress { - [Default] object toJSON(); - readonly attribute DOMString city; - readonly attribute DOMString country; - readonly attribute DOMString dependentLocality; - readonly attribute DOMString organization; - readonly attribute DOMString phone; - readonly attribute DOMString postalCode; - readonly attribute DOMString recipient; - readonly attribute DOMString region; - readonly attribute DOMString sortingCode; - readonly attribute FrozenArray<DOMString> addressLine; - }; --
- The {{PaymentAddress}} interface represents a physical - address. -
- -- The steps to internally construct a - `PaymentAddress` with an optional {{AddressInit}} - |details:AddressInit| are given by the following algorithm: -
-- Represents the country of the address. When getting, returns - the value of the {{PaymentAddress}}'s - {{PaymentAddress/[[country]]}} internal slot. -
-- Represents the address line of the address. When getting, - returns the value of the {{PaymentAddress}}'s - {{PaymentAddress/[[addressLine]]}} internal slot. -
-- Represents the region of the address. When getting, returns - the value of the {{PaymentAddress}}'s {{PaymentAddress/[[region]]}} - internal slot. -
-- Represents the city of the address. When getting, returns - the value of the {{PaymentAddress}}'s {{PaymentAddress/[[city]]}} - internal slot. -
-- Represents the dependent locality of the address. When - getting, returns the value of the {{PaymentAddress}}'s - {{PaymentAddress/[[dependentLocality]]}} internal slot. -
-- Represents the postal code of the address. When getting, - returns the value of the {{PaymentAddress}}'s - {{PaymentAddress/[[postalCode]]}} internal slot. -
-- Represents the sorting code of the address. When getting, - returns the value of the {{PaymentAddress}}'s - {{PaymentAddress/[[sortingCode]]}} internal slot. -
-- Represents the organization of the address. When getting, - returns the value of the {{PaymentAddress}}'s - {{PaymentAddress/[[organization]]}} internal slot. -
-- Represents the recipient of the address. When getting, - returns the value of the {{PaymentAddress}}'s - {{PaymentAddress/[[recipient]]}} internal slot. -
-- Represents the phone number of the address. When getting, - returns the value of the {{PaymentAddress}}'s - {{PaymentAddress/[[phone]]}} internal slot. -
-- Internal slot - | -- Description (non-normative) - | -
---|---|
- [[\country]] - | -- A country as an [[ISO3166-1]] alpha-2 code stored in its - canonical uppercase form or the empty string. For example, - "JP". - | -
- [[\addressLine]] - | -- A frozen array, possibly of zero length, representing an - address line. - | -
- [[\region]] - | -- A region as a country subdivision name or the - empty string, such as "Victoria", representing the state of - Victoria in Australia. - | -
- [[\city]] - | -- A city or the empty string. - | -
- [[\dependentLocality]] - | -- A dependent locality or the empty string. - | -
- [[\postalCode]] - | -- A postal code or the empty string. - | -
- [[\sortingCode]] - | -- A sorting code or the empty string. - | -
- [[\organization]] - | -- An organization or the empty string. - | -
- [[\recipient]] - | -- A recipient or the empty string. - | -
- [[\phone]] - | -- A phone number or the empty string. - | -
- dictionary AddressInit { - DOMString country = ""; - sequence<DOMString> addressLine = []; - DOMString region = ""; - DOMString city = ""; - DOMString dependentLocality = ""; - DOMString postalCode = ""; - DOMString sortingCode = ""; - DOMString organization = ""; - DOMString recipient = ""; - DOMString phone = ""; - }; --
- An {{AddressInit}} is passed when - [=PaymentAddress.PaymentAddress()|constructing=] a - {{PaymentAddress}}. Its members are as follows. -
-- dictionary AddressErrors { - DOMString addressLine; - DOMString city; - DOMString country; - DOMString dependentLocality; - DOMString organization; - DOMString phone; - DOMString postalCode; - DOMString recipient; - DOMString region; - DOMString sortingCode; - }; --
- The members of the {{AddressErrors}} dictionary represent validation - errors with specific parts of a physical address. Each - dictionary member has a dual function: firstly, its presence denotes - that a particular part of an address is suffering from a validation - error. Secondly, the string value allows the developer to describe - the validation error (and possibly how the end user can fix the - error). -
-- Developers need to be aware that users might not have the ability to - fix certain parts of an address. As such, they need to be mindful not - to ask the user to fix things they might not have control over. -
-- The steps to create a `PaymentAddress` from - user-provided input are given by the following algorithm. The - algorithm takes a list |redactList|. -
-- The |redactList| optionally gives user agents the possibility to - limit the amount of personal information about the recipient that - the API shares with the merchant. -
-- For merchants, the resulting {{PaymentAddress}} object provides - enough information to, for example, calculate shipping costs, but, - in most cases, not enough information to physically locate and - uniquely identify the recipient. -
-- Unfortunately, even with the |redactList|, recipient anonymity - cannot be assured. This is because in some countries postal codes - are so fine-grained that they can uniquely identify a recipient. -
-- Postal codes in certain countries can be so specific as - to uniquely identify an individual. This being a privacy - concern, some user agents only return the part of a postal code - that they deem sufficient for a merchant to calculate shipping - costs. This varies across countries and regions, and so the - choice to redact part, or all, of the postal code is left to - the discretion of implementers in the interest of protecting - users' privacy. -
-- If "region" is not in |redactList|: -
-- In some countries (e.g., Belgium) it is uncommon for users to - include a region as part of a physical address - (even if all the regions of a country are part of [[ISO3166-2]]). - As such, when the user agent knows that the user is inputting the - address for a particular country, it might not provide a field - for the user to input a region. In such cases, the user - agent returns an empty string for both {{PaymentAddress}}'s - {{PaymentAddress/region}} attribute - but the address can still - serve its intended purpose (e.g., be valid for shipping or - billing purposes). -
-- dictionary PaymentShippingOption { - required DOMString id; - required DOMString label; - required PaymentCurrencyAmount amount; - boolean selected = false; - }; --
- The {{PaymentShippingOption}} dictionary has members describing a - shipping option. Developers can provide the user with one or more - shipping options by calling the - {{PaymentRequestUpdateEvent/updateWith()}} method in response to a - change event. -
-- enum PaymentComplete { - "fail", - "success", - "unknown" - }; --
@@ -3131,7 +1836,7 @@
+
The retry(|errorFields:PaymentValidationErrors|)
method
MUST act as follows:
dictionary PaymentValidationErrors { - PayerErrors payer; - AddressErrors shippingAddress; DOMString error; object paymentMethod; };
- dictionary PayerErrors { - DOMString email; - DOMString name; - DOMString phone; - }; --
- The {{PayerErrors}} is used to represent validation errors with one - or more payer details. -
-- Payer details are any of the payer's name, payer's phone - number, and payer's email. -
-- const payer = { - email: "The domain is invalid.", - phone: "Unknown country code.", - name: "Not in database.", - }; - await response.retry({ payer }); --
- If the {{PaymentOptions/requestShipping}} member was set to true in - the {{PaymentOptions}} passed to the {{PaymentRequest}} constructor, - then {{PaymentRequest/shippingAddress}} will be the full and final - shipping address chosen by the user. -
-- If the {{PaymentOptions/requestShipping}} member was set to true in - the {{PaymentOptions}} passed to the {{PaymentRequest}} constructor, - then {{PaymentRequest/shippingOption}} will be the - {{PaymentShippingOption/id}} attribute of the selected shipping - option. -
-- If the {{PaymentOptions/requestPayerName}} member was set to true in - the {{PaymentOptions}} passed to the {{PaymentRequest}} constructor, - then {{PaymentResponse/payerName}} will be the name provided by the - user. -
-- If the {{PaymentOptions/requestPayerEmail}} member was set to true in - the {{PaymentOptions}} passed to the {{PaymentRequest}} constructor, - then {{PaymentResponse/payerEmail}} will be the email address chosen - by the user. -
-- If the {{PaymentOptions/requestPayerPhone}} member was set to true in - the {{PaymentOptions}} passed to the {{PaymentRequest}} constructor, - then {{PaymentResponse/payerPhone}} will be the phone number chosen - by the user. -
-- Allows a developer to handle "payerdetailchange" events. -
-shippingaddresschange
- shippingoptionchange
- payerdetailchange
- paymentmethodchange
@@ -3828,50 +2321,13 @@ - // ❌ Bad - this won't work! - request.onshippingaddresschange = async ev => { - // await goes to next tick, and updateWith() - // was not called. - const details = await getNewDetails(oldDetails); - // 💥 So it's now too late! updateWith() - // throws "InvalidStateError". - ev.updateWith(details); - }; - - // ✅ Good - UI will wait. - request.onshippingaddresschange = ev => { - // Calling updateWith() with a promise is ok 👍 - const promiseForNewDetails = getNewDetails(oldDetails); - ev.updateWith(promiseForNewDetails); - }; -
Additionally, {{PaymentRequestUpdateEvent/[[waitForUpdate]]}} prevents reuse of {{PaymentRequestUpdateEvent}}.
-- // ❌ Bad - calling updateWith() twice doesn't work! - request.addEventListener("shippingaddresschange", ev => { - ev.updateWith(details); // this is ok. - // 💥 [[waitForUpdate]] is true, throws "InvalidStateError". - ev.updateWith(otherDetails); - }); - - // ❌ Bad - this won't work either! - request.addEventListener("shippingaddresschange", async ev => { - const p = Promise.resolve({ ...details }); - ev.updateWith(p); - await p; - // 💥 Only one call to updateWith() is allowed, - // so the following throws "InvalidStateError" - ev.updateWith({ ...newDetails }); - }); -
+ "PaymentRequestUpdateEvent/updatewith-method.https.html"> The {{PaymentRequestUpdateEvent/updateWith()}} with |detailsPromise:Promise| method MUST act as follows:
@@ -4019,88 +2475,6 @@- The shipping address changed algorithm runs when the user - provides a new shipping address. It MUST run the following steps: -
-- The |redactList| limits the amount of personal information - about the recipient that the API shares with the merchant. -
-- For merchants, the resulting {{PaymentAddress}} object - provides enough information to, for example, calculate - shipping costs, but, in most cases, not enough information - to physically locate and uniquely identify the recipient. -
-- Unfortunately, even with the |redactList|, recipient - anonymity cannot be assured. This is because in some - countries postal codes are so fine-grained that they can - uniquely identify a recipient. -
-- The shipping option changed algorithm runs when the user - chooses a new shipping option. It MUST run the following steps: -
-id
string of the
- {{PaymentShippingOption}} provided by the user.
- - When the user selects or changes a payment method (e.g., a credit - card), the {{PaymentMethodChangeEvent}} includes redacted billing - address information for the purpose of performing tax calculations. - Redacted attributes include, but are not limited to, address - line, dependent locality, organization, phone - number, and recipient. -
+
The PaymentRequest updated algorithm is run by other algorithms above to fire an event to indicate that a user has made a change to a {{PaymentRequest}} called |request| with an event @@ -4184,85 +2549,11 @@
- The user agent MUST run the payer detail changed algorithm - when the user changes the |payer name|, or the |payer email|, or the - |payer phone| in the user interface: -
-+
The user accepts the
payment request algorithm runs when the user accepts the
payment request and confirms that they want to pay. It MUST queue
@@ -4282,13 +2573,6 @@
- If
- |request|.{{PaymentRequest/[[options]]}}.{{PaymentOptions/requestShipping}}
- is true, and
- |request|.{{PaymentRequest/[[details]]}}.{{PaymentDetailsBase/shippingOptions}}
- is empty, then the developer has signified that there are
- no valid shipping options for the currently-chosen
- shipping address (given by |request|'s
- {{PaymentRequest/shippingAddress}}).
-
- In this case, the user agent SHOULD display an error
- indicating this, and MAY indicate that the
- currently-chosen shipping address is invalid in some way.
- The user agent SHOULD use the
- {{PaymentDetailsUpdate/error}} member of |details|, if it
- is present, to give more information about why there are
- no valid shipping options for that address.
-
- Further, if
- |details|["{{PaymentDetailsUpdate/shippingAddressErrors}}"]
- member is present, the user agent SHOULD display an error
- specifically for each erroneous field of the shipping
- address. This is done by matching each present member of
- the {{AddressErrors}} to a corresponding input field in
- the shown user interface.
-
- Similarly, if |details|["{{payerErrors}}"] member is
- present and |request|.{{PaymentRequest/[[options]]}}'s
- {{PaymentOptions/requestPayerName}},
- {{PaymentOptions/requestPayerEmail}}, or
- {{PaymentOptions/requestPayerPhone}} is true, then
- display an error specifically for each erroneous field.
-
- Likewise, if
- |details|.{{PaymentDetailsUpdate/paymentMethodErrors}} is
- present, then display errors specifically for each
- erroneous input field for the particular payment method.
-
The user agent MUST NOT share information about the user with
- a developer (e.g., the shipping address) without user consent.
+ a developer without user consent.
In particular, the {{PaymentMethodData}}'s {{PaymentMethodData/data}}
@@ -4944,22 +3083,8 @@
take no further action. The user agent user interface SHOULD
ensure that this never occurs.
-
to an object resulting from running the |handler|'s steps to
respond to a payment request.
-
-
sequence
<{{PaymentShippingOption}}>.
-
-
-
-
-
@@ -4554,9 +2754,7 @@
-
-
@@ -4673,50 +2856,6 @@
data shared via the {{PaymentMethodChangeEvent}}'s
{{PaymentMethodChangeEvent/methodDetails}} attribute. Requirements
and approaches for minimizing shared data are likely to vary by
- payment method and might include:
+ payment method.
Where sharing of privacy-sensitive information might not be obvious to users (e.g., when [=payment handler/payment method changed @@ -5011,9 +3136,7 @@
For the user-facing aspects of Payment Request API, implementations integrate with platform accessibility APIs via form controls and other - input modalities. Furthermore, to increase the intelligibility of - total, shipping addresses, and contact information, implementations - format data according to system conventions. + input modalities.
+
User agents MAY impose implementation-specific limits on otherwise unconstrained inputs, e.g., to prevent denial of service attacks, to guard against running out of memory, or to work around