2020-04-28 11:23:04 +00:00
|
|
|
/* global _paq */
|
|
|
|
|
2022-09-06 12:51:50 +00:00
|
|
|
import { getJitsiMeetGlobalNS } from '../../base/util/helpers';
|
2020-04-28 11:23:04 +00:00
|
|
|
|
2022-09-06 12:51:50 +00:00
|
|
|
import AbstractHandler, { IEvent } from './AbstractHandler';
|
2020-04-28 11:23:04 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Analytics handler for Matomo.
|
|
|
|
*/
|
2020-04-29 10:40:04 +00:00
|
|
|
export default class MatomoHandler extends AbstractHandler {
|
2022-09-06 12:51:50 +00:00
|
|
|
_userProperties: Object;
|
2020-04-28 11:23:04 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates new instance of the Matomo handler.
|
|
|
|
*
|
|
|
|
* @param {Object} options -
|
|
|
|
* @param {string} options.matomoEndpoint - The Matomo endpoint.
|
|
|
|
* @param {string} options.matomoSiteID - The site ID.
|
|
|
|
*/
|
2022-09-06 12:51:50 +00:00
|
|
|
constructor(options: any) {
|
2020-04-28 11:23:04 +00:00
|
|
|
super(options);
|
|
|
|
this._userProperties = {};
|
|
|
|
|
|
|
|
if (!options.matomoEndpoint) {
|
|
|
|
throw new Error(
|
|
|
|
'Failed to initialize Matomo handler: no endpoint defined.'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (!options.matomoSiteID) {
|
|
|
|
throw new Error(
|
|
|
|
'Failed to initialize Matomo handler: no site ID defined.'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
this._enabled = true;
|
|
|
|
this._initMatomo(options);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initializes the _paq object.
|
|
|
|
*
|
|
|
|
* @param {Object} options -
|
|
|
|
* @param {string} options.matomoEndpoint - The Matomo endpoint.
|
|
|
|
* @param {string} options.matomoSiteID - The site ID.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2022-09-06 12:51:50 +00:00
|
|
|
_initMatomo(options: any) {
|
|
|
|
// @ts-ignore
|
2020-04-28 11:23:04 +00:00
|
|
|
const _paq = window._paq || [];
|
|
|
|
|
2022-09-06 12:51:50 +00:00
|
|
|
// @ts-ignore
|
2020-04-28 11:23:04 +00:00
|
|
|
window._paq = _paq;
|
|
|
|
|
|
|
|
_paq.push([ 'trackPageView' ]);
|
|
|
|
_paq.push([ 'enableLinkTracking' ]);
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
// add trailing slash if needed
|
|
|
|
const u = options.matomoEndpoint.endsWith('/')
|
|
|
|
? options.matomoEndpoint
|
|
|
|
: `${options.matomoEndpoint}/`;
|
|
|
|
|
|
|
|
// configure the tracker
|
|
|
|
_paq.push([ 'setTrackerUrl', `${u}matomo.php` ]);
|
|
|
|
_paq.push([ 'setSiteId', options.matomoSiteID ]);
|
|
|
|
|
|
|
|
// insert the matomo script
|
|
|
|
const d = document,
|
|
|
|
g = d.createElement('script'),
|
|
|
|
s = d.getElementsByTagName('script')[0];
|
|
|
|
|
|
|
|
g.type = 'text/javascript';
|
|
|
|
g.async = true;
|
|
|
|
g.defer = true;
|
|
|
|
g.src = `${u}matomo.js`;
|
2022-09-06 12:51:50 +00:00
|
|
|
s.parentNode?.insertBefore(g, s);
|
2020-04-28 11:23:04 +00:00
|
|
|
})();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extracts the integer to use for a Matomo event's value field
|
|
|
|
* from a lib-jitsi-meet analytics event.
|
|
|
|
*
|
|
|
|
* @param {Object} event - The lib-jitsi-meet analytics event.
|
|
|
|
* @returns {number} - The integer to use for the 'value' of a Matomo
|
|
|
|
* event, or NaN if the lib-jitsi-meet event doesn't contain a
|
|
|
|
* suitable value.
|
|
|
|
* @private
|
|
|
|
*/
|
2022-09-06 12:51:50 +00:00
|
|
|
_extractValue(event: IEvent) {
|
2022-09-08 09:52:36 +00:00
|
|
|
const value = event?.attributes?.value;
|
2020-04-28 11:23:04 +00:00
|
|
|
|
|
|
|
// Try to extract an integer from the 'value' attribute.
|
2022-09-06 12:51:50 +00:00
|
|
|
return Math.round(parseFloat(value ?? ''));
|
2020-04-28 11:23:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the permanent properties for the current session.
|
|
|
|
*
|
|
|
|
* @param {Object} userProps - The permanent properties.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2022-09-06 12:51:50 +00:00
|
|
|
setUserProperties(userProps: any = {}) {
|
2020-04-28 11:23:04 +00:00
|
|
|
if (!this._enabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const visitScope = [ 'user_agent', 'callstats_name', 'browser_name' ];
|
|
|
|
|
|
|
|
// add variables in the 'page' scope
|
|
|
|
Object.keys(userProps)
|
|
|
|
.filter(key => visitScope.indexOf(key) === -1)
|
|
|
|
.forEach((key, index) => {
|
2022-09-06 12:51:50 +00:00
|
|
|
// @ts-ignore
|
2020-04-28 11:23:04 +00:00
|
|
|
_paq.push([
|
|
|
|
'setCustomVariable',
|
|
|
|
1 + index,
|
|
|
|
key,
|
|
|
|
userProps[key],
|
|
|
|
'page'
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// add variables in the 'visit' scope
|
|
|
|
Object.keys(userProps)
|
|
|
|
.filter(key => visitScope.indexOf(key) !== -1)
|
|
|
|
.forEach((key, index) => {
|
2022-09-06 12:51:50 +00:00
|
|
|
// @ts-ignore
|
2020-04-28 11:23:04 +00:00
|
|
|
_paq.push([
|
|
|
|
'setCustomVariable',
|
|
|
|
1 + index,
|
|
|
|
key,
|
|
|
|
userProps[key],
|
|
|
|
'visit'
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This is the entry point of the API. The function sends an event to
|
|
|
|
* the Matomo endpoint. The format of the event is described in
|
|
|
|
* analyticsAdapter in lib-jitsi-meet.
|
|
|
|
*
|
|
|
|
* @param {Object} event - The event in the format specified by
|
|
|
|
* lib-jitsi-meet.
|
|
|
|
* @returns {void}
|
|
|
|
*/
|
2022-09-06 12:51:50 +00:00
|
|
|
sendEvent(event: IEvent) {
|
2020-04-28 11:23:04 +00:00
|
|
|
if (this._shouldIgnore(event)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const value = this._extractValue(event);
|
2022-09-08 09:52:36 +00:00
|
|
|
const matomoEvent: Array<string | number | undefined> = [
|
|
|
|
'trackEvent', 'jitsi-meet', this._extractName(event) ];
|
2020-04-28 11:23:04 +00:00
|
|
|
|
|
|
|
if (!isNaN(value)) {
|
|
|
|
matomoEvent.push(value);
|
|
|
|
}
|
|
|
|
|
2022-09-06 12:51:50 +00:00
|
|
|
// @ts-ignore
|
2020-04-28 11:23:04 +00:00
|
|
|
_paq.push(matomoEvent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const globalNS = getJitsiMeetGlobalNS();
|
|
|
|
|
|
|
|
globalNS.analyticsHandlers = globalNS.analyticsHandlers || [];
|
|
|
|
globalNS.analyticsHandlers.push(MatomoHandler);
|