coral-spectrum/coral-utils/src/scripts/Tracking.js
- /**
- * Copyright 2019 Adobe. All rights reserved.
- * This file is licensed to you under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License. You may obtain a copy
- * of the License at http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under
- * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
- * OF ANY KIND, either express or implied. See the License for the specific language
- * governing permissions and limitations under the License.
- */
-
- /**
- Signature function used to track the usage of Coral components. By default, there is no out of the box
- implementation as tracking is agnostic of the underlying technology.
-
- You need to implement a new tracker and add it with: <code>Coral.tracking.addListener(fn(){ });</code>
-
- The <code>fn()</code> callback will receive multiple arguments:
- * <code>trackData</code> - an object with fixed structure e.g. <code>{type: "button", eventType: "click", element: "save settings", feature: "sites"}</code>
- * <code>event</code> - the CustomEvent or MouseEvent details object.
- * <code>component</code> - the component reference object.
-
- Using the above data you can map it to your own analytics tracker.
- */
- class Tracking {
- /* @ignore */
- constructor() {
- /**
- All registered trackers.
-
- @type {Array<Function>}
- */
- this._trackers = [];
- }
-
- /**
- Returns <code>true</code> if the tracking is disabled for the given component, otherwise false.
-
- @param {HTMLElement} component
- @returns {Boolean}
- */
- _isTrackingDisabledForComponent(component) {
- return component &&
- typeof component.tracking !== 'undefined' &&
- component.tracking === component.constructor.tracking.OFF;
- }
-
- /**
- Get tracking annotations from the parent Component to which the event was bound.
-
- @param {BaseComponent} component
- @returns {{trackingElement: String, trackingElement: String}}
- */
- _getTrackingDataFromComponentAttr(component) {
- if (this._isTrackingDisabledForComponent(component)) {
- return {
- trackingElement: '',
- trackingFeature: ''
- };
- }
-
- // Eg. from DOM trackingfeature="sites"
- const trackingFeature = component.trackingFeature || '';
-
- // Eg. from DOM trackingelement="rail toggle"
- const trackingElement = component.trackingElement || '';
-
- return {trackingFeature, trackingElement};
- }
-
- /**
- Returns a tracking data object that can be used to compile data to send to an actual Analytics tracker.
-
- @param {String} eventType
- @param {String} targetType
- @param {CustomEvent} event
- @param {BaseComponent} component
- @param {BaseComponent} childComponent
- @returns {Object} An object with the tracking data.
- */
- _createTrackingData(eventType, targetType, event, component, childComponent) {
- const parentComponentType = (component.getAttribute('is') || component.tagName).toLowerCase();
-
- // Gather data into the Coral Tracking structure.
- const trackDataFromAttr = this._getTrackingDataFromComponentAttr(component);
-
- // Compile data
- /**
- The default Coral tracking data object
- filled with values from root Component and child Component (if exists).
- @type {{targetType: string, targetElement: string, eventType: string, rootElement: string, rootFeature: string, rootType: string}}
- */
- return {
- targetType: targetType || parentComponentType || '',
- targetElement: childComponent && childComponent.trackingElement ? childComponent.trackingElement : component.trackingElement,
- eventType: eventType || event.type,
- rootElement: trackDataFromAttr.trackingElement,
- rootFeature: trackDataFromAttr.trackingFeature,
- rootType: parentComponentType
- };
- }
-
- /**
- Add a tracking callback. This will be invoked every time a tracking event is emitted.
-
- @param {TrackingCallback} trackingCallback
- The callback to execute.
- */
- addListener(trackingCallback) {
- if (typeof trackingCallback !== 'function') {
- throw new Error('Coral.Tracking: Tracker must be a function callback.');
- }
-
- if (this._trackers.indexOf(trackingCallback) !== -1) {
- throw new Error('Coral.Tracking: Tracker callback cannot be added twice.');
- }
-
- this._trackers.push(trackingCallback);
- }
-
- /**
- Removes a tracker.
-
- @param {TrackingCallback} trackingCallback
- */
- removeListener(trackingCallback) {
- this._trackers = this._trackers.filter(trackerFn => trackerFn !== trackingCallback);
- }
-
- /**
- Notify all trackers subscribed.
-
- @param {String} eventType
- Eg. click, select, etc.
- @param {String} targetType
- Eg. cycle button, cycle button item, etc.
- @param {CustomEvent} event
- @param {BaseComponent} component
- @param {BaseComponent} childComponent
- Optional, in case the event occurred on a child component.
- @returns {Boolean} if the event was dispatch to at least 1 tracker.
- */
- track(eventType, targetType, event, component, childComponent) {
- if (
- this._trackers.length === 0 ||
- this._isTrackingDisabledForComponent(component) ||
- this._isTrackingDisabledForComponent(childComponent)
- ) {
- return false;
- }
-
- const args = Array.prototype.slice.call(arguments, [2]);
-
- const trackingData = this._createTrackingData(eventType, targetType, event, component, childComponent);
- this._trackers.forEach((trackerFn) => {
- trackerFn.apply(null, [trackingData].concat(args));
- });
-
- return true;
- }
- }
-
- /**
- Executes the callback when ever there is an interaction inside the component that needs to be tracked. This can be used
- to get insight on how users interact with the page and the features that available.
-
- @typedef {function} TrackingCallback
-
- @param {Object} trackData
- Object containing the data to be tracked. It contains the properties <code>type</code>, <code>eventType</code>,
- <code>element</code> and <code>feature</code>.
- @param {CustomEvent} event
- Underlying event that was generated by the user
- @param {HTMLElement} component
- Component that triggered the tracking event.
- */
- /**
- Tracking API to get insight on component usage.
-
- @type {Tracking}
- */
- const tracking = new Tracking();
- export default tracking;