UNPKG

@w3f/utm-element

Version:

Web components and functions for UTM parameters data manipulation.

177 lines (159 loc) 4.82 kB
const DNT = window ? (window.doNotTrack || navigator.doNotTrack) : false /* Custom Elements */ /* manages URL query params starting with UTM or === REF */ class UtmElement extends HTMLElement { get localStorageKey() { return this.getAttribute('local-storage-key') || this.localName } set localStorageKey(str) { this.setAttribute('local-storage-key', str) } connectedCallback() { if (DNT) { console.info(this.localName, 'Not storing utm params when doNotTrack is enabled') return this.remove() } const oldUtmFromStorage = this.getUtm() const newUtmFromUrl = this.getUrlUtmParams(window.location) if (newUtmFromUrl) { this.utm = newUtmFromUrl this.saveUtm(this.utm) } else if (oldUtmFromStorage) { this.utm = oldUtmFromStorage } } render() { if (!this.utm || !this.utm.length) return const params = this.getUtm() } /* accepts a URL of type `window.location` * returns a list of UTM/REF data objects with `key` & `value` keys */ getUrlUtmParams(url) { const urlData = new URL(url) const utmParams = [] const paramsSearch = new URLSearchParams(urlData.search); for (const [key, value] of paramsSearch.entries()) { if (key.startsWith('utm') || key === 'ref') { utmParams.push({key, value}) } } return utmParams } /* save a list of UTM objects to the session storage */ saveUtm(utmList) { sessionStorage.setItem(this.localStorageKey, JSON.stringify(utmList)) } /* get the UTM data */ getUtm() { const utmFromStorage = JSON.parse(sessionStorage.getItem(this.localStorageKey)) return utmFromStorage } /* take a URL string (a.href) * return the same URL, with utm query params */ setUtmOnUrl(url) { if (!url) return const urlData = new URL(url) const paramsSearch = new URLSearchParams(urlData.search); if (this.utm && this.utm.length) { this.utm.forEach(utm => { paramsSearch.set(utm.key, utm.value) }) return `${urlData.origin}${urlData.pathname}?${paramsSearch.toString()}${urlData.hash}` } else { return url } } } /* Extend a DOM anchor element: - use with: `customElements.define('utm-link', UtmLink, {extends: 'a'})` - `<a is="utm-element" href="https://...">test</a>` > Does not work as `<utm-element/>`, needs to be anchor element > Needs to be defined, after utm-element has been defined & injected in DOM */ class UtmLink extends HTMLAnchorElement { connectedCallback() { const href = this.getAttribute('href') if (href) { try { this.href = this.setUtmOnUrl(href) } catch(error) { /* if the URL returns an error, try with a temporary URL, to just add the UTM params, then remove it */ const newUrl = this.setUtmOnUrl(window.location.href + href) this.href = newUrl.split(window.location.href)[1] } } } setUtmOnUrl(href) { const $utmElement = document.querySelector('utm-element') if ($utmElement) { return $utmElement.setUtmOnUrl(href) } else { return href } } } /* Convenient methods */ /* define the utm-element, so it can be used in the DOM (append to <body>) */ const defineUtmElement = (elName = 'utm-element') => { if (!customElements.get(elName)) { customElements.define(elName, UtmElement) } } /* append the utm-element in the dom */ const insertUtmElement = ($target = 'body', elName = 'utm-element') => { const $utmElement = document.createElement(elName) $utmElement.setAttribute('hidden', true) document.querySelector($target).append($utmElement) } /* define the utm-link element, should be always after utm-element defined+injected, used only as: `<a is="utm-link" href=""></a>` */ const defineLinkElement = (elName = 'utm-link') => { if (!customElements.get(elName)) { customElements.define(elName, UtmLink, {extends: 'a'}) } } /* a trick to put the utm on a hubspot form */ const hubspotOnFormReady = (event) => { if (DNT) return {error: 'do-not-track requested'} const $form = event[0] const $utmElement = document.querySelector('utm-element') if (!$form || !$utmElement) { const error = 'Hubspot form, or <utm-element> missing' return { error, $form, $utmElement } } let utmList = $utmElement.getUtm() let utmInputs = utmList.map(utm => { const utmSelector = `input[type="hidden"][name="${utm.key}"]` const $utmInput = $form.querySelector(utmSelector) if ($utmInput) { $utmInput.value = utm.value return $utmInput } }) return { utmList, utmInputs, hubspotForm: $form } } export { UtmElement, UtmLink, defineUtmElement, insertUtmElement, defineLinkElement, hubspotOnFormReady }