diff options
Diffstat (limited to 'browser/components/payments/res/mixins')
3 files changed, 211 insertions, 0 deletions
diff --git a/browser/components/payments/res/mixins/HandleEventMixin.js b/browser/components/payments/res/mixins/HandleEventMixin.js new file mode 100644 index 0000000000..8d09ac2207 --- /dev/null +++ b/browser/components/payments/res/mixins/HandleEventMixin.js @@ -0,0 +1,28 @@ +/* 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/. */ + +/** + * A mixin to forward events to on* methods if defined. + * + * @param {string} superclass The class to extend. + * @returns {class} + */ +export default function HandleEventMixin(superclass) { + return class HandleEvent extends superclass { + handleEvent(evt) { + function capitalize(str) { + return str.charAt(0).toUpperCase() + str.slice(1); + } + if (super.handleEvent) { + super.handleEvent(evt); + } + // Check whether event name is a defined function in object. + let fn = "on" + capitalize(evt.type); + if (this[fn] && typeof this[fn] === "function") { + return this[fn](evt); + } + return null; + } + }; +} diff --git a/browser/components/payments/res/mixins/ObservedPropertiesMixin.js b/browser/components/payments/res/mixins/ObservedPropertiesMixin.js new file mode 100644 index 0000000000..5fe71af90c --- /dev/null +++ b/browser/components/payments/res/mixins/ObservedPropertiesMixin.js @@ -0,0 +1,71 @@ +/* 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/. */ + +/** + * Define getters and setters for observedAttributes converted to camelCase and + * trigger a batched aynchronous call to `render` upon observed + * attribute/property changes. + */ + +export default function ObservedPropertiesMixin(superClass) { + return class ObservedProperties extends superClass { + static kebabToCamelCase(name) { + return name.replace(/-([a-z])/g, ($0, $1) => $1.toUpperCase()); + } + + constructor() { + super(); + + this._observedPropertiesMixin = { + pendingRender: false, + }; + + // Reflect property changes for `observedAttributes` to attributes. + for (let name of this.constructor.observedAttributes || []) { + if (name in this) { + // Don't overwrite existing properties. + continue; + } + // Convert attribute names from kebab-case to camelCase properties + Object.defineProperty(this, ObservedProperties.kebabToCamelCase(name), { + configurable: true, + get() { + return this.getAttribute(name); + }, + set(value) { + if (value === null || value === undefined || value === false) { + this.removeAttribute(name); + } else { + this.setAttribute(name, value); + } + }, + }); + } + } + + async _invalidateFromObservedPropertiesMixin() { + if (this._observedPropertiesMixin.pendingRender) { + return; + } + + this._observedPropertiesMixin.pendingRender = true; + await Promise.resolve(); + try { + this.render(); + } finally { + this._observedPropertiesMixin.pendingRender = false; + } + } + + attributeChangedCallback(attr, oldValue, newValue) { + if (super.attributeChangedCallback) { + super.attributeChangedCallback(attr, oldValue, newValue); + } + if (oldValue === newValue) { + return; + } + this._invalidateFromObservedPropertiesMixin(); + } + }; +} diff --git a/browser/components/payments/res/mixins/PaymentStateSubscriberMixin.js b/browser/components/payments/res/mixins/PaymentStateSubscriberMixin.js new file mode 100644 index 0000000000..ede9e1bfc5 --- /dev/null +++ b/browser/components/payments/res/mixins/PaymentStateSubscriberMixin.js @@ -0,0 +1,112 @@ +/* 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/. */ + +import PaymentsStore from "../PaymentsStore.js"; + +/** + * A mixin for a custom element to observe store changes to information about a payment request. + */ + +/** + * State of the payment request dialog. + */ +export let requestStore = new PaymentsStore({ + changesPrevented: false, + orderDetailsShowing: false, + "basic-card-page": { + guid: null, + // preserveFieldValues: true, + selectedStateKey: "selectedPaymentCard", + }, + "shipping-address-page": { + guid: null, + }, + "payer-address-page": { + guid: null, + }, + "billing-address-page": { + guid: null, + }, + "payment-summary": {}, + page: { + id: "payment-summary", + previousId: null, + // onboardingWizard: true, + // error: "", + }, + request: { + completeStatus: "", + tabId: null, + topLevelPrincipal: { URI: { displayHost: null } }, + requestId: null, + paymentMethods: [], + paymentDetails: { + id: null, + totalItem: { label: null, amount: { currency: null, value: 0 } }, + displayItems: [], + payerErrors: {}, + paymentMethodErrors: null, + shippingAddressErrors: {}, + shippingOptions: [], + modifiers: null, + error: "", + }, + paymentOptions: { + requestPayerName: false, + requestPayerEmail: false, + requestPayerPhone: false, + requestShipping: false, + shippingType: "shipping", + }, + shippingOption: null, + }, + selectedPayerAddress: null, + selectedPaymentCard: null, + selectedPaymentCardSecurityCode: null, + selectedShippingAddress: null, + selectedShippingOption: null, + savedAddresses: {}, + savedBasicCards: {}, + tempAddresses: {}, + tempBasicCards: {}, +}); + +/** + * A mixin to render UI based upon the requestStore and get updated when that store changes. + * + * Attaches `requestStore` to the element to give access to the store. + * @param {class} superClass The class to extend + * @returns {class} + */ +export default function PaymentStateSubscriberMixin(superClass) { + return class PaymentStateSubscriber extends superClass { + constructor() { + super(); + this.requestStore = requestStore; + } + + connectedCallback() { + this.requestStore.subscribe(this); + this.render(this.requestStore.getState()); + if (super.connectedCallback) { + super.connectedCallback(); + } + } + + disconnectedCallback() { + this.requestStore.unsubscribe(this); + if (super.disconnectedCallback) { + super.disconnectedCallback(); + } + } + + /** + * Called by the store upon state changes. + * @param {object} state The current state + */ + stateChangeCallback(state) { + this.render(state); + } + }; +} |