| |
|
|
| import { config, scriptEl } from './config' |
| import { track } from './track' |
|
|
| export var DEFAULT_FILE_TYPES = [ |
| 'pdf', |
| 'xlsx', |
| 'docx', |
| 'txt', |
| 'rtf', |
| 'csv', |
| 'exe', |
| 'key', |
| 'pps', |
| 'ppt', |
| 'pptx', |
| '7z', |
| 'pkg', |
| 'rar', |
| 'gz', |
| 'zip', |
| 'avi', |
| 'mov', |
| 'mp4', |
| 'mpeg', |
| 'wmv', |
| 'midi', |
| 'mp3', |
| 'wav', |
| 'wma', |
| 'dmg' |
| ] |
|
|
| var MIDDLE_MOUSE_BUTTON = 1 |
| var PARENTS_TO_SEARCH_LIMIT = 3 |
| var fileTypesToTrack = DEFAULT_FILE_TYPES |
|
|
| function getLinkEl(link) { |
| while ( |
| link && |
| (typeof link.tagName === 'undefined' || !isLink(link) || !link.href) |
| ) { |
| link = link.parentNode |
| } |
| return link |
| } |
|
|
| function isLink(element) { |
| return element && element.tagName && element.tagName.toLowerCase() === 'a' |
| } |
|
|
| function shouldInterceptNavigation(event, link) { |
| |
| if (event.defaultPrevented) return false |
| var target = link.target |
| |
| if ( |
| target && |
| (typeof target !== 'string' || !target.match(/^_(self|parent|top)$/i)) |
| ) |
| return false |
| |
| if ( |
| event.ctrlKey || |
| event.metaKey || |
| event.shiftKey || |
| event.type !== 'click' |
| ) |
| return false |
|
|
| return true |
| } |
|
|
| function handleLinkClickEvent(event) { |
| if (event.type === 'auxclick' && event.button !== MIDDLE_MOUSE_BUTTON) { |
| return |
| } |
|
|
| var link = getLinkEl(event.target) |
| var hrefWithoutQuery = |
| link && typeof link.href === 'string' && link.href.split('?')[0] |
|
|
| if (COMPILE_TAGGED_EVENTS) { |
| if (isElementOrParentTagged(link, 0)) { |
| |
| |
| return |
| } |
| } |
|
|
| if (COMPILE_OUTBOUND_LINKS && (!COMPILE_CONFIG || config.outboundLinks)) { |
| if (isOutboundLink(link)) { |
| return sendLinkClickEvent(event, link, { |
| name: 'Outbound Link: Click', |
| props: { url: link.href } |
| }) |
| } |
| } |
|
|
| if (COMPILE_FILE_DOWNLOADS && (!COMPILE_CONFIG || config.fileDownloads)) { |
| if (isDownloadToTrack(hrefWithoutQuery)) { |
| return sendLinkClickEvent(event, link, { |
| name: 'File Download', |
| props: { url: hrefWithoutQuery } |
| }) |
| } |
| } |
| } |
|
|
| function sendLinkClickEvent(event, link, eventAttrs) { |
| |
| |
| var attrs |
| if (COMPILE_COMPAT) { |
| var followedLink = false |
| function followLink() { |
| if (!followedLink) { |
| followedLink = true |
| window.location = link.href |
| } |
| } |
|
|
| if (shouldInterceptNavigation(event, link)) { |
| attrs = { props: eventAttrs.props, callback: followLink } |
| if (COMPILE_REVENUE) { |
| attrs.revenue = eventAttrs.revenue |
| } |
| track(eventAttrs.name, attrs) |
| setTimeout(followLink, 5000) |
| event.preventDefault() |
| } else { |
| attrs = { props: eventAttrs.props } |
| if (COMPILE_REVENUE) { |
| attrs.revenue = eventAttrs.revenue |
| } |
| track(eventAttrs.name, attrs) |
| } |
| } else { |
| attrs = { props: eventAttrs.props } |
| if (COMPILE_REVENUE) { |
| attrs.revenue = eventAttrs.revenue |
| } |
| track(eventAttrs.name, attrs) |
| } |
| } |
|
|
| function isOutboundLink(link) { |
| return ( |
| link && |
| typeof link.href === 'string' && |
| link.host && |
| link.host !== location.host |
| ) |
| } |
|
|
| function isDownloadToTrack(url) { |
| if (!url) { |
| return false |
| } |
|
|
| var fileType = url.split('.').pop() |
| return fileTypesToTrack.some(function (fileTypeToTrack) { |
| return fileTypeToTrack === fileType |
| }) |
| } |
|
|
| function isTagged(element) { |
| var classList = element && element.classList |
| if (classList) { |
| for (var i = 0; i < classList.length; i++) { |
| if (classList.item(i).match(/plausible-event-name(=|--)(.+)/)) { |
| return true |
| } |
| } |
| } |
| return false |
| } |
|
|
| function isElementOrParentTagged(element, parentsChecked) { |
| if (!element || parentsChecked > PARENTS_TO_SEARCH_LIMIT) { |
| return false |
| } |
| if (isTagged(element)) { |
| return true |
| } |
| return isElementOrParentTagged(element.parentNode, parentsChecked + 1) |
| } |
|
|
| |
| |
| function getTaggedEventAttributes(htmlElement) { |
| var taggedElement = isTagged(htmlElement) |
| ? htmlElement |
| : htmlElement && htmlElement.parentNode |
| var eventAttrs = { name: null, props: {} } |
| if (COMPILE_REVENUE) { |
| eventAttrs.revenue = {} |
| } |
|
|
| var classList = taggedElement && taggedElement.classList |
| if (!classList) { |
| return eventAttrs |
| } |
|
|
| for (var i = 0; i < classList.length; i++) { |
| var className = classList.item(i) |
|
|
| var key |
| var value |
| var matchList = className.match(/plausible-event-(.+)(=|--)(.+)/) |
| if (matchList) { |
| key = matchList[1] |
| value = matchList[3].replace(/\+/g, ' ') |
|
|
| if (key.toLowerCase() == 'name') { |
| eventAttrs.name = value |
| } else { |
| eventAttrs.props[key] = value |
| } |
| } |
|
|
| if (COMPILE_REVENUE) { |
| var revenueMatchList = className.match(/plausible-revenue-(.+)(=|--)(.+)/) |
| if (revenueMatchList) { |
| key = revenueMatchList[1] |
| value = revenueMatchList[3] |
| eventAttrs.revenue[key] = value |
| } |
| } |
| } |
|
|
| return eventAttrs |
| } |
|
|
| export function init() { |
| document.addEventListener('click', handleLinkClickEvent) |
| document.addEventListener('auxclick', handleLinkClickEvent) |
|
|
| if (COMPILE_FILE_DOWNLOADS && (!COMPILE_CONFIG || config.fileDownloads)) { |
| if (COMPILE_CONFIG) { |
| if ( |
| typeof config.fileDownloads === 'object' && |
| Array.isArray(config.fileDownloads.fileExtensions) |
| ) { |
| fileTypesToTrack = config.fileDownloads.fileExtensions |
| } |
| } else { |
| var fileTypesAttr = scriptEl.getAttribute('file-types') |
| var addFileTypesAttr = scriptEl.getAttribute('add-file-types') |
|
|
| if (fileTypesAttr) { |
| fileTypesToTrack = fileTypesAttr.split(',') |
| } |
| if (addFileTypesAttr) { |
| fileTypesToTrack = addFileTypesAttr |
| .split(',') |
| .concat(DEFAULT_FILE_TYPES) |
| } |
| } |
| } |
|
|
| if (COMPILE_CONFIG && config.formSubmissions) { |
| function trackFormSubmission(e) { |
| if (e.target.hasAttribute('novalidate') || e.target.checkValidity()) { |
| if (COMPILE_TAGGED_EVENTS && isElementOrParentTagged(e.target, 0)) { |
| |
| return |
| } |
| track('Form: Submission') |
| } |
| } |
|
|
| document.addEventListener('submit', trackFormSubmission, true) |
| } |
|
|
| if (COMPILE_TAGGED_EVENTS) { |
| function handleTaggedFormSubmitEvent(event) { |
| var form = event.target |
| var eventAttrs = getTaggedEventAttributes(form) |
| if (!eventAttrs.name) { |
| return |
| } |
|
|
| var attrs |
| |
| |
| if (COMPILE_COMPAT) { |
| event.preventDefault() |
| var formSubmitted = false |
|
|
| function submitForm() { |
| if (!formSubmitted) { |
| formSubmitted = true |
| form.submit() |
| } |
| } |
|
|
| setTimeout(submitForm, 5000) |
|
|
| attrs = { props: eventAttrs.props, callback: submitForm } |
| if (COMPILE_REVENUE) { |
| attrs.revenue = eventAttrs.revenue |
| } |
| track(eventAttrs.name, attrs) |
| } else { |
| attrs = { props: eventAttrs.props } |
| if (COMPILE_REVENUE) { |
| attrs.revenue = eventAttrs.revenue |
| } |
| track(eventAttrs.name, attrs) |
| } |
| } |
|
|
| function isForm(element) { |
| return ( |
| element && element.tagName && element.tagName.toLowerCase() === 'form' |
| ) |
| } |
|
|
| function handleTaggedElementClickEvent(event) { |
| if (event.type === 'auxclick' && event.button !== MIDDLE_MOUSE_BUTTON) { |
| return |
| } |
|
|
| var clicked = event.target |
|
|
| var clickedLink |
| var taggedElement |
| |
| |
| for (var i = 0; i <= PARENTS_TO_SEARCH_LIMIT; i++) { |
| if (!clicked) { |
| break |
| } |
|
|
| |
| if (isForm(clicked)) { |
| return |
| } |
| if (isLink(clicked)) { |
| clickedLink = clicked |
| } |
| if (isTagged(clicked)) { |
| taggedElement = clicked |
| } |
| clicked = clicked.parentNode |
| } |
|
|
| if (taggedElement) { |
| var eventAttrs = getTaggedEventAttributes(taggedElement) |
|
|
| if (clickedLink) { |
| |
| |
| eventAttrs.props.url = clickedLink.href |
| sendLinkClickEvent(event, clickedLink, eventAttrs) |
| } else { |
| var attrs = {} |
| attrs.props = eventAttrs.props |
| if (COMPILE_REVENUE) { |
| attrs.revenue = eventAttrs.revenue |
| } |
| track(eventAttrs.name, attrs) |
| } |
| } |
| } |
|
|
| document.addEventListener('submit', handleTaggedFormSubmitEvent) |
| document.addEventListener('click', handleTaggedElementClickEvent) |
| document.addEventListener('auxclick', handleTaggedElementClickEvent) |
| } |
| } |
|
|