Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/tracking.js')
-rw-r--r--app/assets/javascripts/tracking.js103
1 files changed, 56 insertions, 47 deletions
diff --git a/app/assets/javascripts/tracking.js b/app/assets/javascripts/tracking.js
index 1b4ca1d5741..7c0097fbe37 100644
--- a/app/assets/javascripts/tracking.js
+++ b/app/assets/javascripts/tracking.js
@@ -1,4 +1,4 @@
-import $ from 'jquery';
+import _ from 'underscore';
const DEFAULT_SNOWPLOW_OPTIONS = {
namespace: 'gl',
@@ -14,18 +14,31 @@ const DEFAULT_SNOWPLOW_OPTIONS = {
linkClickTracking: false,
};
-const extractData = (el, opts = {}) => {
- const { trackEvent, trackLabel = '', trackProperty = '' } = el.dataset;
- let trackValue = el.dataset.trackValue || el.value || '';
- if (el.type === 'checkbox' && !el.checked) trackValue = false;
- return [
- trackEvent + (opts.suffix || ''),
- {
- label: trackLabel,
- property: trackProperty,
- value: trackValue,
- },
- ];
+const eventHandler = (e, func, opts = {}) => {
+ const el = e.target.closest('[data-track-event]');
+ const action = el && el.dataset.trackEvent;
+ if (!action) return;
+
+ let value = el.dataset.trackValue || el.value || undefined;
+ if (el.type === 'checkbox' && !el.checked) value = false;
+
+ const data = {
+ label: el.dataset.trackLabel,
+ property: el.dataset.trackProperty,
+ value,
+ context: el.dataset.trackContext,
+ };
+
+ func(opts.category, action + (opts.suffix || ''), _.omit(data, _.isUndefined));
+};
+
+const eventHandlers = (category, func) => {
+ const handler = opts => e => eventHandler(e, func, { ...{ category }, ...opts });
+ const handlers = [];
+ handlers.push({ name: 'click', func: handler() });
+ handlers.push({ name: 'show.bs.dropdown', func: handler({ suffix: '_show' }) });
+ handlers.push({ name: 'hide.bs.dropdown', func: handler({ suffix: '_hide' }) });
+ return handlers;
};
export default class Tracking {
@@ -39,49 +52,43 @@ export default class Tracking {
return typeof window.snowplow === 'function' && this.trackable();
}
- static event(category = document.body.dataset.page, event = 'generic', data = {}) {
+ static event(category = document.body.dataset.page, action = 'generic', data = {}) {
if (!this.enabled()) return false;
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
if (!category) throw new Error('Tracking: no category provided for tracking.');
- return window.snowplow(
- 'trackStructEvent',
- category,
- event,
- Object.assign({}, { label: '', property: '', value: '' }, data),
- );
+ const { label, property, value, context } = data;
+ const contexts = context ? [context] : undefined;
+ return window.snowplow('trackStructEvent', category, action, label, property, value, contexts);
}
- constructor(category = document.body.dataset.page) {
- this.category = category;
- }
-
- bind(container = document) {
- if (!this.constructor.enabled()) return;
- container.querySelectorAll(`[data-track-event]`).forEach(el => {
- if (this.customHandlingFor(el)) return;
- // jquery is required for select2, so we use it always
- // see: https://github.com/select2/select2/issues/4686
- $(el).on('click', this.eventHandler(this.category));
- });
- }
+ static bindDocument(category = document.body.dataset.page, documentOverride = null) {
+ const el = documentOverride || document;
+ if (!this.enabled() || el.trackingBound) return [];
- customHandlingFor(el) {
- const classes = el.classList;
+ el.trackingBound = true;
- // bootstrap dropdowns
- if (classes.contains('dropdown')) {
- $(el).on('show.bs.dropdown', this.eventHandler(this.category, { suffix: '_show' }));
- $(el).on('hide.bs.dropdown', this.eventHandler(this.category, { suffix: '_hide' }));
- return true;
- }
-
- return false;
+ const handlers = eventHandlers(category, (...args) => this.event(...args));
+ handlers.forEach(event => el.addEventListener(event.name, event.func));
+ return handlers;
}
- eventHandler(category = null, opts = {}) {
- return e => {
- this.constructor.event(category || this.category, ...extractData(e.currentTarget, opts));
+ static mixin(opts) {
+ return {
+ data() {
+ return {
+ tracking: {
+ // eslint-disable-next-line no-underscore-dangle
+ category: this.$options.name || this.$options._componentTag,
+ },
+ };
+ },
+ methods: {
+ track(action, data) {
+ const category = opts.category || data.category || this.tracking.category;
+ Tracking.event(category || 'unspecified', action, { ...opts, ...this.tracking, ...data });
+ },
+ },
};
}
}
@@ -89,7 +96,7 @@ export default class Tracking {
export function initUserTracking() {
if (!Tracking.enabled()) return;
- const opts = Object.assign({}, DEFAULT_SNOWPLOW_OPTIONS, window.snowplowOptions);
+ const opts = { ...DEFAULT_SNOWPLOW_OPTIONS, ...window.snowplowOptions };
window.snowplow('newTracker', opts.namespace, opts.hostname, opts);
window.snowplow('enableActivityTracking', 30, 30);
@@ -97,4 +104,6 @@ export function initUserTracking() {
if (opts.formTracking) window.snowplow('enableFormTracking');
if (opts.linkClickTracking) window.snowplow('enableLinkClickTracking');
+
+ Tracking.bindDocument();
}