@w3f/utm-element
Version:
Web components and functions for UTM parameters data manipulation.
177 lines (159 loc) • 4.82 kB
JavaScript
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
}