@financial-times/o-tracking
Advanced tools
Comparing version 1.4.3 to 1.5.0
/*global require, module */ | ||
'use strict'; // eslint-disable-line strict | ||
const settings = require("./dist/javascript/core/settings.js"); | ||
const settings = require("./dist/javascript/core/settings"); | ||
const user = require("./dist/javascript/core/user.js"); | ||
const user = require("./dist/javascript/core/user"); | ||
const session = require("./dist/javascript/core/session.js"); | ||
const session = require("./dist/javascript/core/session"); | ||
const send = require("./dist/javascript/core/send.js"); | ||
const send = require("./dist/javascript/core/send"); | ||
/** | ||
@@ -87,3 +87,3 @@ * The version of the tracking module. | ||
Tracking.prototype.event = require("./dist/javascript/events/custom.js"); | ||
Tracking.prototype.event = require("./dist/javascript/events/custom"); | ||
/** | ||
@@ -94,4 +94,10 @@ * Make the page tracking request. | ||
Tracking.prototype.page = require("./dist/javascript/events/page-view.js"); | ||
Tracking.prototype.page = require("./dist/javascript/events/page-view"); | ||
/** | ||
* To initalise view events for components/elements. | ||
* @see {@link view#init} | ||
*/ | ||
Tracking.prototype.view = require("./dist/javascript/events/component-view"); | ||
/** | ||
* To initalise click events. | ||
@@ -101,3 +107,3 @@ * @see {@link click#init} | ||
Tracking.prototype.click = require("./dist/javascript/events/click.js"); | ||
Tracking.prototype.click = require("./dist/javascript/events/click"); | ||
/** | ||
@@ -117,3 +123,3 @@ * Previously, the click handler was initialised as "link". | ||
Tracking.prototype.utils = require("./dist/javascript/utils.js"); | ||
Tracking.prototype.utils = require("./dist/javascript/utils"); | ||
/** | ||
@@ -120,0 +126,0 @@ * Initialises the Tracking object. |
@@ -14,4 +14,5 @@ /*global module, require */ | ||
const getTrace = require("../../libs/get-trace"); | ||
let internalQueue; | ||
const elementPropertiesToCollect = ["nodeName", "className", "id", "href", "text", "role"]; | ||
const eventPropertiesToCollect = ["ctrlKey", "altKey", "shiftKey", "metaKey"]; // Trigger the event tracking | ||
@@ -35,106 +36,2 @@ | ||
} | ||
}; // Utility for trimming strings | ||
const sanitise = property => { | ||
return typeof property === 'string' ? property.trim() : property; | ||
}; // For a given container element, get the number of elements that match the | ||
// clicked element (siblings); and the index of the clicked element (position). | ||
const getSiblingsAndPosition = (el, clickedEl, selector) => { | ||
const siblings = Array.from(el.querySelectorAll(selector)); | ||
const position = siblings.findIndex(item => item === clickedEl); | ||
if (position === -1) { | ||
return; | ||
} | ||
return { | ||
siblings: siblings.length, | ||
position | ||
}; | ||
}; // Get all (sanitised) properties of a given element. | ||
const getAllElementProperties = el => { | ||
return elementPropertiesToCollect.reduce((returnObject, property) => { | ||
if (el[property]) { | ||
returnObject[property] = sanitise(el[property]); | ||
} else if (el.getAttribute(property)) { | ||
returnObject[property] = sanitise(el.getAttribute(property)); | ||
} else if (el.hasAttribute(property)) { | ||
returnObject[property] = el.hasAttribute(property); | ||
} | ||
return returnObject; | ||
}, {}); | ||
}; // Get some properties of a given element. | ||
const getDomPathProps = (attrs, props) => { | ||
// Collect any attribute that matches given strings. | ||
attrs.filter(attribute => attribute.name.match(/^data-trackable|^data-o-|^aria-/i)).forEach(attribute => { | ||
props[attribute.name] = attribute.value; | ||
}); | ||
return props; | ||
}; // Get only the custom data-trackable-context-? properties of a given element | ||
const getContextProps = (attrs, props, isClickedEl) => { | ||
const customProps = {}; // for the clicked element collect properties like className, nodeName | ||
if (isClickedEl) { | ||
elementPropertiesToCollect.forEach(name => { | ||
if (typeof props[name] !== 'undefined' && name !== 'id') { | ||
customProps[name] = props[name]; | ||
} | ||
}); | ||
} // Collect any attribute that matches given strings. | ||
attrs.filter(attribute => attribute.name.match(/^data-trackable-context-/i)).forEach(attribute => { | ||
customProps[attribute.name.replace('data-trackable-context-', '')] = attribute.value; | ||
}); | ||
return customProps; | ||
}; | ||
const assignIfUndefined = (subject, target) => { | ||
for (const prop in subject) { | ||
if (!target[prop]) { | ||
target[prop] = subject[prop]; | ||
} else { | ||
console.warn(`You can't set a custom property called ${prop}`); | ||
} | ||
} | ||
}; // Trace the clicked element and all of its parents, collecting properties as we go | ||
const getTrace = el => { | ||
const rootEl = document; | ||
const clickedEl = el; | ||
const selector = clickedEl.getAttribute('data-trackable') ? `[data-trackable="${clickedEl.getAttribute('data-trackable')}"]` : clickedEl.nodeName; | ||
const trace = []; | ||
const customContext = {}; | ||
while (el && el !== rootEl) { | ||
const props = getAllElementProperties(el); | ||
const attrs = Array.from(el.attributes); | ||
let domPathProps = getDomPathProps(attrs, props); // If the element happens to have a data-trackable attribute, get the siblings | ||
// and position of the clicked element (relative to the current element). | ||
if (domPathProps["data-trackable"]) { | ||
domPathProps = Object.assign(domPathProps, getSiblingsAndPosition(el, clickedEl, selector)); | ||
} | ||
trace.push(domPathProps); | ||
const contextProps = getContextProps(attrs, props, el === clickedEl); | ||
assignIfUndefined(contextProps, customContext); | ||
el = el.parentNode; | ||
} | ||
return { | ||
trace, | ||
customContext | ||
}; | ||
}; // Get properties for the event (as opposed to properties of the clicked element) | ||
@@ -148,3 +45,3 @@ // Available properties include mouse x- and y co-ordinates, for example. | ||
if (event[property]) { | ||
returnObject[property] = sanitise(event[property]); | ||
returnObject[property] = utils.sanitise(event[property]); | ||
} | ||
@@ -175,3 +72,3 @@ } catch (e) { | ||
context.url = window.document.location.href || null; | ||
assignIfUndefined(customContext, context); | ||
utils.assignIfUndefined(customContext, context); | ||
eventData.context = context; // Merge the event data into the "parent" config data | ||
@@ -178,0 +75,0 @@ |
@@ -235,2 +235,42 @@ /*global module, require, window */ | ||
/** | ||
* Trim strings | ||
* @param {String} str - The string to trim. | ||
* @return {String} The trimmed string. | ||
*/ | ||
function sanitise(str) { | ||
return typeof str === 'string' ? str.trim() : str; | ||
} | ||
/** | ||
* Assign the subject value if the target properties are undefined | ||
* @param {Object} subject - assign the value | ||
* @param {Object} target - be assigned the value | ||
* @return | ||
*/ | ||
function assignIfUndefined(subject, target) { | ||
for (const prop in subject) { | ||
if (!target[prop]) { | ||
target[prop] = subject[prop]; | ||
} else { | ||
console.warn(`You can't set a custom property called ${prop}`); | ||
} | ||
} | ||
} | ||
/** | ||
* Whitelist props | ||
* @param {Object} props - An object whose props need to be whitelisted | ||
* @param {Array} list - A list for whitelisting | ||
* @return | ||
*/ | ||
function whitelistProps(props, list) { | ||
return list.reduce((acc, propName) => Object.assign({}, acc, props[propName] ? { | ||
[propName]: props[propName] | ||
} : undefined), {}); | ||
} | ||
/** | ||
* Utilities. | ||
@@ -255,3 +295,6 @@ * @alias utils | ||
getValueFromUrl: getValueFromUrl, | ||
getValueFromJsVariable: getValueFromJsVariable | ||
getValueFromJsVariable: getValueFromJsVariable, | ||
sanitise: sanitise, | ||
assignIfUndefined: assignIfUndefined, | ||
whitelistProps: whitelistProps | ||
}; |
@@ -14,3 +14,5 @@ { | ||
"required": [ | ||
"CustomEvent" | ||
"CustomEvent", | ||
"IntersectionObserver", | ||
"IntersectionObserverEntry" | ||
], | ||
@@ -17,0 +19,0 @@ "optional": [ |
@@ -6,5 +6,6 @@ { | ||
"dist/", | ||
"index.js", | ||
"browser.js", | ||
"src/", | ||
"main*", | ||
"!src/**/*.js", | ||
"main.scss", | ||
"img", | ||
@@ -20,4 +21,9 @@ "*.json", | ||
], | ||
"keywords": [ | ||
"origami", | ||
"component", | ||
"ft" | ||
], | ||
"name": "@financial-times/o-tracking", | ||
"version": "1.4.3", | ||
"version": "1.5.0", | ||
"description": "Origami module for FT tracking.", | ||
@@ -31,4 +37,3 @@ "dependencies": { | ||
"origami-build-tools": "^7.2.0" | ||
}, | ||
"main": "main.js" | ||
} | ||
} |
@@ -64,2 +64,4 @@ # Origami Tracking component [![CircleCI](https://circleci.com/gh/Financial-Times/o-tracking.svg?style=svg&circle-token=bac74d66190dbd699381ab25baab148fb3bb010c)](https://circleci.com/gh/Financial-Times/o-tracking) [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](#licence) | ||
oTracking.click.init(category); | ||
// Components/Elements views. | ||
oTracking.view.init({...opts...}); | ||
} | ||
@@ -83,2 +85,4 @@ ``` | ||
oTracking.click.init(category); | ||
// Components/Elements views. | ||
oTracking.view.init({...opts...}); | ||
} | ||
@@ -193,3 +197,22 @@ ``` | ||
* Click events [initalised as above](#usage), will populate a `domPathTokens` property. If the clicked element has the `data-trackable` attribute, sibling elements will also be included within `domPathTokens`. | ||
* View events are fired for elements with the `data-o-tracking-view` attribute by default, unless `o-tracking`'s `selector` option is configured. Like click events, view events populate a `domPathTokens` property. To collect data for events, set the `category` option, or provide a callback[`getContextData`] | ||
_Note:_ This feature requires `window.IntersectionObserver` in order to track the events | ||
_Note:_ `getContextData` should be a function which returns `{Object}`. It accepts the viewed element as an argument | ||
```js | ||
const opts = { | ||
category: 'audio', // default: 'component' | ||
selector: '.o-teaser__audio', // default: '[data-o-tracking-view]' | ||
getContextData: (el) => { // default: null | ||
return { | ||
contentId: el.getAttribute('data-id'), | ||
type: 'audio', | ||
subtype: 'podcast', | ||
component: 'teaser' | ||
}; | ||
} | ||
} | ||
oTracking.view.init(opts); | ||
``` | ||
Events are decorated with config values you pass in via `init()` or `updateConfig()` if they are part of `context`, `user`, or `device` objects. Values passed in as `context` to individual events will override context values from init. | ||
@@ -196,0 +219,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
283
69981
22
1937
1