{"version":3,"file":"z-rebrand.min.js","sources":["../../src/scripts/foundation/moduleInitializer.js","../../src/scripts/utilities/browser-detect.js","../../src/scripts/foundation/mouseEventPolyfill.js","../../src/scripts/feature/accounts/contact-preferences.js","../../src/scripts/foundation/eventBus.js","../../src/scripts/utilities/scroll-top.js","../../src/scripts/utilities/scroller.js","../../src/scripts/foundation/form/validation.js","../../src/scripts/feature/form/field.js","../../src/scripts/feature/form/enable-form.js","../../src/scripts/utilities/ajax.js","../../src/scripts/feature/accounts/account-registration.js","../../src/scripts/feature/accounts/finish-registration.js","../../src/scripts/feature/accounts/register-marketing-preferences.js","../../src/scripts/feature/accounts/reveal-password.js","../../src/scripts/utilities/debounce.js","../../src/scripts/feature/order/bank-account-lookup.js","../../src/scripts/utilities/file-saver.js","../../src/scripts/feature/order/download-agreement.js","../../src/scripts/feature/order/postcode-lookup.js","../../src/scripts/feature/order/request-price.js","../../src/scripts/utilities/offset.js","../../src/scripts/feature/order/step-indicator.js","../../src/scripts/feature/order/renewal-modal.js","../../src/scripts/utilities/selector.js","../../src/scripts/feature/order/guarantor-details.js","../../src/scripts/feature/page-content/anchor-list.js","../../src/scripts/feature/page-content/content-toggle.js","../../src/scripts/utilities/is-mobile.js","../../src/scripts/feature/page-content/page-accordion.js","../../src/scripts/utilities/toggle-slide.js","../../src/scripts/feature/page-content/why-us-carousel.js","../../src/scripts/feature/search/collapsible.js","../../src/scripts/feature/page-content/journey-hero-banner.js","../../src/scripts/feature/navigation/cards-pagination.js","../../src/scripts/feature/page-content/widget-toggle.js","../../src/scripts/feature/form/handle-runtime-validation.js","../../src/scripts/feature/form/prepopulate-email.js","../../src/scripts/feature/form/handle-key-input.js","../../src/scripts/feature/marketing/tracking.js","../../src/scripts/feature/webchat/webchat.js","../../src/scripts/feature/scc/address-finder.js","../../src/scripts/utilities/slide-down.js","../../src/scripts/feature/scc/element-offset.js","../../src/scripts/feature/scc/address-handler.js","../../src/scripts/feature/contact/condition-handler.js","../../src/scripts/feature/form/gtm-event-handler.js","../../src/scripts/feature/accounts/travel-documents.js","../../src/scripts/feature/page-content/cookie-consent.js","../../src/scripts/utilities/cookie.js","../../src/scripts/feature/usagetype/usagetype.js","../../src/scripts/utilities/events.js","../../src/scripts/feature/order/address.js","../../src/scripts/feature/offers/offers-collapsible.js","../../src/scripts/feature/offers/offers-dropdownOption.js","../../src/scripts/feature/offers/offers-dropdown.js","../../src/scripts/feature/offers/accordion-collapsible.js","../../src/scripts/feature/offers/offers-filters.js","../../src/scripts/feature/offers/special-offers.js","../../src/scripts/feature/marketing/marketing-modal.js","../../src/scripts/feature/search/budgetRangeSelector.js","../../src/scripts/zenauto.js"],"sourcesContent":["import document from 'document';\r\n\r\nexport const loadModules = modules => {\r\n modules.forEach((Module, index) => {\r\n if (!Module || typeof Module !== 'function') {\r\n console.log('Invalid module format', module, index);\r\n }\r\n\r\n const module = Module();\r\n \r\n if (module.selector) {\r\n const components = document.querySelectorAll(module.selector);\r\n if (components) {\r\n [...components].forEach(component => {\r\n //console.log('initializing module', module.selector);\r\n module.init(component);\r\n });\r\n } else {\r\n //console.log('module not found', module.selector);\r\n }\r\n } else {\r\n module.init();\r\n }\r\n });\r\n};","import window from 'window';\r\nimport document from 'document';\r\n\r\nexport const browserDetect = () => {\r\n \r\n function _detectIE() {\r\n var ua = window.navigator.userAgent;\r\n var msie = ua.indexOf('MSIE ');\r\n if (msie > 0) {\r\n // IE 10 or older => return version number\r\n return ['IE', parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10)];\r\n }\r\n var trident = ua.indexOf('Trident/');\r\n if (trident > 0) {\r\n // IE 11 => return version number\r\n var rv = ua.indexOf('rv:');\r\n return ['IE', parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10)];\r\n }\r\n var edge = ua.indexOf('Edge/');\r\n if (edge > 0) {\r\n // Edge (IE 12+) => return version number\r\n return ['IE', parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10)];\r\n }\r\n // other browser\r\n return false;\r\n }\r\n\r\n function _getOperatingSystem() {\r\n var userAgent = window.navigator.userAgent,\r\n platform = window.navigator.platform,\r\n macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'],\r\n windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'],\r\n iosPlatforms = ['iPhone', 'iPad', 'iPod'],\r\n os = null;\r\n if (macosPlatforms.indexOf(platform) !== -1) {\r\n os = 'mac-os';\r\n } else if (iosPlatforms.indexOf(platform) !== -1) {\r\n os = 'ios';\r\n } else if (windowsPlatforms.indexOf(platform) !== -1) {\r\n os = 'windows';\r\n } else if (/Android/.test(userAgent)) {\r\n os = 'android';\r\n } else if (!os && /Linux/.test(platform)) {\r\n os = 'linux';\r\n }\r\n return os;\r\n }\r\n\r\n var init = function() {\r\n\r\n var nAgt = navigator.userAgent;\r\n var browserName = navigator.appName;\r\n\r\n var fullVersion = '' + parseFloat(navigator.appVersion);\r\n var majorVersion = parseInt(navigator.appVersion, 10);\r\n var nameOffset, verOffset, ix;\r\n\r\n // // In Opera 15+, the true version is after \"OPR/\"\r\n if ((verOffset = nAgt.indexOf('OPR/')) != -1) {\r\n browserName = 'Opera';\r\n fullVersion = nAgt.substring(verOffset + 4);\r\n }\r\n // // In older Opera, the true version is after \"Opera\" or after \"Version\"\r\n else if ((verOffset = nAgt.indexOf('Opera')) != -1) {\r\n browserName = 'Opera';\r\n fullVersion = nAgt.substring(verOffset + 6);\r\n if ((verOffset = nAgt.indexOf('Version')) != -1) fullVersion = nAgt.substring(verOffset + 8);\r\n }\r\n // // In MSIE, the true version is after \"MSIE\" in userAgent\r\n else if ((verOffset = nAgt.indexOf('MSIE')) != -1) {\r\n browserName = 'Microsoft Internet Explorer';\r\n fullVersion = nAgt.substring(verOffset + 5);\r\n }\r\n // // In Chrome, the true version is after \"Chrome\"\r\n else if ((verOffset = nAgt.indexOf('Chrome')) != -1) {\r\n browserName = 'Chrome';\r\n fullVersion = nAgt.substring(verOffset + 7);\r\n }\r\n // // In Safari, the true version is after \"Safari\" or after \"Version\"\r\n else if ((verOffset = nAgt.indexOf('Safari')) != -1) {\r\n browserName = 'Safari';\r\n fullVersion = nAgt.substring(verOffset + 7);\r\n if ((verOffset = nAgt.indexOf('Version')) != -1) fullVersion = nAgt.substring(verOffset + 8);\r\n }\r\n // // In Firefox, the true version is after \"Firefox\"\r\n else if ((verOffset = nAgt.indexOf('Firefox')) != -1) {\r\n browserName = 'Firefox';\r\n fullVersion = nAgt.substring(verOffset + 8);\r\n }\r\n // // In most other browsers, \"name/version\" is at the end of userAgent\r\n else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) {\r\n browserName = nAgt.substring(nameOffset, verOffset);\r\n fullVersion = nAgt.substring(verOffset + 1);\r\n if (browserName.toLowerCase() == browserName.toUpperCase()) {\r\n browserName = navigator.appName;\r\n }\r\n }\r\n // // trim the fullVersion string at semicolon/space if present\r\n if ((ix = fullVersion.indexOf(';')) != -1) fullVersion = fullVersion.substring(0, ix);\r\n if ((ix = fullVersion.indexOf(' ')) != -1) fullVersion = fullVersion.substring(0, ix);\r\n\r\n // majorVersion = parseInt('' + fullVersion, 10);\r\n if (isNaN(majorVersion)) {\r\n fullVersion = '' + parseFloat(navigator.appVersion);\r\n majorVersion = parseInt(navigator.appVersion, 10);\r\n }\r\n var IE = _detectIE();\r\n if (IE) {\r\n browserName = IE[0];\r\n majorVersion = IE[1];\r\n }\r\n var Browser = browserName ? browserName.toLowerCase() : browserName;\r\n var Version = majorVersion;\r\n var OS = _getOperatingSystem();\r\n var isTouch = 'ontouchstart' in document.documentElement;\r\n var body = document.querySelector('body');\r\n body.classList.add(Browser);\r\n body.classList.add(Browser + '-' + Version);\r\n body.classList.add(OS);\r\n body.classList.add((isTouch ? 'has' : 'no') + '-touch');\r\n };\r\n\r\n return {\r\n init: init\r\n };\r\n};","import window from 'window';\r\nimport document from 'document';\r\n\r\nexport const mouseEventPolyfill = () => {\r\n\r\n const init = () => {\r\n try {\r\n new MouseEvent('test');\r\n return false; // No need to polyfill\r\n } catch (e) {\r\n // Need to polyfill - fall through\r\n }\r\n\r\n // Polyfills DOM4 MouseEvent\r\n var MouseEventPolyfill = function (eventType, params) {\r\n params = params || { bubbles: false, cancelable: false };\r\n var mouseEvent = document.createEvent('MouseEvent');\r\n mouseEvent.initMouseEvent(eventType,\r\n params.bubbles,\r\n params.cancelable,\r\n window,\r\n 0,\r\n params.screenX || 0,\r\n params.screenY || 0,\r\n params.clientX || 0,\r\n params.clientY || 0,\r\n params.ctrlKey || false,\r\n params.altKey || false,\r\n params.shiftKey || false,\r\n params.metaKey || false,\r\n params.button || 0,\r\n params.relatedTarget || null\r\n );\r\n\r\n return mouseEvent;\r\n }\r\n\r\n MouseEventPolyfill.prototype = Event.prototype;\r\n\r\n window.MouseEvent = MouseEventPolyfill;\r\n };\r\n\r\n return {\r\n init,\r\n };\r\n};","\r\nimport document from 'document';\r\n\r\nexport const contactPreferences = () => {\r\n const selectors = {\r\n labelGroup: '.form-field-group',\r\n checkbox: 'input[type=\"checkbox\"]',\r\n label: 'label',\r\n selected: '.selected',\r\n unselected: '.unselected'\r\n };\r\n\r\n const toggleText = (checkbox, label) => {\r\n const selectedText = label.querySelectorAll(selectors.selected)[0];\r\n var unselectedText = label.querySelectorAll(selectors.unselected)[0];\r\n\r\n if (checkbox.checked) {\r\n unselectedText.style.display = 'none';\r\n selectedText.style.display = 'block';\r\n } else {\r\n selectedText.style.display = 'none';\r\n unselectedText.style.display = 'block';\r\n }\r\n };\r\n\r\n const attachEvents = (root) => {\r\n const labelGroups = root.querySelectorAll(selectors.labelGroup);\r\n \r\n labelGroups.forEach(group => { \r\n const checkbox = group.querySelectorAll(selectors.checkbox)[0];\r\n const label = group.querySelectorAll(selectors.label)[0];\r\n \r\n toggleText(checkbox, label);\r\n checkbox.addEventListener('change', () => {\r\n toggleText(checkbox, label);\r\n });\r\n });\r\n };\r\n\r\n const init = component => {\r\n const root = document.getElementById(component.id);\r\n attachEvents(root);\r\n };\r\n\r\n return {\r\n init: init,\r\n selector: '#marketing-preferences-form'\r\n };\r\n};","// example from https://davidwalsh.name/pubsub-javascript\r\nexport const eventBus = (() => {\r\n\r\n var topics = {};\r\n\r\n var subscribe = function (topic, listener) {\r\n if (!topics.hasOwnProperty.call(topics, topic)) {\r\n topics[topic] = [];\r\n }\r\n topics[topic].push(listener);\r\n };\r\n\r\n var unsubscribe = function (topic) {\r\n delete topics[topic];\r\n };\r\n\r\n // fire the subscribed event\r\n var publish = function (topic, options) {\r\n // manages event queue\r\n if (!topics.hasOwnProperty.call(topics, topic)) {\r\n return;\r\n }\r\n\r\n topics[topic].forEach(function (item) {\r\n item(options != undefined ? options : {});\r\n });\r\n };\r\n\r\n return {\r\n subscribe: subscribe,\r\n unsubscribe: unsubscribe,\r\n publish: publish\r\n };\r\n})();","import window from 'window';\r\nimport document from 'document';\r\n\r\nexport const scrollTop = (() => {\r\n\r\n let activeAnimation;\r\n\r\n const stop = () => {\r\n activeAnimation = false;\r\n };\r\n \r\n /**\r\n * Simulates the animated scrollTop of jQuery. Used when css3:false or scrollBar:true or autoScrolling:false\r\n */\r\n const scrollTo = (params) => {\r\n const element = typeof params.element !== 'undefined' ? params.element : window;\r\n const to = params.to;\r\n const duration = typeof params.duration !== 'undefined' ? params.duration : 700;\r\n const callback = typeof params.callback !== 'undefined' ? params.callback : null;\r\n const easing = typeof params.easing !== 'undefined' ? params.easing : Math.easeInOutCubic;\r\n\r\n const start = element!==window ? element.scrollTop : (window.pageYOffset || document.documentElement.scrollTop) - (document.documentElement.clientTop || 0);\r\n const change = to - start;\r\n let currentTime = 0;\r\n const increment = 16; //same amount of milliseconds as requestAnimationFrame\r\n activeAnimation = true;\r\n\r\n const animateScroll = () => {\r\n\r\n //in case we want to stop it from other function whenever we want\r\n if (activeAnimation) {\r\n currentTime += increment;\r\n const easingValue = duration ? easing(currentTime, start, change, duration) : to;\r\n element.scrollTo(0, easingValue);\r\n\r\n if (currentTime < duration) {\r\n setTimeout(animateScroll, increment);\r\n } else if (callback){\r\n callback();\r\n }\r\n }else if (currentTime < duration && callback){\r\n callback();\r\n }\r\n };\r\n\r\n animateScroll();\r\n }\r\n\r\n return {\r\n scrollTo,\r\n stop\r\n };\r\n\r\n})();","import window from 'window';\r\nimport document from 'document';\r\nimport { scrollTop } from './scroll-top';\r\n\r\nexport const scroller = (() => {\r\n const isSmoothScrollSupported = 'scrollBehavior' in document.documentElement.style;\r\n const main = document.querySelector('main');\r\n\r\n const getScrollOffset = () => main ? main.offsetTop : 0;\r\n\r\n const scrollToElement = (element, callback, offsetTop = 0) => {\r\n const scrollOffset = getScrollOffset();\r\n const noop = () => { };\r\n\r\n if (isSmoothScrollSupported) {\r\n function scrollTo(offset, callback = noop) {\r\n const onScroll = function () {\r\n const scrollTop = window.scrollTop || window.pageYOffset;\r\n\r\n // run callback when current position has further scroll\r\n if (scrollTop <= offset) {\r\n window.removeEventListener('scroll', onScroll);\r\n callback();\r\n }\r\n }\r\n window.addEventListener('scroll', onScroll);\r\n onScroll();\r\n window.scrollTo({\r\n top: offset,\r\n behavior: 'smooth'\r\n });\r\n }\r\n\r\n const topOfElement = element.getBoundingClientRect().top + (window.scrollY || window.pageYOffset) - scrollOffset;\r\n\r\n scrollTo(topOfElement - offsetTop, callback);\r\n\r\n } else {\r\n const to = document.querySelector(element).offset().top - scrollOffset - offsetTop;\r\n scrollTop.scrollTo({\r\n to: to,\r\n easing: window.easings.easeOutBounce,\r\n duration: 500,\r\n callback: callback\r\n });\r\n }\r\n };\r\n\r\n const isScrolledIntoView = (element, offsetTop = 0) => {\r\n const rect = element.getBoundingClientRect();\r\n const scrollOffset = getScrollOffset() + offsetTop;\r\n const isInView = (rect.top >= scrollOffset) && (rect.bottom <= window.innerHeight);\r\n return isInView;\r\n };\r\n\r\n return {\r\n scrollToElement,\r\n isScrolledIntoView\r\n };\r\n})();","export const hasAttribute = (field, name) => field.getAttribute(name) != null;\r\n\r\nconst hasClass = (field, className) => field.classList.contains(className);\r\n\r\nexport const hasPattern = field => hasAttribute(field, 'pattern');\r\n\r\nexport const isRequired = field => hasAttribute(field, 'required');\r\n\r\nexport const isGroupRequired = field => hasAttribute(field, 'group-required');\r\n\r\nexport const accessibleInvalid = field => hasAttribute(field, 'aria-invalid');\r\n\r\nexport const isReadOnly = field => hasAttribute(field, 'readonly') || field.readOnly;\r\n\r\nexport const isDisabled = field => hasAttribute(field, 'disabled') || field.disabled;\r\n\r\nexport const hasMatching = field => hasAttribute(field, 'data-matching-text');\r\n\r\nexport const hasOptionValidate = field => hasAttribute(field, 'data-runtime-validate');\r\n\r\nexport const hasRuntimeValidate = field => hasClass(field, 'js-runtime-validate');\r\n\r\nexport const hasBlankAndPattern = field => hasPattern(field) && hasClass(field, 'js-validation-blank');\r\n\r\nexport const hasPatternOnlyValidation = field => hasAttribute(field, 'pattern-only-validation');\r\n\r\nexport const shouldBeValidated = field => {\r\n if (!hasPatternOnlyValidation(field) && !isRequired(field) && !field.value && !hasBlankAndPattern(field) && !isGroupRequired(field)) {\r\n return false;\r\n } else {\r\n return (!isReadOnly(field) &&\r\n !isDisabled(field) &&\r\n (hasPattern(field) || hasMatching(field) || isRequired(field)) || isGroupRequired(field));\r\n }\r\n};\r\n\r\nexport const matchesPattern = field => {\r\n try { \r\n if (!hasPattern(field)) {\r\n return false;\r\n } else {\r\n var pattern = field.getAttribute('pattern');\r\n\r\n return (field.value || hasBlankAndPattern(field)) && new RegExp(pattern).test(field.value);\r\n }\r\n }\r\n catch (error) {\r\n console.error(error.message);\r\n }\r\n};\r\n\r\nexport const matchingText = field => {\r\n try {\r\n if (!hasMatching(field)) {\r\n return false;\r\n } else {\r\n const fieldToMatch = field.getAttribute('data-matching-text');\r\n const matchingElement = document.getElementById(fieldToMatch);\r\n\r\n return matchingElement === null || field.value === matchingElement.value;\r\n }\r\n }\r\n catch (error) {\r\n console.error(error.message);\r\n }\r\n};\r\n\r\nexport const hasMinimumOptionsChecked = field => {\r\n var nodeList = document.getElementsByName(field.name);\r\n\r\n var minRequiredOptions = field.getAttribute('min-required');\r\n\r\n if (isNaN(minRequiredOptions)) {\r\n return false;\r\n }\r\n\r\n if (nodeList && nodeList.length > 0) {\r\n var group = Array.from(nodeList);\r\n\r\n var checkedItems = group.filter(function (element) {\r\n return element.checked;\r\n });\r\n\r\n return checkedItems.length >= minRequiredOptions;\r\n }\r\n\r\n return false;\r\n};\r\n\r\nexport const disableSubmitButton = btn => {\r\n\r\n if (btn) {\r\n btn.setAttribute(\"disabled\", \"true\");\r\n }\r\n};","export const Field = field => {\r\n const visible = 'visible';\r\n\r\n const formGroup = field.closest('.js-field-validate , [data-validation-role=\"js-field-validate\"]');\r\n const fieldAsterik = field.parentNode.querySelector('.form-field-group__asterik');\r\n const errorMessage = formGroup && formGroup.querySelector('.js-field-validate--error');\r\n\r\n if (!errorMessage) {\r\n console.warn(\"Error message missing for\", field);\r\n }\r\n\r\n return {\r\n element: field,\r\n formGroup: formGroup,\r\n showError() {\r\n if (field.type === \"checkbox\" || field.type === \"radio\") {\r\n this.toggleForGroup(true);\r\n } else {\r\n field.setAttribute('aria-invalid', 'true');\r\n }\r\n if (errorMessage) {\r\n const adjacentInput = errorMessage.previousElementSibling;\r\n const inputName = adjacentInput.getAttribute('name');\r\n const errorId = `${inputName}-error`;\r\n errorMessage.classList.add(visible);\r\n adjacentInput.setAttribute('aria-describedby', errorId);\r\n errorMessage.setAttribute('id', errorId);\r\n }\r\n },\r\n hideError() {\r\n if (field.type === \"checkbox\" || field.type === \"radio\") {\r\n this.toggleForGroup(false);\r\n } else {\r\n field.removeAttribute('aria-invalid');\r\n }\r\n if (errorMessage) {\r\n const adjacentInput = errorMessage.previousElementSibling;\r\n const inputName = adjacentInput.getAttribute('name');\r\n const errorId = `${inputName}-error`;\r\n errorMessage.classList.remove(visible);\r\n adjacentInput.removeAttribute('aria-describedby', errorId);\r\n errorMessage.removeAttribute('id', errorId);\r\n }\r\n },\r\n setEagerValidation() {\r\n field.setAttribute('data-eager-validate', '');\r\n },\r\n setRequired() {\r\n field.setAttribute('required', 'required');\r\n fieldAsterik && fieldAsterik.classList.remove('hide');\r\n },\r\n removeRequired() {\r\n field.removeAttribute('required');\r\n fieldAsterik && fieldAsterik.classList.add('hide');\r\n },\r\n isReactiveValidationEnabled() {\r\n return field.hasAttribute('data-reactive-validate');\r\n },\r\n isEagerValidationEnabled() {\r\n return field.hasAttribute('data-eager-validate');\r\n },\r\n focus() {\r\n field.focus();\r\n },\r\n toggleForGroup(toggleOn) {\r\n\r\n var nodeList = document.getElementsByName(field.name);\r\n\r\n if (nodeList && nodeList.length > 0) {\r\n if (toggleOn) {\r\n [...nodeList].map(x => x.setAttribute('aria-invalid', 'true'));\r\n } else {\r\n [...nodeList].map(x => x.removeAttribute('aria-invalid'));\r\n\r\n }\r\n }\r\n }\r\n };\r\n}","import { scroller } from '../../utilities/scroller';\r\nimport { eventBus } from '../../foundation/eventBus';\r\nimport { shouldBeValidated, isRequired, hasPattern, hasAttribute, matchesPattern, hasMatching, matchingText, isGroupRequired, hasMinimumOptionsChecked, disableSubmitButton } from '../../foundation/form/validation';\r\nimport { Field } from './field';\r\n\r\nexport const events = {\r\n formSubmitted: 'formSubmitted',\r\n validate: 'validate',\r\n};\r\n\r\nexport const enableFormSubmission = () => {\r\n\r\n const Form = function (form) {\r\n form.setAttribute('novalidate', '');\r\n\r\n let isSubmitted = false;\r\n\r\n // Check if input needs validating or not\r\n const shouldSkipValidation = (field) => !field || !field.element;\r\n\r\n function getFields() {\r\n const allFields = [...form.querySelectorAll('input, textarea, select')];\r\n\r\n return allFields.filter(field => shouldBeValidated(field))\r\n .map(field => Field(field));\r\n }\r\n\r\n const isValidField = field => {\r\n if (shouldSkipValidation(field)) {\r\n return;\r\n }\r\n\r\n let isInvalid;\r\n\r\n const element = field.element;\r\n\r\n if (hasAttribute(element, 'skip-validation')) {\r\n return true;\r\n } else if (element.type === 'checkbox' || element.type === 'radio') {\r\n isInvalid = (isRequired(element) && !element.checked) || (isGroupRequired(element) && !hasMinimumOptionsChecked(element));\r\n } else if(hasAttribute(element, 'pattern-only-validation')) {\r\n if(isRequired(element)) {\r\n isInvalid = !element.value.trim() || (hasPattern(element) && !matchesPattern(element));\r\n } else {\r\n isInvalid = element.value.trim() ? (hasPattern(element) && !matchesPattern(element)) : false;\r\n }\r\n } else {\r\n isInvalid = (isRequired(element) && !element.value.trim()) || (hasPattern(element) && !matchesPattern(element)) || (hasMatching(element) && !matchingText(element));\r\n }\r\n\r\n return !isInvalid;\r\n };\r\n\r\n const isValidForm = () => getFields().every(isValidField);\r\n\r\n const validateField = field => {\r\n if (shouldSkipValidation(field)) {\r\n return;\r\n }\r\n\r\n const isValid = isValidField(field);\r\n\r\n if (isValid) {\r\n field.hideError();\r\n } else {\r\n field.showError();\r\n field.setEagerValidation();\r\n }\r\n\r\n return isValid;\r\n };\r\n\r\n const validateForm = (options = {}) => {\r\n const isValid = isValidForm();\r\n\r\n if (!options.ignoreErrors) {\r\n getFields().forEach(field => {\r\n validateField(field);\r\n });\r\n }\r\n\r\n return isValid;\r\n };\r\n\r\n function submitEvent(event) {\r\n isSubmitted = true;\r\n const isValidForm = validateForm();\r\n\r\n eventBus.publish(events.formSubmitted, { isValidForm: isValidForm, id : form.id, event: event });\r\n\r\n if (!isValidForm) {\r\n event.preventDefault();\r\n const field = getFields().find(field => !isValidField(field));\r\n const element = field.formGroup;\r\n\r\n const paddingTop = 8;\r\n\r\n if (element && !scroller.isScrolledIntoView(element, paddingTop)) {\r\n scroller.scrollToElement(element, field.focus, paddingTop);\r\n } else {\r\n field.focus();\r\n }\r\n } else {\r\n var button = document.querySelector(\"[data-submit-disable]\");\r\n disableSubmitButton(button);\r\n }\r\n }\r\n\r\n const bindEvents = () => {\r\n getFields().forEach(field => {\r\n if (shouldSkipValidation(field)) {\r\n return;\r\n }\r\n\r\n const element = field.element;\r\n const eventType = ['checkbox', 'radio', 'select-one'].includes(element.type) ? 'change' : 'blur';\r\n\r\n const handler = event => {\r\n const shouldRun = ((event.type === 'blur' || event.type === 'change') && !field.isEagerValidationEnabled() && (isSubmitted || Boolean(element.value))) || field.isEagerValidationEnabled();\r\n\r\n if (shouldRun) {\r\n validateField(field);\r\n }\r\n\r\n if (eventType === 'blur' && element && element.type === 'date' && element.value && element.max) {\r\n let date = new Date(element.value).toISOString().slice(0, 10);\r\n let today = new Date().toISOString().slice(0, 10);\r\n if (date > today) {\r\n element.value = today;\r\n }\r\n }\r\n };\r\n\r\n element.addEventListener(eventType, handler);\r\n\r\n if (eventType === 'blur') {\r\n element.addEventListener('input', handler);\r\n }\r\n });\r\n\r\n form.onsubmit = submitEvent;\r\n };\r\n\r\n return {\r\n init() {\r\n bindEvents();\r\n eventBus.subscribe(events.validate, validateForm);\r\n }\r\n };\r\n };\r\n\r\n const init = component => {\r\n const form = new Form(component);\r\n form.init();\r\n };\r\n\r\n return {\r\n init: init,\r\n selector: '[data-component=\"form\"] .js-form, .form .js-form'\r\n };\r\n};","\r\nconst ajaxRequest = (() => {\r\n\r\n const post = (url, data, contentType, success) => {\r\n return _makeRequest('POST', url, data, contentType, success);\r\n }\r\n\r\n const get = (url, data, contentType, success) => {\r\n return _makeRequest('GET', url, data, contentType, success);\r\n }\r\n\r\n const _makeRequest = (httpMethod, url, data, contentType, success) => {\r\n const params = typeof data == 'string' ? data : Object.keys(data).map(\r\n (k) => { return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]) }\r\n ).join('&');\r\n const xhr = new XMLHttpRequest();\r\n xhr.open(httpMethod, url);\r\n xhr.onreadystatechange = function() {\r\n if (xhr.readyState>3 && xhr.status==200) { success(xhr.responseText); }\r\n };\r\n xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');\r\n xhr.setRequestHeader('Content-Type', contentType || 'application/x-www-form-urlencoded; charset=UTF-8');\r\n xhr.send(params);\r\n return xhr;\r\n }\r\n\r\n const jsonp = (url, dataObj, timeout) => {\r\n const params = typeof dataObj == 'string' ? dataObj : Object.keys(dataObj).map(\r\n (k) => { return encodeURIComponent(k) + '=' + encodeURIComponent(dataObj[k]) }\r\n ).join('&');\r\n \r\n return new Promise((resolve, reject) => { \r\n timeout = timeout || 10000; // default timeout \r\n const callbackName=\"jsonp\"+(+new Date());\r\n const head = document.getElementsByTagName('head')[0] || document.documentElement;\r\n const script = document.createElement('script');\r\n script.src =`${url}${url.includes('?')?'&':'?'}${params}&callback=${callbackName}&v=1.0`;\r\n script.async = \"true\";\r\n \r\n window[callbackName] = (data) => {\r\n cleanUp();\r\n resolve(data);\r\n }\r\n \r\n script.onerror = () => {\r\n cleanUp();\r\n reject( Error(\"Network error loading \" + script.src) );\r\n }\r\n \r\n head.appendChild(script);\r\n const timeoutFunction = setTimeout(function() {\r\n cleanUp();\r\n reject( Error(\"Request to \" + url + \" failed to execute callback after \" + timeout + \"ms.\") ) \r\n }, timeout);\r\n \r\n const cleanUp = () => {\r\n timeoutFunction && clearTimeout(timeoutFunction);\r\n window[callbackName] && delete window[callbackName];\r\n script && head.removeChild(script);\r\n }\r\n \r\n } );\r\n }\r\n\r\n const fetchRequest = async (url, data, method, success) => {\r\n return await fetch(\r\n url,\r\n {\r\n method: method,\r\n body: data\r\n })\r\n .then((response) => {\r\n success(response); \r\n }) \r\n .catch((err) => {\r\n throw new Error(`Request to ${url} failed!`, err);\r\n });\r\n }\r\n\r\n return {\r\n post,\r\n get,\r\n jsonp,\r\n fetch: fetchRequest,\r\n };\r\n})();\r\n\r\nexport { ajaxRequest };","import document from 'document';\r\nimport { eventBus } from '../../foundation/eventBus';\r\nimport { events as formEvents } from '../../feature/form/enable-form';\r\nimport { ajaxRequest } from '../../utilities/ajax';\r\n\r\nexport const accountRegistration = () => {\r\n\r\n let isValidRegistration = false;\r\n const serverErrorHiddenClass = \"form-field-group__server-error--hidden\";\r\n\r\n const selectors = { \r\n serverError: '.form-field-group__server-error',\r\n }\r\n\r\n const _redirect = (url) => { \r\n window.location = url;\r\n }\r\n\r\n const _handleTvSquared = component => {\r\n var _tvq = window._tvq = window._tvq || [];\r\n const siteId = component.getAttribute(\"data-tvsquared-siteid\");\r\n const actionTag = component.getAttribute(\"data-tvsquared-actiontag\");\r\n\r\n (function(){\r\n var actionname = actionTag;\r\n var action = {\r\n 'rev': '',\r\n 'prod': '',\r\n 'id': actionname,\r\n 'promo': ''\r\n };\r\n\r\n const tvSquaredDomain = component.getAttribute(\"data-tvsquared-domain\");\r\n var u = ((\"https:\" == document.location.protocol)\r\n ? \"https://\" + tvSquaredDomain\r\n : \"http://\" + tvSquaredDomain);\r\n _tvq.push(['setSiteId', siteId]);\r\n _tvq.push(['setTrackerUrl', u + 'tv2track.php']);\r\n _tvq.push([function () {\r\n this.setCustomVariable(5, actionname, JSON.stringify(action), 'page')\r\n }]);\r\n _tvq.push(['trackPageView']);\r\n var d = document,\r\n g = d.createElement('script'),\r\n s = d.getElementsByTagName('script')[0];\r\n g.type = 'text/javascript';\r\n g.defer = true;\r\n g.async = true;\r\n g.src = u + 'tv2track.js';\r\n s.parentNode.insertBefore(g, s);\r\n })();\r\n }\r\n\r\n const _registerAccount = async (component) => {\r\n const element = document.querySelector(selectors.serverError);\r\n const url = component.getAttribute(\"action\");\r\n const method = component.getAttribute(\"method\");\r\n const data = new FormData(component);\r\n\r\n data.append(\"submit\", \"Submit\");\r\n\r\n try { \r\n await ajaxRequest.fetch(url, data, method,\r\n (response) => {\r\n if (response.redirected) {\r\n\r\n const isTvSquaredEnabled = component.getAttribute(\"data-tvsquared-enabled\");\r\n if (isTvSquaredEnabled === \"True\") { \r\n _handleTvSquared(component);\r\n }\r\n \r\n _redirect(response.url + '?registration=true'); \r\n } else {\r\n element.classList.remove(serverErrorHiddenClass);\r\n } \r\n });\r\n }\r\n catch (err) {\r\n console.log(\"Something went wrong!\", err);\r\n }\r\n }\r\n\r\n const _bindEvents = component => {\r\n\r\n component.addEventListener('submit', async (e) => {\r\n e.preventDefault();\r\n \r\n if (isValidRegistration){\r\n _registerAccount(component);\r\n } \r\n });\r\n };\r\n\r\n const init = component => {\r\n\r\n eventBus.subscribe(formEvents.formSubmitted, (data) => {\r\n isValidRegistration = data.isValidForm;\r\n });\r\n \r\n _bindEvents(component);\r\n };\r\n\r\n return {\r\n init,\r\n selector: '.register-form form'\r\n };\r\n};","import document from 'document';\r\nimport { eventBus } from '../../foundation/eventBus';\r\nimport { events as formEvents } from '../../feature/form/enable-form';\r\n\r\nexport const finishRegistration = () => {\r\n const _disableRegistrationButton = async () => {\r\n const element = document.getElementById('saveDetailsBtn');\r\n element.disabled = true;\r\n }\r\n\r\n const init = () => {\r\n eventBus.subscribe(formEvents.formSubmitted, (data) => {\r\n if (data.isValidForm && window.location.pathname === '/finish-registration') {\r\n _disableRegistrationButton();\r\n }\r\n });\r\n };\r\n\r\n return {\r\n init\r\n };\r\n};","export const marketingPreferencesRebrand = () => {\r\n\r\n const init = component => { \r\n const checkboxes = [...component.querySelectorAll(\"input[type='checkbox']\")];\r\n\r\n checkboxes.forEach(checkbox => {\r\n checkbox.addEventListener('change', event => {\r\n event.target.value = event.target.checked;\r\n });\r\n });\r\n };\r\n\r\n return {\r\n init,\r\n selector: '.marketing-preference-rebrand'\r\n };\r\n};","export const revealPassword = () => {\r\n \r\n const toggleInputType = input => {\r\n const type = input.type === 'password' ? 'text' : 'password';\r\n input.setAttribute('type', type);\r\n };\r\n\r\n const init = component => {\r\n const revelPasswordIcon = component.querySelector('.js-reveal-password');\r\n const passwordField = component.querySelector('.js-password-field');\r\n\r\n if (revelPasswordIcon && passwordField) {\r\n revelPasswordIcon.addEventListener('click', () => {\r\n toggleInputType(passwordField);\r\n });\r\n }\r\n };\r\n\r\n return {\r\n init,\r\n selector: '[data-component=\"password-reveal\"]'\r\n };\r\n};\r\n","// debounce example function https://remysharp.com/2010/07/21/throttling-function-calls#comment-497362\r\nexport const debounce = (fn, delay) => {\r\n let timer = null;\r\n return function () {\r\n const context = this;\r\n const args = arguments;\r\n clearTimeout(timer);\r\n timer = setTimeout(() => {\r\n fn.apply(context, args);\r\n }, delay);\r\n };\r\n};","import document from 'document';\r\nimport { eventBus } from '../../foundation/eventBus';\r\nimport { debounce } from '../../utilities/debounce';\r\nimport { events as formEvents } from '../../feature/form/enable-form';\r\nimport { ajaxRequest } from '../../utilities/ajax';\r\n\r\nexport const bankAccountLookup = () => {\r\n // API documentation https://www.pcapredict.com/support/webservice/bankaccountvalidation/interactive/validate/2/\r\n const selectors = {\r\n root: '.form',\r\n button: '.find-bank-account-btn',\r\n field: '.form-field-group__input',\r\n sortCodeField: '.js-sort-code',\r\n accountNumberField: '.js-account-number',\r\n errorMessage: '.form-field-group__error',\r\n resultError: '.find-bank-account-error',\r\n postcodeError: '.bank-postcode-error',\r\n continueBtn: '.form-button-group__submit-btn',\r\n hiddenFieldValidator: '.js-bank-valid'\r\n };\r\n\r\n let config = {}; // global object that gets mapped to later in the code\r\n\r\n const _makeRequest = (service, dataObj, func) => {\r\n\r\n const url = service.url + '?' + Object.keys(dataObj).map(\r\n (k) => { return encodeURIComponent(k) + '=' + encodeURIComponent(dataObj[k]) }\r\n ).join('&');\r\n ajaxRequest.get(url, dataObj, 'application/json', func);\r\n };\r\n\r\n const _populateAddress = (data) => {\r\n\r\n if (data != null && data != {}) {\r\n\r\n const fields = Array.from(document.querySelector(selectors.root).querySelectorAll(selectors.field));\r\n const addressKeys = Object.keys(data);\r\n\r\n function populateField(key) {\r\n const field = fields.filter((item) => {\r\n const itemAttr = item.getAttribute('data-address-key');\r\n if (itemAttr === key) {\r\n return itemAttr;\r\n }\r\n })[0];\r\n\r\n if (field) {\r\n field.value = data[field.getAttribute('data-address-key')];\r\n field.removeAttribute('aria-invalid');\r\n field.removeAttribute(selectors.errorMessage);\r\n field.classList.remove('visible');\r\n }\r\n }\r\n\r\n addressKeys.forEach(populateField);\r\n\r\n _validatePageBeacon();\r\n }\r\n };\r\n\r\n const _clearBankAddressFields = (data) => {\r\n const fields = Array.from(document.querySelector(selectors.root).querySelectorAll(selectors.field));\r\n const addressKeys = Object.keys(data);\r\n\r\n function clearField(key) {\r\n const field = fields.filter((item) => {\r\n const itemAttr = item.getAttribute('data-address-key');\r\n if (itemAttr === key) {\r\n return itemAttr;\r\n }\r\n })[0];\r\n\r\n if (field) {\r\n field.value = '';\r\n }\r\n }\r\n\r\n addressKeys.forEach(clearField);\r\n }\r\n\r\n const _validatePageBeacon = () => {\r\n eventBus.publish(formEvents.validate);\r\n };\r\n\r\n const _validBankDetails = () => {\r\n document.querySelector(selectors.resultError).classList.remove('visible');\r\n };\r\n\r\n const _invalidBankDetails = () => {\r\n document.querySelector(selectors.resultError).classList.add('visible');\r\n };\r\n\r\n const _updateHiddenCheckbox = (state) => {\r\n document.querySelector(selectors.hiddenFieldValidator).check = state;\r\n };\r\n\r\n const _isHiddenCheckboxChecked = () => {\r\n return document.querySelector(selectors.hiddenFieldValidator).check;\r\n };\r\n\r\n const _hasBankAccountDetailsBeenCorrected = () => {\r\n // returns a true or false statement from the PCA api if the account number requires correction\r\n // due to acceptance criteria change we have hard coded the corrected details to false as of 18/01/2018\r\n return false;\r\n };\r\n\r\n const _correctAccountNumber = (data) => {\r\n // if PCA returns corrected details update the bank account number field \r\n document.querySelector(selectors.accountNumberField).value = data.correctedAccountNumber;\r\n };\r\n\r\n const _isDirectDebitCompatible = (data) => {\r\n // return a true or false if the bank account has direct debit capability\r\n return data.isDirectDebitCapable;\r\n };\r\n\r\n const _isCorrectBankDetails = (data) => {\r\n return data.isCorrect;\r\n };\r\n\r\n const _isBankPostcodeAvailable = (data) => {\r\n if (data.contactPostcode == '' || null) {\r\n return false;\r\n }\r\n else {\r\n _validBankPostcode();\r\n return true;\r\n }\r\n };\r\n\r\n const _validBankPostcode = () => {\r\n document.querySelector(selectors.postcodeError).classList.remove('visible');\r\n _enableContinueBtn();\r\n };\r\n\r\n const _invalidBankPostcode = () => {\r\n document.querySelector(selectors.postcodeError).classList.add('visible');\r\n _disableContinueBtn();\r\n };\r\n\r\n const _enableContinueBtn = () => {\r\n document.querySelector(selectors.continueBtn).classList.remove('disabled');\r\n };\r\n\r\n const _disableContinueBtn = () => {\r\n if (!document.querySelector(selectors.continueBtn).classList.contains('disabled')) {\r\n document.querySelector(selectors.continueBtn).classList.add('disabled');\r\n }\r\n };\r\n\r\n const _responseActions = (data) => {\r\n var dataObj = JSON.parse(data);\r\n if (!_isBankPostcodeAvailable(dataObj)) {\r\n _clearBankAddressFields(dataObj);\r\n _invalidBankPostcode();\r\n }\r\n else if (_isCorrectBankDetails(dataObj) && _isDirectDebitCompatible(dataObj) && !_hasBankAccountDetailsBeenCorrected()) {\r\n _updateHiddenCheckbox(true);\r\n _populateAddress(dataObj);\r\n _validBankDetails();\r\n }\r\n else if (_isCorrectBankDetails(dataObj) && _isDirectDebitCompatible(dataObj) && _hasBankAccountDetailsBeenCorrected()) {\r\n _correctAccountNumber(dataObj);\r\n _updateHiddenCheckbox(true);\r\n _populateAddress(dataObj);\r\n _validBankDetails();\r\n }\r\n else {\r\n _updateHiddenCheckbox(false);\r\n _invalidBankDetails();\r\n }\r\n };\r\n\r\n const _getBranchDetails = (sortCode, accountNumber) => {\r\n if (sortCode != '' && accountNumber != '') {\r\n const branchDetails = [\r\n {\r\n url: config.bankAccountValidatorService\r\n },\r\n {\r\n AccountNumber: accountNumber,\r\n SortCode: sortCode\r\n },\r\n function (data) {\r\n _responseActions(data);\r\n }\r\n ];\r\n _makeRequest.apply(null, branchDetails);\r\n }\r\n };\r\n\r\n const _getSortCode = (el) => {\r\n return el.closest(selectors.root).querySelector(selectors.sortCodeField).value;\r\n };\r\n\r\n const _getAccountNumber = (el) => {\r\n return el.closest(selectors.root).querySelector(selectors.accountNumberField).value;\r\n };\r\n\r\n const _bindEvents = (root) => {\r\n const button = root.querySelector(selectors.button);\r\n button.addEventListener('click', (e) => {\r\n e.preventDefault();\r\n _getBranchDetails.call(\r\n null,\r\n _getSortCode(e.currentTarget),\r\n _getAccountNumber(e.currentTarget)\r\n );\r\n eventBus.publish(formEvents.validate);\r\n });\r\n\r\n root.querySelector(selectors.sortCodeField).addEventListener('input', _debounce);\r\n root.querySelector(selectors.accountNumberField).addEventListener('input', _debounce);\r\n };\r\n\r\n const _debounce = debounce(function () {\r\n if (_isHiddenCheckboxChecked()) {\r\n _updateHiddenCheckbox(false);\r\n }\r\n }, 200);\r\n\r\n const _getSettings = (root, resolve) => {\r\n const pcaBtn = root.querySelectorAll(selectors.button);\r\n\r\n if (pcaBtn.length > 0) {\r\n const element = pcaBtn[0];\r\n const data = {\r\n bankAccountValidatorService: element.dataset.bankAccountValidator\r\n };\r\n config = { ...config, ...data };\r\n resolve(true);\r\n }\r\n };\r\n\r\n const init = () => {\r\n const root = document.querySelectorAll(selectors.root)[0];\r\n if (root) {\r\n const readSettings = new Promise((resolve) => {\r\n _getSettings(root, resolve);\r\n });\r\n readSettings\r\n .then(() => {\r\n _bindEvents(root);\r\n });\r\n }\r\n };\r\n\r\n return {\r\n init: init\r\n };\r\n};\r\n","import window from 'window';\r\n\r\n/* FileSaver.js\r\n * A saveAs() FileSaver implementation.\r\n * 1.3.2\r\n * 2016-06-16 18:25:19\r\n *\r\n * By Eli Grey, http://eligrey.com\r\n * License: MIT\r\n * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md\r\n */\r\n\r\n/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */\r\n\r\n/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */\r\n\r\nvar saveAs = saveAs || (function (view) {\r\n \"use strict\";\r\n \r\n // IE <10 is explicitly unsupported\r\n if (typeof view === \"undefined\" || typeof navigator !== \"undefined\" && /MSIE [1-9]\\./.test(navigator.userAgent)) {\r\n return;\r\n }\r\n var\r\n doc = view.document\r\n // only get URL when necessary in case Blob.js hasn't overridden it yet\r\n , get_URL = function () {\r\n return view.URL || view.webkitURL || view;\r\n }\r\n , save_link = doc.createElementNS(\"http://www.w3.org/1999/xhtml\", \"a\")\r\n , can_use_save_link = \"download\" in save_link\r\n , click = function (node) {\r\n var event = new MouseEvent(\"click\");\r\n node.dispatchEvent(event);\r\n }\r\n , is_safari = /constructor/i.test(view.HTMLElement) || view.safari\r\n , is_chrome_ios = /CriOS\\/[\\d]+/.test(navigator.userAgent)\r\n , throw_outside = function (ex) {\r\n (view.setImmediate || view.setTimeout)(function () {\r\n throw ex;\r\n }, 0);\r\n }\r\n , force_saveable_type = \"application/octet-stream\"\r\n // the Blob API is fundamentally broken as there is no \"downloadfinished\" event to subscribe to\r\n , arbitrary_revoke_timeout = 1000 * 40 // in ms\r\n , revoke = function (file) {\r\n var revoker = function () {\r\n if (typeof file === \"string\") { // file is an object URL\r\n get_URL().revokeObjectURL(file);\r\n } else { // file is a File\r\n file.remove();\r\n }\r\n };\r\n setTimeout(revoker, arbitrary_revoke_timeout);\r\n }\r\n , dispatch = function (filesaver, event_types, event) {\r\n event_types = [].concat(event_types);\r\n var i = event_types.length;\r\n while (i--) {\r\n var listener = filesaver[\"on\" + event_types[i]];\r\n if (typeof listener === \"function\") {\r\n try {\r\n listener.call(filesaver, event || filesaver);\r\n } catch (ex) {\r\n throw_outside(ex);\r\n }\r\n }\r\n }\r\n }\r\n , auto_bom = function (blob) {\r\n // prepend BOM for UTF-8 XML and text/* types (including HTML)\r\n // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF\r\n if (/^\\s*(?:text\\/\\S*|application\\/xml|\\S*\\/\\S*\\+xml)\\s*;.*charset\\s*=\\s*utf-8/i.test(blob.type)) {\r\n return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type });\r\n }\r\n return blob;\r\n }\r\n , FileSaver = function (blob, name, no_auto_bom) {\r\n if (!no_auto_bom) {\r\n blob = auto_bom(blob);\r\n }\r\n // First try a.download, then web filesystem, then object URLs\r\n var\r\n filesaver = this\r\n , type = blob.type\r\n , force = type === force_saveable_type\r\n , object_url\r\n , dispatch_all = function () {\r\n dispatch(filesaver, \"writestart progress write writeend\".split(\" \"));\r\n }\r\n // on any filesys errors revert to saving with object URLs\r\n , fs_error = function () {\r\n if ((is_chrome_ios || (force && is_safari)) && view.FileReader) {\r\n // Safari doesn't allow downloading of blob urls\r\n var reader = new FileReader();\r\n reader.onloadend = function () {\r\n var url = is_chrome_ios ? reader.result : reader.result.replace(/^data:[^;]*;/, 'data:attachment/file;');\r\n var popup = view.open(url, '_blank');\r\n if (!popup) view.location.href = url;\r\n url = undefined; // release reference before dispatching\r\n filesaver.readyState = filesaver.DONE;\r\n dispatch_all();\r\n };\r\n reader.readAsDataURL(blob);\r\n filesaver.readyState = filesaver.INIT;\r\n return;\r\n }\r\n // don't create more object URLs than needed\r\n if (!object_url) {\r\n object_url = get_URL().createObjectURL(blob);\r\n }\r\n if (force) {\r\n view.location.href = object_url;\r\n } else {\r\n var opened = view.open(object_url, \"_blank\");\r\n if (!opened) {\r\n // Apple does not allow window.open, see https://developer.apple.com/library/safari/documentation/Tools/Conceptual/SafariExtensionGuide/WorkingwithWindowsandTabs/WorkingwithWindowsandTabs.html\r\n view.location.href = object_url;\r\n }\r\n }\r\n filesaver.readyState = filesaver.DONE;\r\n dispatch_all();\r\n revoke(object_url);\r\n }\r\n ;\r\n filesaver.readyState = filesaver.INIT;\r\n\r\n if (can_use_save_link) {\r\n object_url = get_URL().createObjectURL(blob);\r\n setTimeout(function () {\r\n save_link.href = object_url;\r\n save_link.download = name;\r\n click(save_link);\r\n dispatch_all();\r\n revoke(object_url);\r\n filesaver.readyState = filesaver.DONE;\r\n });\r\n return;\r\n }\r\n\r\n fs_error();\r\n }\r\n , FS_proto = FileSaver.prototype\r\n , saveAs = function (blob, name, no_auto_bom) {\r\n return new FileSaver(blob, name || blob.name || \"download\", no_auto_bom);\r\n }\r\n ;\r\n // IE 10+ (native saveAs)\r\n if (typeof navigator !== \"undefined\" && navigator.msSaveOrOpenBlob) {\r\n return function (blob, name, no_auto_bom) {\r\n name = name || blob.name || \"download\";\r\n\r\n if (!no_auto_bom) {\r\n blob = auto_bom(blob);\r\n }\r\n return navigator.msSaveOrOpenBlob(blob, name);\r\n };\r\n }\r\n\r\n FS_proto.abort = function () { };\r\n FS_proto.readyState = FS_proto.INIT = 0;\r\n FS_proto.WRITING = 1;\r\n FS_proto.DONE = 2;\r\n\r\n FS_proto.error =\r\n FS_proto.onwritestart =\r\n FS_proto.onprogress =\r\n FS_proto.onwrite =\r\n FS_proto.onabort =\r\n FS_proto.onerror =\r\n FS_proto.onwriteend =\r\n null;\r\n\r\n return saveAs;\r\n}(\r\n typeof self !== \"undefined\" && self\r\n || typeof window !== \"undefined\" && window\r\n || Function('return typeof this === \"object\" && this.content')()\r\n));\r\n// `self` is undefined in Firefox for Android content script context\r\n// while `this` is nsIContentFrameMessageManager\r\n// with an attribute `content` that corresponds to the window\r\n\r\nexport { saveAs };","import window from 'window';\r\nimport document from 'document';\r\nimport { saveAs } from '../../utilities/file-saver';\r\n\r\nexport const downloadAgreement = () => {\r\n\r\n const selectors = {\r\n downloadInput: '.download-agreement__btn',\r\n };\r\n\r\n const config = {\r\n url: '/api/orders/downloadagreement',\r\n disabled: 'disabled',\r\n contentype: 'content-type',\r\n blob: 'blob',\r\n formtype: 'application/x-www-form-urlencoded',\r\n octettype: 'application/octet-stream',\r\n jsontype: 'application/json',\r\n texttype: 'text/plain'\r\n };\r\n\r\n var _download = function (e) {\r\n const el = e.currentTarget;\r\n el.disabled = config.disabled;\r\n var url = config.url + '?agreementnumber=' + el.dataset.agreementno + '&proposalnumber=' + el.dataset.proposalnumber;\r\n\r\n var xhttp = new XMLHttpRequest();\r\n xhttp.open('GET', url, true);\r\n xhttp.setRequestHeader(config.contentype, config.formtype);\r\n xhttp.responseType = config.blob;\r\n xhttp.onreadystatechange = function () {\r\n if (xhttp.readyState == 4) {\r\n el.disabled = false;\r\n if (xhttp.status == 401) {\r\n window.location.replace(this.getResponseHeader(\"LoginPage\"));\r\n }\r\n if (xhttp.status == 200) {\r\n var isJson = this.getResponseHeader(config.contentype).indexOf(config.jsontype) != -1;\r\n if (isJson) {\r\n var myblob = new Blob([this.response], { type: config.texttype });\r\n var reader = new FileReader();\r\n reader.onload = function () { alert(reader.result); }\r\n reader.readAsText(myblob);\r\n } else {\r\n saveAs(new Blob([this.response], { type: config.octettype }), el.dataset.filename);\r\n }\r\n }\r\n }\r\n };\r\n xhttp.send();\r\n };\r\n\r\n return {\r\n init: function () {\r\n const input = document.querySelectorAll(selectors.downloadInput);\r\n if (input.length) {\r\n input.forEach((element) => element.addEventListener('click', _download));\r\n }\r\n }\r\n };\r\n};","import document from 'document';\r\nimport { eventBus } from '../../foundation/eventBus';\r\nimport { events as formEvents } from '../../feature/form/enable-form';\r\n\r\nexport const postcodeLookup = () => {\r\n\r\n const selectors = {\r\n root: '.form',\r\n searchField: '.js-postcode-lookup',\r\n field: '.form-field-group__input',\r\n postcodeField: '.form-field-group__postcode',\r\n addressList: 'js-address-list',\r\n searchButton: '.find-address-btn',\r\n resultsContainer: '.address-search',\r\n errorMessage: '.form-field-group__error',\r\n warningMessageLocation: '.form-section',\r\n warningMessage: '.form-field-group__warningMessage',\r\n manualAddressButton: '.manual-address-link',\r\n hiddenField: '.js-hidden-fields',\r\n visibleFieldToggle: 'form-field-group__hidden-fields--visible'\r\n };\r\n\r\n var config = {};\r\n\r\n var _makeRequest = function (service, dataObj, func)\r\n {\r\n service.url += '?' + ( new URLSearchParams( dataObj ) ).toString();\r\n var method = 'GET'\r\n let options = {\r\n method\r\n };\r\n fetch(service.url, options)\r\n .then((response) => response.json())\r\n .then((result) => {\r\n if (result.Items && result.Items[0].Error) {\r\n var dataMessage = result.Items[0];\r\n console.warn(`Error: ${dataMessage.Error}, ${dataMessage.Description}, ${dataMessage.Cause}, ${dataMessage.Resolution}`);\r\n }\r\n else\r\n {\r\n if (typeof func != 'function')\r\n {\r\n console.warn(func + ' is not a function');\r\n }\r\n else\r\n {\r\n func(result);\r\n }\r\n }\r\n })\r\n .catch((error) => {\r\n console.warn('Error:', error);\r\n });\r\n }\r\n\r\n var _findAddress = function (text) {\r\n if (text != null || text != '') {\r\n var findArr = [\r\n {\r\n url: config.findService\r\n },\r\n {\r\n key: config.key,\r\n text: text,\r\n countries: config.country // this can be GB (single) or GB, US, CA\r\n },\r\n function (data) {\r\n _findListOfAddress(data);\r\n }\r\n ];\r\n _makeRequest.apply(null, findArr);\r\n }\r\n };\r\n\r\n var _findListOfAddress = function (data) {\r\n if (data.Items.length) {\r\n var item = data.Items[0];\r\n if (item.Type === \"Postcode\" || item.Type === 'BuildingNumber' || item.Type === 'Street') {\r\n var findArr = [\r\n {\r\n url: config.findService\r\n },\r\n {\r\n key: config.key,\r\n text: item.Text,\r\n countries: config.country, // this can be GB (single) or GB, US, CA\r\n container: item.Id // id is recieved from previous ajax request\r\n },\r\n\r\n function createResultList(data) {\r\n var items = data.Items.map(function (suggestion) {\r\n return {\r\n label: suggestion.Text + \", \" + suggestion.Description,\r\n value: '',\r\n data: suggestion\r\n };\r\n });\r\n\r\n _createHtmlResultsContainer(items);\r\n }\r\n ];\r\n _makeRequest.apply(null, findArr);\r\n } else {\r\n var items = data.Items.map(function (suggestion) {\r\n return {\r\n label: suggestion.Text + \", \" + suggestion.Description,\r\n value: '',\r\n data: suggestion\r\n };\r\n });\r\n _createHtmlResultsContainer(items);\r\n }\r\n }\r\n };\r\n\r\n var _retrieveAddress = function (id) {\r\n if (id != null || id != '') {\r\n var retrieveArr = [\r\n {\r\n url: config.receiveService\r\n },\r\n {\r\n key: config.key,\r\n id: id,\r\n field1format: config.customfield\r\n },\r\n function clearResults(data) {\r\n if (data.Items.length) {\r\n _clearResultsContainer();\r\n _removeEnterManualField();\r\n _showHiddenField();\r\n _populateAddress(data);\r\n }\r\n }\r\n ];\r\n _makeRequest.apply(null, retrieveArr);\r\n }\r\n };\r\n\r\n var _createHtmlResultsContainer = function (resultItems) {\r\n var resultsContainer = document.querySelector(selectors.resultsContainer);\r\n if (resultItems.length) {\r\n resultsContainer.innerHTML = `