UNPKG

paypal-checkout

Version:

PayPal Checkout components, for integrating checkout products.

185 lines (148 loc) 6.09 kB
/* @flow */ export function getComponentScript() : () => void { /* istanbul ignore next */ return () => { const ATTRIBUTE = { OPTIONAL: 'optional' }; const CLASS = { HIDDEN: 'hidden', DOM_READY: 'dom-ready' }; const SELECTOR = { ALL: '*', OPTIONAL: `[${ ATTRIBUTE.OPTIONAL }]` }; const TAG = { STYLE: 'style' }; function once(handler : Function) : Function { let called = false; return (...args) => { if (!called) { called = true; handler(...args); } }; } function debounce(handler : Function, time : number = 50) : Function { let timeout; return (...args) => { clearTimeout(timeout); timeout = setTimeout(() => { handler(...args); }, time); }; } // eslint-disable-next-line flowtype/no-mutable-array function toArray<T>(item) : Array<T> { return Array.prototype.slice.call(item); } function getElements(selector, parent) : $ReadOnlyArray<HTMLElement> { parent = parent || document; return toArray(parent.querySelectorAll(selector)).filter(el => { return el.tagName.toLowerCase() !== TAG.STYLE; }); } function getParent(element : HTMLElement) : HTMLElement { // $FlowFixMe return element.parentElement; } function showElement(el : HTMLElement) { el.classList.remove(CLASS.HIDDEN); } function hideElement(el : HTMLElement) { el.classList.add(CLASS.HIDDEN); } function sum(arr : $ReadOnlyArray<number>) : number { let result = 0; for (const item of arr) { result += item; } return result; } function unique<T>(arr : $ReadOnlyArray<T>) : $ReadOnlyArray<T> { const result = []; for (const el of arr) { if (result.indexOf(el) === -1) { result.push(el); } } return result; } function getAllChildren(element : HTMLElement) : $ReadOnlyArray<HTMLElement> { return getElements(SELECTOR.ALL, element); } function getOptionalIndex(element : HTMLElement) : number { return parseInt(element.getAttribute(ATTRIBUTE.OPTIONAL) || 0, 10); } function getElementsTotalWidth(elements : $ReadOnlyArray<HTMLElement>) : number { return sum(elements.map(child => child.offsetWidth)); } function getOptionalParents() : $ReadOnlyArray<HTMLElement> { const optional = [ ...getElements(SELECTOR.OPTIONAL), ...getElements('.{ CLASS.FUNDINGICONS } .{ CLASS.CARD }'), ...getElements('.{ CLASS.BUTTON }-label-credit .{ CLASS.BUTTON }-logo-paypal') ]; return unique(optional.map(getParent).filter(Boolean)); } function getOptionalChildren(parent : HTMLElement) : $ReadOnlyArray<HTMLElement> { return toArray(getElements(SELECTOR.OPTIONAL, parent)).sort((first, second) => { return getOptionalIndex(first) - getOptionalIndex(second); }); } const children = getOptionalParents().map(optionalParent => { const allChildren = getAllChildren(optionalParent); const optionalChildren = getOptionalChildren(optionalParent); return { optionalParent, allChildren, optionalChildren }; }); function toggleOptionals() { for (const { optionalParent, allChildren, optionalChildren } of children) { const parentWidth = optionalParent.offsetWidth; let usedWidth = getElementsTotalWidth(allChildren) - getElementsTotalWidth(optionalChildren); for (const optionalChild of optionalChildren) { usedWidth += optionalChild.offsetWidth; if ((usedWidth + 4) >= parentWidth) { hideElement(optionalChild); } else { showElement(optionalChild); } } } } function setupTabOutlineEvent() { const buttonsContainer = document.getElementsByClassName('{ CLASS.CONTAINER }')[0]; const tabKeyCode = 9; function handleMouseDownOnce() { buttonsContainer.classList.remove('{ CLASS.SHOULD_FOCUS }'); window.removeEventListener('mousedown', handleMouseDownOnce); window.addEventListener('keydown', handleFirstTab); // eslint-disable-line no-use-before-define } function handleFirstTab(e) { if (e.keyCode === tabKeyCode) { buttonsContainer.classList.add('{ CLASS.SHOULD_FOCUS }'); window.removeEventListener('keydown', handleFirstTab); window.addEventListener('mousedown', handleMouseDownOnce); } } buttonsContainer.classList.add('{ CLASS.SHOULD_FOCUS }'); window.addEventListener('keydown', handleFirstTab); } const setDomReady = once(debounce(() => { window.addEventListener('resize', toggleOptionals); if (document.body) { document.body.classList.add(CLASS.DOM_READY); } })); const load = () => { toggleOptionals(); setDomReady(); }; toggleOptionals(); setupTabOutlineEvent(); document.addEventListener('DOMContentLoaded', load); window.addEventListener('load', load); window.addEventListener('resize', load); }; }