vue-analytics
Version:
Google Analytics plugin for Vue
452 lines (376 loc) • 10 kB
JavaScript
/*!
* vue-analytics v4.0.0
* (c) 2017 Matteo Gabriele
* Released under the ISC License.
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('load-script')) :
typeof define === 'function' && define.amd ? define(['load-script'], factory) :
(global.VueAnalytics = factory(global.loadScript));
}(this, (function (loadScript) { 'use strict';
loadScript = 'default' in loadScript ? loadScript['default'] : loadScript;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
/**
* Whining helper
* @param {String} message
*/
var warn = function warn() {
for (var _len = arguments.length, message = Array(_len), _key = 0; _key < _len; _key++) {
message[_key] = arguments[_key];
}
/* eslint-disable */
console.warn('[VueAnalytics] ' + message.join(' '));
/* eslint-enable */
};
/**
* Returns if a string exists in the array of routes
* @param {String} name
* @return {Boolean}
*/
var exists = function exists(name) {
return !!(config.ignoreRoutes.length && config.ignoreRoutes.indexOf(name) !== -1);
};
/**
* Merges two objects
* @param {Object} obj
* @param {Object} src
* @return {Object}
*/
var merge = function merge(obj, src) {
Object.keys(src).forEach(function (key) {
if (obj[key] && _typeof(obj[key]) === 'object') {
merge(obj[key], src[key]);
return;
}
obj[key] = src[key];
});
return obj;
};
function getName(value) {
return value.replace(/-/gi, '');
}
function getListId() {
return [].concat(config.id);
}
/**
* Default configuration
*/
var config = {
debug: {
enabled: false,
trace: false,
sendHitTask: true
},
autoTracking: {
exception: false,
page: true
},
id: null,
userId: null,
ignoreRoutes: []
};
/**
* Returns the new configuation object
* @param {Object} params
* @return {Object}
*/
function updateConfig(params) {
return merge(config, params);
}
function ga(method) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
if (typeof window.ga === 'undefined') {
return;
}
var ids = getListId();
ids.forEach(function (id) {
var _window;
var domain = getName(id);
var name = ids.length > 1 ? domain + '.' + method : method;
(_window = window).ga.apply(_window, [name].concat(args));
});
}
function getDataFromRouter(router, args) {
if (!router) {
warn('Is not possible to track the current route without VueRouter installed');
return;
}
var params = {
page: router.currentRoute.path,
title: router.currentRoute.name,
location: window.location.href
};
if (typeof args[1] === 'function') {
params.hitCallback = args[1];
}
return params;
}
/**
* Page tracking
* @param {any} args
* @example
* $ga.page('/home')
*
* $ga.page(this.$router, {
* hitCallback () { //done }
* })
*
* $ga.page({
* page: '/home',
* title: 'home page',
* location: window.location.href,
* hitCallback () { // done }
* })
*/
function page() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var value = args[0];
if (value.constructor.name === 'VueRouter') {
ga('send', 'pageview', getDataFromRouter(value, args));
return;
}
ga.apply(undefined, ['send', 'pageview'].concat(args));
}
/**
* Updating tracker data
* @param {any} data
*/
function set$1() {
if (typeof window.ga === 'undefined') {
return;
}
for (var _len = arguments.length, data = Array(_len), _key = 0; _key < _len; _key++) {
data[_key] = arguments[_key];
}
if (!data.length) {
return;
}
if (_typeof(data[0]) === 'object' && data[0].constructor === Object) {
// Use the ga.set with an object literal
ga('set', data[0]);
return;
}
if (data.length < 2 || typeof data[0] !== 'string' && typeof data[1] !== 'string') {
warn('$ga.set needs a field name and a field value, or you can pass an object literal');
return;
}
// Use ga.set with field name and field value
ga('set', data[0], data[1]);
}
/**
* Enable route autoTracking page
* @param {VueRouter} router
*/
function autoTrackPage(router) {
if (!router && config.autoTracking.page) {
var url = 'https://github.com/MatteoGabriele/vue-analytics#auto-tracking';
warn('page auto-tracking doesn\'t work without a router instance.', url);
return;
}
if (!config.autoTracking.page || !router) {
return;
}
// Track the first page when the user lands on it
var currentRoute = router.currentRoute;
if (!exists(currentRoute.name)) {
set$1('page', currentRoute.path);
page(router);
}
// Track all other pages
router.afterEach(function (_ref) {
var path = _ref.path,
name = _ref.name;
if (exists(name)) {
return;
}
set$1('page', path);
page(router);
});
}
/**
* Exception Tracking
* @param {Error} error
* @param {Boolean} [fatal=false]
* try {
* // something that might not work
* } catch (error) {
* $ga.exception(error.message)
* }
*/
function exception(error) {
var fatal = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
ga('send', 'exception', {
exDescription: error,
exFatal: fatal
});
}
function autoTrackException() {
if (!config.autoTracking.exception) {
return;
}
// start auto tracking error exceptions
window.onerror = function (error) {
return exception(error.message || error);
};
}
/**
* Event tracking
* @param {any} args
* @example
* $ga.event('category', 'action', 'label', 'value')
*
* $ga.event({
* eventCategory: 'lorem ipsum',
* eventAction: 'dolor',
* eventLabel: 'sit',
* eventValue: 1
* })
*/
function event() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
ga.apply(undefined, ['send', 'event'].concat(args));
}
/**
* Time tracking
* @param {any} args
* @example
* $ga.time('category', 'variable', 1, 'label')
*
* $ga.time({
* timingCategory: 'category',
* timingVar: 'variable',
* timingValue: 1,
* timingLabel: 'label'
* })
*/
function time() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
ga.apply(undefined, ['send', 'timing'].concat(args));
}
/**
* Plain access to the GA
* with the query method is possible to pass everything.
* if there's some new command that is not implemented yet, just use this
* @param {any} args
*/
function query() {
ga.apply(undefined, arguments);
}
/**
* Social interactions
* @param {any} args
* $ga.social('Facebook', 'like', http://myownpersonaldomain.com)
*
* $ga.social({
* socialNetwork: 'Facebook',
* socialAction: 'like',
* socialTarget: 'http://myownpersonaldomain.com'
* })
*/
function social() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
ga.apply(undefined, ['send', 'social'].concat(args));
}
/**
* Use Google Analytics require key
* @param {any} value
*/
function gaRequire(value) {
ga('require', value);
}
var features = {
autoTrackPage: autoTrackPage,
autoTrackException: autoTrackException,
social: social,
page: page,
event: event,
time: time,
exception: exception,
set: set$1,
query: query,
// require is already a used keyword in javascript
// need to pass it in a different way or could export
// the wrong function
require: gaRequire
};
function init(router, callback) {
if (config.manual) {
return;
}
if (!config.id || !config.id.length) {
var url = 'https://github.com/MatteoGabriele/vue-analytics#usage';
warn('Please enter a Google Analaytics tracking ID', url);
return;
}
var options = config.userId || {};
var debugSource = config.debug.enabled ? '_debug' : '';
var source = 'https://www.google-analytics.com/analytics' + debugSource + '.js';
loadScript(source, function (error, script) {
if (error) {
warn('Ops! Could\'t load the Google Analytics script');
return;
}
var poll = setInterval(function () {
if (!window.ga) {
return;
}
clearInterval(poll);
if (config.debug.enabled) {
window.ga_debug = {
trace: config.debug.trace
};
}
var ids = getListId();
ids.forEach(function (id) {
if (ids.length > 1) {
// we need to register the name used by the ga methods so that
// when a method is used Google knows which account did it
options['name'] = getName(id);
}
window.ga('create', id, 'auto', options);
});
// the callback is fired when window.ga is available and before any other hit is sent
// see MatteoGabriele/vue-analytics/issues/20
if (callback && typeof callback === 'function') {
callback();
}
if (!config.debug.sendHitTask) {
features.set('sendHitTask', null);
}
// send the first pageview hit
ga('send', 'pageview');
features.autoTrackException();
features.autoTrackPage(router);
}, 10);
});
}
/**
* Vue installer
* @param {Vue instance} Vue
* @param {Object} [options={}]
*/
function install(Vue) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var router = options.router;
delete options.router;
updateConfig(options);
init(router, options.onReady);
Vue.prototype.$ga = Vue.$ga = features;
}
var index = { install: install, getName: getName };
return index;
})));