{ "version": 3, "sources": ["src/js/helpers/enabled.js", "src/js/helpers/isset.js", "src/js/patterns/sticky-header.js", "src/js/patterns/video.js", "src/js/patterns/site-search.js", "src/js/patterns/toast.js", "src/js/patterns/content-search.js", "src/js/patterns/inline-search.js", "src/js/patterns/field-counter.js", "node_modules/embla-carousel/src/components/utils.ts", "node_modules/embla-carousel/src/components/Alignment.ts", "node_modules/embla-carousel/src/components/EventStore.ts", "node_modules/embla-carousel/src/components/Animations.ts", "node_modules/embla-carousel/src/components/Axis.ts", "node_modules/embla-carousel/src/components/Limit.ts", "node_modules/embla-carousel/src/components/Counter.ts", "node_modules/embla-carousel/src/components/DragHandler.ts", "node_modules/embla-carousel/src/components/DragTracker.ts", "node_modules/embla-carousel/src/components/NodeRects.ts", "node_modules/embla-carousel/src/components/PercentOfView.ts", "node_modules/embla-carousel/src/components/ResizeHandler.ts", "node_modules/embla-carousel/src/components/ScrollBody.ts", "node_modules/embla-carousel/src/components/ScrollBounds.ts", "node_modules/embla-carousel/src/components/ScrollContain.ts", "node_modules/embla-carousel/src/components/ScrollLimit.ts", "node_modules/embla-carousel/src/components/ScrollLooper.ts", "node_modules/embla-carousel/src/components/ScrollProgress.ts", "node_modules/embla-carousel/src/components/ScrollSnaps.ts", "node_modules/embla-carousel/src/components/SlideRegistry.ts", "node_modules/embla-carousel/src/components/ScrollTarget.ts", "node_modules/embla-carousel/src/components/ScrollTo.ts", "node_modules/embla-carousel/src/components/SlideFocus.ts", "node_modules/embla-carousel/src/components/Vector1d.ts", "node_modules/embla-carousel/src/components/Translate.ts", "node_modules/embla-carousel/src/components/SlideLooper.ts", "node_modules/embla-carousel/src/components/SlidesHandler.ts", "node_modules/embla-carousel/src/components/SlidesInView.ts", "node_modules/embla-carousel/src/components/SlideSizes.ts", "node_modules/embla-carousel/src/components/SlidesToScroll.ts", "node_modules/embla-carousel/src/components/Engine.ts", "node_modules/embla-carousel/src/components/EventHandler.ts", "node_modules/embla-carousel/src/components/Options.ts", "node_modules/embla-carousel/src/components/OptionsHandler.ts", "node_modules/embla-carousel/src/components/PluginsHandler.ts", "node_modules/embla-carousel/src/components/EmblaCarousel.ts", "src/js/patterns/embla-carousel-nav.js", "node_modules/embla-carousel-class-names/src/components/Options.ts", "node_modules/embla-carousel-class-names/src/components/utils.ts", "node_modules/embla-carousel-class-names/src/components/ClassNames.ts", "src/js/patterns/depot-finder.js", "src/js/patterns/enquiry-link.js", "node_modules/embla-carousel-autoplay/src/components/Options.ts", "node_modules/embla-carousel-autoplay/src/components/Autoplay.ts", "src/js/patterns/embla-tween-opacity.js", "src/js/patterns/embla-thumbs-nav.js", "src/js/patterns/embla-carousel-init.js", "src/js/patterns/add-to-basket.js", "node_modules/f11y/umd/f11y.es.js", "node_modules/arrive/src/arrive.js", "src/js/app.js", "src/js/helpers/check-sticky.js"], "sourcesContent": ["/**\r\n * Adds body class to check if JS is enabled\r\n * @returns {Boolean}\r\n */\r\nfunction isJavascriptEnabled(){\r\n document.body.classList.add('js-enabled');\r\n return true;\r\n}\r\n\r\nexports.isJavascriptEnabled = isJavascriptEnabled;", "/**\r\n * Checks if a node/element exists\r\n * @param {HTMLElement|Element} node - The node/element to check\r\n * @returns {Boolean}\r\n */\r\nfunction isSet(node){\r\n if (typeof(node) != 'undefined' && node != null) {\r\n return true;\r\n }else{\r\n return false;\r\n }\r\n}\r\n\r\n\r\nexports.isSet = isSet;", "class Sticky {\r\n constructor (domNode) {\r\n this.documentElm = document.documentElement;\r\n this.window = window;\r\n this.prevScroll = this.window.scrollY || this.documentElm.scrollTop;\r\n this.currentScroll;\r\n this.headerHeight;\r\n this.direction = 0;\r\n this.prevDirection = 0;\r\n this.stickyHeader = domNode\r\n this.stickyOffset = domNode.offsetTop;\r\n this.header\r\n\r\n this.checkOffset = this.checkOffset.bind(this);\r\n window.addEventListener(\r\n 'scroll', \r\n this.checkOffset\r\n );\r\n\r\n this.checkScroll = this.checkScroll.bind(this)\r\n window.addEventListener(\r\n 'scroll', \r\n this.checkScroll\r\n );\r\n\r\n this.setMargin = this.setMargin.bind(this)\r\n document.addEventListener(\r\n 'DOMContentLoaded', \r\n this.setMargin\r\n );\r\n window.addEventListener(\r\n 'resize', \r\n this.setMargin\r\n );\r\n }\r\n\r\n checkOffset() {\r\n const headerElm = this.stickyHeader;\r\n const stickyOffset = this.stickyOffset;\r\n const pageOffset = window.scrollY;\r\n\r\n if (pageOffset > stickyOffset) {\r\n headerElm.classList.add(\"sticky\");\r\n } else {\r\n headerElm.classList.remove(\"sticky\");\r\n }\r\n }\r\n\r\n toggleHeader(direction, currentScroll) {\r\n const headerElm = this.stickyHeader;\r\n\r\n if (direction === 2 && currentScroll > this.headerHeight) { \r\n headerElm.classList.add('hide');\r\n this.prevDirection = direction;\r\n }\r\n else if (direction === 1) {\r\n headerElm.classList.remove('hide');\r\n this.prevDirection = direction;\r\n }\r\n }\r\n\r\n checkScroll() {\r\n //Find the direction of scroll: 0 = initial, 1 = up, 2 = down\r\n let currentScroll = this.window.scrollY || this.documentElm.scrollTop;\r\n let direction = this.direction;\r\n let prevScroll = this.prevScroll;\r\n let prevDirection = this.prevDirection;\r\n\r\n if (currentScroll > prevScroll) { //Scrolling Up\r\n direction = 2;\r\n }\r\n else if (currentScroll < prevScroll) { //Scrolling Down\r\n direction = 1;\r\n }\r\n\r\n if (direction !== prevDirection) {\r\n this.toggleHeader(direction, currentScroll);\r\n }\r\n\r\n this.prevScroll = currentScroll;\r\n }\r\n\r\n setMargin() {\r\n let headerHeight = this.stickyHeader.offsetHeight;\r\n this.documentElm.style.marginTop = headerHeight + 'px';\r\n this.documentElm.style.setProperty('--masthead-height', headerHeight + 'px');\r\n this.headerHeight = headerHeight;\r\n }\r\n}\r\n \r\nexports.Sticky = Sticky", "import { isSet } from \"../helpers/isset\";\r\n\r\n/**\r\n * Description: Initialise the vimeo player functionalities\r\n * \r\n * @class Search\r\n * @typedef {Search}\r\n */\r\n\r\nclass Video {\r\n constructor(domNode) {\r\n this.domNode = domNode;\r\n\r\n window.addEventListener(\r\n 'load',\r\n this.init.bind(this),\r\n true\r\n );\r\n }\r\n\r\n init(){\r\n this.domNode.classList.add('has-vimeo-video');\r\n const videoElm = document.createElement('div');\r\n videoElm.classList.add('vimeo-video__player-container');\r\n\r\n this.videoElm = videoElm;\r\n \r\n this.vimeoURL = this.domNode.getAttribute('data-vimeo-url');\r\n \r\n if(!isSet(this.vimeoURL)){\r\n console.warn(\"No Vimeo URL found on \" + this.videoElm);\r\n return;\r\n }\r\n\r\n this.posterElm = this.domNode.querySelector(\"img\");\r\n this.posterElm.classList.add('vimeo-video__poster');\r\n\r\n const actionElm = document.createElement('button');\r\n const actionIcon = document.createElement('i');\r\n actionElm.classList.add('vimeo-video__action');\r\n actionIcon.classList.add('sa-icon--play');\r\n actionElm.append(actionIcon);\r\n\r\n actionElm.addEventListener(\r\n 'click',\r\n this.loadResponse.bind(this)\r\n );\r\n\r\n this.actionElm = actionElm;\r\n\r\n this.domNode.append(this.videoElm);\r\n this.domNode.append(this.actionElm);\r\n\r\n this.requestURL = \"https://vimeo.com/api/oembed.json?url=\" + this.vimeoURL;\r\n\r\n\r\n }\r\n\r\n async loadResponse(){\r\n try {\r\n const vimeoResponse = await fetch(this.requestURL);\r\n const vimeoJSON = await vimeoResponse.json();\r\n const vimeoHTML = vimeoJSON.html;\r\n\r\n this.videoElm.insertAdjacentHTML('beforeend' , vimeoHTML);\r\n this.actionElm.remove();\r\n if(isSet(this.posterElm)){\r\n this.posterElm.remove();\r\n }\r\n \r\n } catch (err) {\r\n console.error(err);\r\n }\r\n }\r\n}\r\n\r\nexports.Video = Video", "/**\r\n * Description: Initialise the live search for the header Site Search\r\n * \r\n * @class SiteSearch\r\n * @typedef {SiteSearch}\r\n */\r\n\r\nclass SiteSearch {\r\n constructor(domNode) {\r\n this.domNode = domNode;\r\n this.inputNode = domNode.querySelector('input[type=\"search\"]');\r\n this.resultContainer = this.domNode.querySelector('.search-results');\r\n this.innerContainer = '';\r\n this.previousSearchString = '';\r\n this.timeout = 0;\r\n this.jsonURL = '';\r\n\r\n this.inputNode.addEventListener(\r\n 'keyup',\r\n this.onInputKeyup.bind(this)\r\n );\r\n\r\n window.addEventListener(\r\n 'load',\r\n this.init.bind(this),\r\n true\r\n );\r\n }\r\n\r\n /**\r\n * Creates and builds any required initial markup for the live search to work\r\n */\r\n init() {\r\n this.jsonURL = this.domNode.getAttribute('data-fetch-url');\r\n const innerContainer = document.createElement('div');\r\n innerContainer.classList.add('inner-container');\r\n const innerContainerElm = this.resultContainer.appendChild(innerContainer);\r\n this.innerContainer = innerContainerElm;\r\n }\r\n\r\n\r\n /**\r\n * Checks if the passed string is different when compared with the previously stored search string this.previousSearchString\r\n * @param {String} value The search query string that we want to check that has changed\r\n */\r\n hasChanged(value){\r\n if(value == this.previousSearchString){\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n\r\n /**\r\n * Handles all keyup keyboard events\r\n * @param {String} string The string that is to be escaped\r\n */\r\n escape(string) {\r\n return string\r\n .replace(/&/g, \"&\")\r\n .replace(//g, \">\")\r\n .replace(/\"/g, \""\")\r\n .replace(/'/g, \"'\");\r\n }\r\n\r\n\r\n /**\r\n * Builds output messages\r\n * @param {String} value The value for the message content\r\n * @param {String} customClass Custom class to be added to the message element\r\n */\r\n buildMessage(value, customClass){\r\n const fragment = new DocumentFragment();\r\n const messageElm = document.createElement('div');\r\n messageElm.classList.add('sa-message');\r\n if(customClass){\r\n messageElm.classList.add(customClass);\r\n }\r\n const message = document.createElement('span');\r\n message.textContent = value;\r\n messageElm.append(message);\r\n fragment.append(messageElm);\r\n return fragment;\r\n }\r\n\r\n\r\n /**\r\n * Builds Search Result\r\n * @param {String} title The title content for the search result\r\n * @param {String} href The link url link for the search result\r\n */\r\n buildSearchResult(title, href){\r\n const listItem = document.createElement('li');\r\n listItem.classList.add('result');\r\n const link = document.createElement('a');\r\n link.href = href;\r\n link.target = '_blank';\r\n const para = document.createElement('p');\r\n para.textContent = title;\r\n const icon = document.createElement('i');\r\n icon.classList.add('sa-icon--arrow-right');\r\n link.append(para);\r\n link.append(icon);\r\n listItem.append(link);\r\n return listItem;\r\n }\r\n\r\n \r\n /**\r\n * Handles all keyup keyboard events\r\n * @param {Object} event The event that triggered this method\r\n */\r\n onInputKeyup(event) {\r\n this.innerContainer.classList.add('is-active');\r\n\r\n if(!this.hasChanged(this.inputNode.value)){\r\n return;\r\n }\r\n\r\n this.previousSearchString = this.inputNode.value;\r\n\r\n if(this.inputNode.textLength == 0){\r\n this.innerContainer.innerHTML = '';\r\n this.innerContainer.classList.remove('is-active');\r\n return;\r\n }\r\n\r\n if(this.inputNode.textLength <= 3){\r\n this.innerContainer.innerHTML = '';\r\n this.innerContainer.append(\r\n this.buildMessage('Please Keep Typing...', 'sa-message--info')\r\n );\r\n return;\r\n }\r\n\r\n clearTimeout(this.timeout);\r\n this.innerContainer.innerHTML = '';\r\n this.innerContainer.append(\r\n this.buildMessage('Searching...', 'sa-message--info')\r\n );\r\n this.timeout = setTimeout(\r\n this.fetchSearchResults.bind(this),\r\n 700\r\n );\r\n }\r\n\r\n\r\n /**\r\n * Fetches the results from JSON query\r\n */\r\n async fetchSearchResults(){\r\n const cleanValue = this.escape(this.inputNode.value);\r\n const searchURL = this.jsonURL + cleanValue;\r\n const innerContainer = this.innerContainer;\r\n\r\n let responseJSON;\r\n\r\n try {\r\n const response = await fetch(searchURL);\r\n\r\n if (!response.ok) {\r\n this.innerContainer.innerHTML = '';\r\n innerContainer.append(\r\n this.buildMessage('Whoops something went wrong, please try again.', 'sa-message--error')\r\n );\r\n throw new Error(`${response.status} ${response.statusText}`);\r\n }\r\n\r\n responseJSON = await response.json();\r\n \r\n } catch (error) {\r\n this.innerContainer.innerHTML = '';\r\n innerContainer.append(\r\n this.buildMessage('Whoops something went wrong, please try again.', 'sa-message--error')\r\n );\r\n\r\n if (error instanceof SyntaxError) {\r\n console.warn('There was a SyntaxError when fetching the JSON', error);\r\n } else {\r\n console.warn('There was an error', error);\r\n }\r\n }\r\n\r\n if (responseJSON) {\r\n const resultsArr = responseJSON.list;\r\n innerContainer.innerHTML = '';\r\n\r\n if(!resultsArr.length){\r\n innerContainer.append(\r\n this.buildMessage('No Results Found.', 'sa-message--info')\r\n );\r\n return;\r\n }\r\n \r\n const title = `Best Matches`;\r\n const list = document.createElement('ul');\r\n\r\n for (let i = 0; i < resultsArr.length; i++) {\r\n if(i <= 2){\r\n const result = resultsArr[i];\r\n list.appendChild( this.buildSearchResult(result.title, result.url) );\r\n }\r\n }\r\n\r\n innerContainer.insertAdjacentHTML('afterbegin', title);\r\n innerContainer.append(list);\r\n\r\n const cta = `\r\n \r\n View All Search Results (` + resultsArr.length + `)\r\n \r\n \r\n `;\r\n\r\n innerContainer.insertAdjacentHTML(\r\n 'beforeend',\r\n cta\r\n );\r\n }\r\n }\r\n}\r\n\r\nexports.SiteSearch = SiteSearch;", "class Toast {\r\n /**\r\n * @param {HTMLElement | Element} domNode \r\n * @param {HTMLElement | Element} toastTemplate \r\n * @param {Object} opts \r\n */\r\n constructor(domNode, toastTemplate, opts) {\r\n\r\n this.f11ySettings = window.f11y.settings;\r\n \r\n /** @type {ToastDefault} */\r\n const DEFAULTS = {\r\n onOpen: () => { },\r\n onDismiss: () => { },\r\n onClear: () => { },\r\n openClass: this.f11ySettings.openClass,\r\n closeToastAttribute: 'f11y-toast-close',\r\n templateElementAttribute: 'f11y-toast-message',\r\n swipeTracking: false,\r\n swipeDirection: 'down',\r\n duration: -1,\r\n awaitCloseTransition: false,\r\n awaitOpenTransition: false \r\n }\r\n\r\n /** @type {ToastDefault} */\r\n this.options = Object.assign(DEFAULTS, opts);\r\n\r\n /** @type {Element | HTMLElement} */\r\n this.domNode = domNode;\r\n\r\n /** @type {Element | HTMLElement} */\r\n this.toastTemplate = toastTemplate;\r\n\r\n this.init();\r\n }\r\n\r\n /**\r\n * Initialises the class component\r\n */\r\n init() {\r\n this.timer = 0;\r\n this.activeToasts = [];\r\n this.onPointerMoveBound = this.onPointerMove.bind(this);\r\n this.swipeThreshold = 50;\r\n window.addEventListener('mousedown', this.onBackgroundMousedown.bind(this), true);\r\n this.domNode.addEventListener( 'focusin', this.#onFocusIn.bind(this) );\r\n this.domNode.addEventListener( 'focusout', this.#onFocusOut.bind(this) );\r\n //this.domNode.addEventListener('keydown', this.onKeydown.bind(this) );\r\n\r\n this.domNode.classList.add(this.f11ySettings.initialisedClass);\r\n }\r\n\r\n refresh() {\r\n this.init();\r\n }\r\n\r\n /**\r\n * Opens the toast\r\n * @param {string} templateString String that populates the templatable element templateElementAttribute\r\n * @param {Element | HTMLElement | null} customToastTemplate Custom template element to be used as a custom template for this particular toast\r\n */\r\n openToast(templateString, customToastTemplate = null) {\r\n let toastTemplate = this.toastTemplate;\r\n if(customToastTemplate != null) toastTemplate = customToastTemplate;\r\n const builtToast = this.#createToast(toastTemplate, templateString);\r\n const toast = this.domNode.insertAdjacentElement('afterbegin', builtToast.firstChild);\r\n const animatingClass = this.f11ySettings.animatingClass;\r\n const animatingOpenClass = this.f11ySettings.animatingOpenClass;\r\n\r\n toast.addEventListener( 'mouseenter', this.#onHoverIn.bind(this) );\r\n toast.addEventListener( 'mouseleave', this.#onHoverOut.bind(this) );\r\n\r\n toast.addEventListener('click', (event) => {\r\n const closeButton = event.target.closest('[f11y-toast-close]');\r\n if (closeButton) {\r\n this.dismissToast(toast.id);\r\n }\r\n });\r\n\r\n toast.style.setProperty('--f11y-toast-height', toast.offsetHeight);\r\n toast.style.setProperty('--f11y-toast-before', this.activeToasts.length);\r\n\r\n if(this.options.swipeTracking){\r\n toast.addEventListener( 'pointerdown', this.onPointerDown.bind(this) );\r\n toast.addEventListener( 'pointerup', this.onPointerUp.bind(this) );\r\n }\r\n\r\n const openClass = this.options.openClass;\r\n if (this.options.awaitOpenTransition) {\r\n toast.addEventListener('transitionend', handler);\r\n toast.classList.remove('will-animate');\r\n\r\n function handler() {\r\n toast.removeEventListener( 'transitionend', handler );\r\n toast.classList.remove(animatingClass, animatingOpenClass);\r\n toast.classList.add(openClass);\r\n }\r\n }\r\n\r\n const toastObj = { id: toast.id, toastElm: toast, height:toast.offsetHeight};\r\n this.activeToasts.push(toastObj);\r\n this.updateToasts();\r\n this.domNode.classList.add('has-toasts');\r\n\r\n this.options.onOpen(toast, this);\r\n\r\n const duration = this.options.duration;\r\n\r\n if(duration === -1) return;\r\n\r\n toastObj.timer = setTimeout(() => {\r\n this.dismissToast(toast.id);\r\n }, duration);\r\n\r\n toast.addEventListener('mouseenter', () => {\r\n clearTimeout(toastObj.timer);\r\n });\r\n\r\n toast.addEventListener('mouseleave', () => {\r\n toastObj.timer = setTimeout(() => {\r\n this.dismissToast(toast.id);\r\n }, duration);\r\n });\r\n }\r\n\r\n /**\r\n * Dismisses a specified toast\r\n * @param {string} id The id attribute of the toast to dismiss\r\n */\r\n dismissToast(id) {\r\n const toast = this.domNode.querySelector('[f11y-toast-id=\"' + id + '\"]');\r\n this.activeToasts = this.activeToasts.filter(obj => obj.id !== id);\r\n const activeToasts = this.activeToasts;\r\n this.updateToasts();\r\n const domNode = this.domNode;\r\n const openClass = this.options.openClass;\r\n const animatingClass = this.f11ySettings.animatingClass;\r\n const animatingCloseClass = this.f11ySettings.animatingCloseClass;\r\n\r\n toast.remove();\r\n\r\n if(!activeToasts.length){\r\n domNode.classList.remove('.is-hovered', 'has-toasts');\r\n }\r\n\r\n this.options.onDismiss(toast, this);\r\n }\r\n\r\n /**\r\n * Builds the toast dom element form the passed template element\r\n * @param {Element | HTMLElement} template Template element to build the toast from\r\n * @param {string} templateString String that populates the templatable element templateElementAttribute\r\n * @returns \r\n */\r\n #createToast(template, templateString) {\r\n const toastInstance = template.content.cloneNode(true);\r\n const toast = new DocumentFragment();\r\n const toastContainer = document.createElement('div');\r\n const array = new Uint32Array(10);\r\n const toastId = 'toast-' + crypto.getRandomValues(array)[0];\r\n const animatingClass = this.f11ySettings.animatingClass;\r\n const animatingOpenClass = this.f11ySettings.animatingOpenClass;\r\n\r\n if(templateString){\r\n const templatableElm = toastInstance.querySelector('[f11y-toast-message]');\r\n templatableElm.textContent = templateString;\r\n }\r\n\r\n if (template.hasAttributes()) {\r\n for (const attr of template.attributes) {\r\n if (attr.name !== 'id') {\r\n toastContainer.setAttribute(attr.name, attr.value);\r\n }\r\n }\r\n }\r\n\r\n toastContainer.setAttribute(\"f11y-toast-id\", toastId);\r\n toastContainer.id = toastId;\r\n if(this.options.swipeTracking === true) toastContainer.classList.add('has-swiping');\r\n\r\n if (this.options.awaitOpenTransition) {\r\n toastContainer.classList.add('will-animate', animatingClass, animatingOpenClass);\r\n }else{\r\n toastContainer.classList.add(this.options.openClass);\r\n }\r\n\r\n toastContainer.append(toastInstance);\r\n toast.append(toastContainer);\r\n return toast;\r\n }\r\n\r\n /**\r\n * Clears all toasts\r\n */\r\n clearToasts(){\r\n if(!this.activeToasts.length) return;\r\n this.activeToasts.slice().forEach(toast => this.dismissToast(toast.id));\r\n\r\n this.options.onClear(this);\r\n }\r\n\r\n /**\r\n * Updates toast properties and css variable values\r\n */\r\n updateToasts(){\r\n let offset = 0;\r\n for(let i = 0; i < this.activeToasts.length; i++){\r\n const toast = this.activeToasts[i];\r\n toast.toastElm.style.setProperty('--f11y-toast-index', i);\r\n toast.toastElm.style.setProperty('--f11y-toast-before', this.activeToasts.length - i - 1);\r\n\r\n this.domNode.style.setProperty('--f11y-toast-first', toast.height);\r\n }\r\n this.activeToasts.slice().reverse().forEach(function(toast) { // dumb shit\r\n toast.toastElm.style.setProperty('--f11y-toast-offset', offset);\r\n offset = offset + toast.height;\r\n });\r\n }\r\n\r\n /**\r\n * Method called when pointer down on a toast\r\n * @param {Event} e The event object that triggered the method\r\n */\r\n onPointerDown(e){\r\n this.dragStartTime = new Date();\r\n e.currentTarget.setPointerCapture(e.pointerId);\r\n if(e.target.tagName === 'BUTTON') return;\r\n this.dragStartRef = { x: e.clientX, y: e.clientY};\r\n e.currentTarget.addEventListener('pointermove', this.onPointerMoveBound);\r\n }\r\n\r\n /**\r\n * Method called when pointer up on a toast\r\n * @param {Event} e The event object that triggered the method\r\n */\r\n onPointerUp(e){\r\n const dir = this.options.swipeDirection;\r\n const prop = dir === 'left' || dir === 'right' ? '--f11y-toast-swipe-x' : '--f11y-toast-swipe-y';\r\n const swipeAmount = Number(e.currentTarget.style.getPropertyValue(prop) || 0);\r\n const timeTaken = new Date().getTime() - this.dragStartTime.getTime();\r\n const velocity = Math.abs(swipeAmount) / timeTaken;\r\n if(Math.abs(swipeAmount) >= this.swipeThreshold || velocity > 0.25){\r\n this.dismissToast(e.currentTarget.id);\r\n return;\r\n }\r\n e.currentTarget.removeEventListener('pointermove', this.onPointerMoveBound);\r\n e.currentTarget.style.setProperty('--f11y-toast-swipe-y', 0); //up-down\r\n e.currentTarget.style.setProperty('--f11y-toast-swipe-x', 0); //left-right\r\n e.currentTarget.removeAttribute('f11y-toast-swiping');\r\n }\r\n\r\n /**\r\n * Method called when pointer move happens on toast\r\n * @param {Event} e The event object that triggered the method\r\n */\r\n onPointerMove(e){\r\n e.currentTarget.setAttribute('f11y-toast-swiping', true);\r\n const yPos = e.clientY - this.dragStartRef.y;\r\n const xPos = e.clientX - this.dragStartRef.x;\r\n\r\n const isAllowedToSwipe = this.#checkSwiping(e, yPos, xPos);\r\n\r\n if (!isAllowedToSwipe) {\r\n e.currentTarget.style.setProperty('--f11y-toast-swipe-y', 0);\r\n e.currentTarget.style.setProperty('--f11y-toast-swipe-x', 0);\r\n }\r\n }\r\n\r\n /**\r\n * Compares the swiping direction with the swipeDirection option to decide if swiping is allowed\r\n * @param {Event} e The event object that triggered the method\r\n * @param {number} yPos \r\n * @param {number} xPos \r\n * @returns {boolean} Is swipipng allowed?\r\n */\r\n #checkSwiping(e, yPos, xPos){\r\n const dir = this.options.swipeDirection;\r\n\r\n let clamp, threshold;\r\n\r\n switch(dir){\r\n case 'up':\r\n clamp = Math.min(0, yPos);\r\n threshold = e.pointerType === 'touch' ? -10 : -2;\r\n if(clamp < threshold){\r\n e.currentTarget.style.setProperty('--f11y-toast-swipe-y', yPos);\r\n return true;\r\n }\r\n break;\r\n case 'down':\r\n clamp = Math.max(0, yPos);\r\n threshold = e.pointerType === 'touch' ? 10 : 2;\r\n if(clamp > threshold){\r\n e.currentTarget.style.setProperty('--f11y-toast-swipe-y', yPos);\r\n return true;\r\n }\r\n break;\r\n case 'left':\r\n clamp = Math.min(0, xPos);\r\n threshold = e.pointerType === 'touch' ? -10 : -2;\r\n if(clamp < threshold){\r\n e.currentTarget.style.setProperty('--f11y-toast-swipe-x', xPos);\r\n return true;\r\n }\r\n break;\r\n case 'right':\r\n default:\r\n clamp = Math.max(0, xPos);\r\n threshold = e.pointerType === 'touch' ? 10 : 2;\r\n if(clamp > threshold){\r\n e.currentTarget.style.setProperty('--f11y-toast-swipe-x', xPos);\r\n return true;\r\n }\r\n break;\r\n }\r\n }\r\n\r\n /**\r\n * Called when hover occurs on toast container domNode\r\n */\r\n #onHoverIn() {\r\n let timer = this.timer;\r\n clearTimeout(timer);\r\n this.domNode.classList.add('is-hovered');\r\n this.domNode.classList.add('has-attention');\r\n }\r\n\r\n /**\r\n * Called when hover leaves toast container domNode\r\n */\r\n #onHoverOut() {\r\n const domNode = this.domNode;\r\n this.timer = setTimeout(function(){\r\n domNode.classList.remove('is-hovered');\r\n domNode.classList.remove('has-attention');\r\n }, 750);\r\n }\r\n\r\n /**\r\n * Called when hover occurs on toast container domNode\r\n */\r\n #onFocusIn() {\r\n let timer = this.timer;\r\n clearTimeout(timer);\r\n this.domNode.classList.add('has-focus');\r\n this.domNode.classList.add('has-attention');\r\n }\r\n \r\n /**\r\n * Called when hover leaves toast container domNode\r\n */\r\n #onFocusOut() {\r\n const domNode = this.domNode;\r\n this.timer = setTimeout(function(){\r\n domNode.classList.remove('has-focus');\r\n domNode.classList.remove('has-attention');\r\n }, 750);\r\n }\r\n\r\n /**\r\n * Handles click events that are outside of the toast domNode remit\r\n * @param {Object} e The event that triggered this method\r\n */\r\n onBackgroundMousedown(e) {\r\n if (!this.domNode.contains(e.target)) {\r\n this.domNode.classList.remove('is-hovered');\r\n this.domNode.classList.remove('has-focus');\r\n this.domNode.classList.remove('has-attention');\r\n }\r\n }\r\n}\r\n\r\nexports.Toast = Toast", "\r\nclass ContentSearch {\r\n constructor(domNode){\r\n this.domNode = domNode;\r\n this.searchInput = this.domNode.querySelector('.search__input');\r\n this.searchSubmit = this.domNode.querySelector('.search__submit');\r\n this.searchClear = this.domNode.querySelector('.search__clear');\r\n this.resultsContainer = this.domNode.querySelector('.results-container');\r\n this.fetchUrl = this.domNode.getAttribute('data-fetch-url');\r\n this.items = [];\r\n\r\n this.loadedEvent = new Event('loaded');\r\n\r\n this.fetchItems(this.fetchUrl);\r\n\r\n this.searchInput.addEventListener(\r\n 'keyup',\r\n this.handleSearchInputKeyup.bind(this)\r\n );\r\n\r\n this.searchSubmit.addEventListener(\r\n 'click',\r\n this.handleSearchSubmitClick.bind(this)\r\n );\r\n\r\n this.searchClear.addEventListener(\r\n 'click',\r\n this.handleSearchClearClick.bind(this)\r\n );\r\n }\r\n\r\n async fetchItems(url){\r\n try {\r\n const res = await fetch(url);\r\n this.items = await res.json();\r\n this.renderItems(this.items);\r\n } catch (err) {\r\n console.error(err);\r\n }\r\n }\r\n\r\n handleSearchSubmitClick(e){\r\n\r\n }\r\n\r\n handleSearchInputKeyup(e){\r\n const searchString = e.target.value.toLowerCase();\r\n let contentType;\r\n\r\n if (e.key === 'Enter') {\r\n this.resultsContainer.scrollIntoView({\r\n behavior: \"auto\"\r\n });\r\n return;\r\n }\r\n\r\n if (e.target.value) {\r\n this.searchClear.classList.remove('is-hidden');\r\n } else {\r\n this.searchClear.classList.add('is-hidden');\r\n }\r\n\r\n const filteredList = this.items.filter((item) => {\r\n let searchableContent = '';\r\n contentType = item.content_type;\r\n searchableContent += item.title.toLowerCase();\r\n searchableContent += ' ';\r\n\r\n if(item.children){\r\n for (var i = 0, l = item.children.length; i < l; i++) {\r\n searchableContent += item.children[i].title.toLowerCase();\r\n searchableContent += ' ';\r\n }\r\n }\r\n\r\n return (\r\n searchableContent.includes(searchString)\r\n );\r\n });\r\n\r\n setTimeout(() => {\r\n if (!this.resultsContainer.hasChildNodes()) {\r\n const noResults = document.createElement(\"div\");\r\n const noResultText = document.createElement(\"h4\");\r\n\r\n noResults.classList.add('no-results');\r\n \r\n if(contentType === \"depot\"){\r\n noResults.classList.add('embla__slide');\r\n noResultText.classList.add(\"sa-200\", \"x-large-body\");\r\n }\r\n\r\n noResultText.textContent = 'Sorry, no results match your search...';\r\n \r\n noResults.appendChild(noResultText);\r\n this.resultsContainer.appendChild(noResults);\r\n }\r\n }, 100);\r\n\r\n this.renderItems(filteredList);\r\n }\r\n\r\n handleSearchClearClick(e){\r\n this.searchInput.value = '';\r\n this.renderItems(this.items);\r\n this.searchClear.classList.add('is-hidden');\r\n }\r\n\r\n renderItems(json){\r\n const htmlString = json.map(\r\n (item) => {\r\n let html = ``;\r\n if(item.content_type == 'depot'){\r\n html = `\r\n
\r\n `;\r\n }\r\n if(item.content_type == 'contact'){\r\n html = `\r\n