%PDF- %PDF-
| Direktori : /home/bitrix/www/bitrix/modules/landing/install/js/landing/event-tracker/ |
| Current File : /home/bitrix/www/bitrix/modules/landing/install/js/landing/event-tracker/event-tracker.js |
;(function() {
"use strict";
BX.namespace("BX.Landing");
var bind = BX.Landing.Utils.bind;
var data = BX.Landing.Utils.data;
var isEmpty = BX.Landing.Utils.isEmpty;
var isPlainObject = BX.Landing.Utils.isPlainObject;
var slice = BX.Landing.Utils.slice;
var findParent = BX.Landing.Utils.findParent;
var trim = BX.Landing.Utils.trim;
var join = BX.Landing.Utils.join;
var attr = BX.Landing.Utils.attr;
/**
* Reduces tracking events
* @param {BX.Landing.EventTracker} tracker
* @param {HTMLElement} element
* @param {string} event
* @return {*}
*/
function trackingReducer(tracker, element, event)
{
switch (event)
{
case "show":
return trackShowEvent(tracker, element);
case "click":
return trackClickEvent(tracker, element);
default:
return (function() {});
}
}
/**
* Tracks shows element event
* @param {BX.Landing.EventTracker} tracker
* @param {HTMLElement} element
*/
function trackShowEvent(tracker, element)
{
if (!tracker.blockWiewMap.has(element))
{
tracker.intersectionObserver.observe(element);
tracker.blockWiewMap.set(element, null);
}
}
/**
* Track clicks on link or child links
* @param {BX.Landing.EventTracker} tracker
* @param {HTMLElement} element
*/
function trackClickEvent(tracker, element)
{
var items = [].concat(
slice(element.querySelectorAll("a")),
slice(element.querySelectorAll("button"))
);
items.forEach(function(item) {
if (!tracker.clickMap.has(item))
{
bind(item, "click", onClick.bind(null, tracker, item));
tracker.clickMap.set(item, null);
}
});
}
/**
* Handles click events
* @param {BX.Landing.EventTracker} tracker
* @param item
*/
function onClick(tracker, item)
{
var block = findParent(item, {className: "block-wrapper"});
var gaData = {
type: "click",
category: join("#", block.id),
label: trim(item.innerText)
};
if (isEmpty(gaData.label) && item.tagName === "A")
{
var firstChild = item.firstElementChild;
if (firstChild && firstChild.tagName === "IMG" && attr(firstChild, "alt"))
{
gaData.label = attr(firstChild, "alt");
}
else
{
gaData.label = attr(item, "href");
}
}
tracker.push(gaData);
}
/**
* Fetches tracking options from element
* @param {HTMLElement} element
* @return {{
* [event]: string[]
* }}
*/
function fetchOptionsFromElement(element)
{
var sourceOptions = data(element);
var resultOptions = {};
if (isPlainObject(sourceOptions) && !isEmpty(sourceOptions))
{
resultOptions.event = sourceOptions["data-event-tracker"] || [];
}
return resultOptions;
}
/**
* Runs intersection timer
* @param {BX.Landing.EventTracker} tracker
* @param {HTMLElement} element
*/
function runIntersectionTimer(tracker, element)
{
clearIntersectionTimer(tracker, element);
var timerId = setTimeout(function() {
var block = findParent(element, {className: "block-wrapper"});
tracker.push({category: "Block", type: "show", label: "#" + block.id});
}, 1000);
tracker.blockWiewMap.set(element, timerId);
}
/**
* Clears intersection timer
* @param {BX.Landing.EventTracker} tracker
* @param {HTMLElement} element
*/
function clearIntersectionTimer(tracker, element)
{
clearTimeout(tracker.blockWiewMap.get(element));
tracker.blockWiewMap.set(element, 0);
}
/**
* Gets ration for IntersectionObserverEntry
* @param {IntersectionObserverEntry} entry
* @return {number}
*/
function getMinIntersectionRatio(entry)
{
var windowHeight = window.innerHeight;
if (entry.boundingClientRect.height <= (windowHeight / 2))
{
return .9;
}
if (entry.boundingClientRect.height >= windowHeight)
{
var ratio = (
Math.min(entry.boundingClientRect.height, windowHeight) /
Math.max(entry.boundingClientRect.height, windowHeight)
);
return ratio - ((ratio / 100) * 10);
}
return 0.70;
}
/**
* Handles intersection event
* @param {BX.Landing.EventTracker} tracker
* @param {IntersectionObserverEntry[]} entries
*/
function onIntersect(tracker, entries)
{
entries.forEach(function(entry) {
if (entry.intersectionRatio >= getMinIntersectionRatio(entry))
{
runIntersectionTimer(tracker, entry.target);
return;
}
clearIntersectionTimer(tracker, entry.target);
})
}
/**
* Implements interface for works with page events for analytics
* @constructor
*/
BX.Landing.EventTracker = function()
{
this.intersectionObserver = new IntersectionObserver(
onIntersect.bind(null, this),
{threshold: [0, .05, .1, .2, .3, .4, .5, .6, .7, .8, .9, 1]}
);
this.blockWiewMap = new WeakMap();
this.clickMap = new WeakMap();
this.services = [
new BX.Landing.EventTracker.Service.GoogleAnalytics()
];
};
/**
* Gets instance of BX.Landing.EventTracker
* @return {*}
*/
BX.Landing.EventTracker.getInstance = function()
{
return (
BX.Landing.EventTracker.instance ||
(BX.Landing.EventTracker.instance = new BX.Landing.EventTracker())
);
};
BX.Landing.EventTracker.prototype = {
/**
* Observes element events
* @param {HTMLElement} element
*/
observe: function(element)
{
var options = fetchOptionsFromElement(document.body);
if (isPlainObject(options) && !isEmpty(options))
{
options.event.forEach(trackingReducer.bind(null, this, element));
}
},
/**
* Pushes event to analytics services
* @param {{type: string, category: string, label: string, [...]}} data
*/
push: function(data)
{
this.services.forEach(function(service) {
service.push(data);
});
},
/**
* Runs events tracking
*/
run: function()
{
slice(document.querySelectorAll(".block-wrapper > *:first-child"))
.forEach(this.observe, this);
}
};
})();