react-metrics
Version:
An analytics library for React.js
1,427 lines (1,143 loc) • 117 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("react"), require("react-dom"));
else if(typeof define === 'function' && define.amd)
define(["react", "react-dom"], factory);
else if(typeof exports === 'object')
exports["ReactMetrics"] = factory(require("react"), require("react-dom"));
else
root["ReactMetrics"] = factory(root["React"], root["ReactDOM"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_7__, __WEBPACK_EXTERNAL_MODULE_15__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ exports: {},
/******/ id: moduleId,
/******/ loaded: false
/******/ };
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/ // Flag the module as loaded
/******/ module.loaded = true;
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/ // Load entry module and return exports
/******/ return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PropTypes = exports.MetricsElement = exports.exposeMetrics = exports.metrics = exports.createMetrics = undefined;
var _createMetrics = __webpack_require__(9);
var _createMetrics2 = _interopRequireDefault(_createMetrics);
var _metrics = __webpack_require__(24);
var _metrics2 = _interopRequireDefault(_metrics);
var _PropTypes = __webpack_require__(2);
var _PropTypes2 = _interopRequireDefault(_PropTypes);
var _exposeMetrics = __webpack_require__(12);
var _exposeMetrics2 = _interopRequireDefault(_exposeMetrics);
var _MetricsElement = __webpack_require__(19);
var _MetricsElement2 = _interopRequireDefault(_MetricsElement);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
exports.createMetrics = _createMetrics2.default;
exports.metrics = _metrics2.default;
exports.exposeMetrics = _exposeMetrics2.default;
exports.MetricsElement = _MetricsElement2.default;
exports.PropTypes = _PropTypes2.default;
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';
/**
* Use invariant() to assert state which your program assumes to be true.
*
* Provide sprintf-style format (only %s is supported) and arguments
* to provide information about what broke and what you were
* expecting.
*
* The invariant message will be stripped in production, but the invariant
* will remain to ensure logic does not differ in production.
*/
var validateFormat = function validateFormat(format) {};
if (true) {
validateFormat = function validateFormat(format) {
if (format === undefined) {
throw new Error('invariant requires an error message argument');
}
};
}
function invariant(condition, format, a, b, c, d, e, f) {
validateFormat(format);
if (!condition) {
var error;
if (format === undefined) {
error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.');
} else {
var args = [a, b, c, d, e, f];
var argIndex = 0;
error = new Error(format.replace(/%s/g, function () {
return args[argIndex++];
}));
error.name = 'Invariant Violation';
}
error.framesToPop = 1; // we don't care about invariant's own frame
throw error;
}
}
module.exports = invariant;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.location = exports.metrics = undefined;
var _propTypes = __webpack_require__(6);
var metrics = exports.metrics = _propTypes.object;
var location = exports.location = (0, _propTypes.shape)({
pathname: _propTypes.string.isRequired,
search: _propTypes.string.isRequired,
query: _propTypes.object,
state: _propTypes.object
});
exports.default = {
metrics: metrics,
location: location
};
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';
var emptyFunction = __webpack_require__(5);
/**
* Similar to invariant but only logs a warning if the condition is not met.
* This can be used to log issues in development environments in critical
* paths. Removing the logging code for production environments will keep the
* same logic and follow the same code paths.
*/
var warning = emptyFunction;
if (true) {
var printWarning = function printWarning(format) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
var argIndex = 0;
var message = 'Warning: ' + format.replace(/%s/g, function () {
return args[argIndex++];
});
if (typeof console !== 'undefined') {
console.error(message);
}
try {
// --- Welcome to debugging React ---
// This error was thrown as a convenience so that you can use this stack
// to find the callsite that caused this warning to fire.
throw new Error(message);
} catch (x) {}
};
warning = function warning(condition, format) {
if (format === undefined) {
throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument');
}
if (format.indexOf('Failed Composite propType: ') === 0) {
return; // Ignore CompositeComponent proptype check.
}
if (!condition) {
for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) {
args[_key2 - 2] = arguments[_key2];
}
printWarning.apply(undefined, [format].concat(args));
}
};
}
module.exports = warning;
/***/ }),
/* 4 */
/***/ (function(module, exports) {
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
'use strict';
var canUseDOM = !!(typeof window !== 'undefined' && window.document && window.document.createElement);
/**
* Simple, lightweight module assisting with the detection and context of
* Worker. Helps avoid circular dependencies and allows code to reason about
* whether or not they are in a Worker, even if they never include the main
* `ReactWorker` dependency.
*/
var ExecutionEnvironment = {
canUseDOM: canUseDOM,
canUseWorkers: typeof Worker !== 'undefined',
canUseEventListeners: canUseDOM && !!(window.addEventListener || window.attachEvent),
canUseViewport: canUseDOM && !!window.screen,
isInWorker: !canUseDOM // For now, this is true - might change in the future.
};
module.exports = ExecutionEnvironment;
/***/ }),
/* 5 */
/***/ (function(module, exports) {
"use strict";
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*
*/
function makeEmptyFunction(arg) {
return function () {
return arg;
};
}
/**
* This function accepts and discards inputs; it has no side effects. This is
* primarily useful idiomatically for overridable function endpoints which
* always need to be callable, since JS lacks a null-call idiom ala Cocoa.
*/
var emptyFunction = function emptyFunction() {};
emptyFunction.thatReturns = makeEmptyFunction;
emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
emptyFunction.thatReturnsNull = makeEmptyFunction(null);
emptyFunction.thatReturnsThis = function () {
return this;
};
emptyFunction.thatReturnsArgument = function (arg) {
return arg;
};
module.exports = emptyFunction;
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
if (true) {
var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' &&
Symbol.for &&
Symbol.for('react.element')) ||
0xeac7;
var isValidElement = function(object) {
return typeof object === 'object' &&
object !== null &&
object.$$typeof === REACT_ELEMENT_TYPE;
};
// By explicitly using `prop-types` you are opting into new development behavior.
// http://fb.me/prop-types-in-prod
var throwOnDirectAccess = true;
module.exports = __webpack_require__(32)(isValidElement, throwOnDirectAccess);
} else {
// By explicitly using `prop-types` you are opting into new production behavior.
// http://fb.me/prop-types-in-prod
module.exports = require('./factoryWithThrowingShims')();
}
/***/ }),
/* 7 */
/***/ (function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_7__;
/***/ }),
/* 8 */
/***/ (function(module, exports) {
Object.defineProperty(exports, "__esModule", {
value: true
});
/**
* Type of default actions supported by metrics
*
* @module ActionTypes
* @internal
*/
var ActionTypes = {
PAGE_VIEW: "pageView", // request page view track
TRACK: "track" // request custom link track
};
exports.default = ActionTypes;
/***/ }),
/* 9 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Metrics = undefined;
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; };
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
exports.isMetrics = isMetrics;
exports.default = createMetrics;
var _eventemitter = __webpack_require__(28);
var _eventemitter2 = _interopRequireDefault(_eventemitter);
var _querystring = __webpack_require__(35);
var _querystring2 = _interopRequireDefault(_querystring);
var _ExecutionEnvironment = __webpack_require__(4);
var _invariant = __webpack_require__(1);
var _invariant2 = _interopRequireDefault(_invariant);
var _warning = __webpack_require__(3);
var _warning2 = _interopRequireDefault(_warning);
var _ActionTypes = __webpack_require__(8);
var _ActionTypes2 = _interopRequireDefault(_ActionTypes);
var _createService = __webpack_require__(16);
var _createService2 = _interopRequireDefault(_createService);
var _extractApis = __webpack_require__(11);
var _extractApis2 = _interopRequireDefault(_extractApis);
var _isPromise = __webpack_require__(18);
var _isPromise2 = _interopRequireDefault(_isPromise);
var _useTrackBindingPlugin = __webpack_require__(10);
var _useTrackBindingPlugin2 = _interopRequireDefault(_useTrackBindingPlugin);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var qs = _ExecutionEnvironment.canUseDOM ? _querystring2.default.decode(window.location.search.substr(1)) : {};
var defaults = {
pageViewEvent: "pageLoad",
pageDefaults: function pageDefaults() {
return {};
},
requestTimeout: 15 * 1000
};
var Transaction = function () {
function Transaction() {
_classCallCheck(this, Transaction);
this.pvTransactions = {};
this.transactionId = 0;
}
_createClass(Transaction, [{
key: "create",
value: function create() {
return ++this.transactionId;
}
}, {
key: "current",
value: function current() {
return this.transactionId;
}
}, {
key: "get",
value: function get(tId) {
return this.pvTransactions[tId];
}
}, {
key: "set",
value: function set(tId, value) {
this.pvTransactions[tId] = value;
}
}, {
key: "remove",
value: function remove(tId) {
if (tId && this.pvTransactions[tId]) {
delete this.pvTransactions[tId];
}
}
}, {
key: "keys",
value: function keys() {
return Object.keys(this.pvTransactions);
}
}]);
return Transaction;
}();
var Metrics = exports.Metrics = function (_EventEmitter) {
_inherits(Metrics, _EventEmitter);
function Metrics() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, Metrics);
if (!options.vendors) {
throw new Error("'vendors' option is required.");
}
var _this = _possibleConstructorReturn(this, (Metrics.__proto__ || Object.getPrototypeOf(Metrics)).call(this));
_this.enabled = options.enabled !== false;
// undocumented option for unit test.
_this.canUseDOM = options.canUseDOM !== undefined ? !!options.canUseDOM : _ExecutionEnvironment.canUseDOM;
if (!_this.canUseDOM) {
_this.enabled = false;
}
_this.debug = !!options.debug || qs.metrics_debug === "true";
_this.customParams = options.customParams || {};
_this.pageDefaults = options.pageDefaults || defaults.pageDefaults;
_this.pageViewEvent = options.pageViewEvent || defaults.pageViewEvent;
_this.requestTimeout = options.requestTimeout || defaults.requestTimeout;
_this.cancelOnNext = options.cancelOnNext !== undefined ? !!options.cancelOnNext : true;
_this.vendors = Array.isArray(options.vendors) ? options.vendors : [options.vendors];
_this.services = _this.vendors.map(function (vendor) {
return (0, _createService2.default)(vendor);
});
_this.apiList = (0, _extractApis2.default)(_this.services.map(function (service) {
return service.apis;
}));
_this.transaction = new Transaction();
_this.routeState = {};
_this.apiImpl = _this.apiList.reduce(function (impl, api) {
impl[api] = function () {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _this._prepareTrack.apply(_this, [api].concat(args));
};
return impl;
}, {});
Object.freeze(_this.apiImpl);
return _this;
}
_createClass(Metrics, [{
key: "listen",
value: function listen(type, callback) {
var _this2 = this;
// if type is not specified, listen for all the apis.
if (typeof type === "function") {
callback = type;
type = null;
}
if (type) {
this.on(type, callback);
} else {
this.apiList.forEach(function (api) {
_this2.on(api, callback);
});
}
return function () {
if (type) {
_this2.removeListener(type, callback);
} else {
_this2.apiList.forEach(function (api) {
_this2.removeListener(api, callback);
});
}
};
}
}, {
key: "setRouteState",
value: function setRouteState(state) {
this._cancelPreviousPromiseIfPending();
this.routeState = state;
}
/* eslint-disable consistent-return */
}, {
key: "useTrackBinding",
value: function useTrackBinding(rootElement, attributePrefix) {
if (!this.enabled) {
return;
}
// if 'false' is passed as first param, detach listeners
if (rootElement === false) {
this._removeTrackBindingListener();
return;
}
(0, _invariant2.default)(typeof this.api.track === "function", "Metrics 'track' method needs to be defined for declarative tracking.");
if (this._trackBindingListener) {
this._removeTrackBindingListener();
}
this._trackBindingListener = (0, _useTrackBindingPlugin2.default)({
callback: this._handleClick.bind(this),
rootElement: rootElement,
attributePrefix: attributePrefix
});
return this._removeTrackBindingListener.bind(this);
}
}, {
key: "destroy",
value: function destroy() {
this._removeListeners();
this._removeTrackBindingListener();
}
}, {
key: "_callServices",
/**
* @method _callServices
* @param type
* @param promise
* @returns {Promise.<T>}
* @private
*/
value: function _callServices(type, promise) {
var _this3 = this;
return promise.then(function (params) {
params = params || [];
var results = [];
var services = _this3.services;
var requestTimeout = _this3.requestTimeout;
function isCompleted() {
return results.length === services.length;
}
function clearTimer(timer) {
if (timer) {
clearTimeout(timer);
timer = null;
}
}
return new Promise(function (resolve) {
function process(result) {
if (this.isTimeout) {
return;
}
this.isTimeout = true;
clearTimer(this.timer);
results.push(result);
if (isCompleted()) {
resolve(results);
}
}
services.map(function (service) {
var apis = service.apis,
name = service.name;
var apiExists = apis && apis[type];
if (apiExists) {
(0, _warning2.default)(typeof apis[type] === "function", "'" + type + "'" + (name ? "(" + name + " Service)" : "") + " is not a function");
}
var requestPromise = apiExists && typeof apis[type] === "function" ? apis[type].apply(apis, _toConsumableArray(params)) : undefined;
if (!(0, _isPromise2.default)(requestPromise)) {
requestPromise = Promise.resolve(requestPromise);
}
requestPromise.isTimeout = false;
requestPromise.timer = setTimeout(process.bind(requestPromise), requestTimeout, {
name: name,
params: params,
error: new Error("Request time out after " + requestTimeout + " ms."),
status: "failure"
});
return requestPromise.then(function (response) {
return {
name: name,
params: params,
response: response,
status: "success"
};
}).catch(function (error) {
return {
name: name,
params: params,
error: error,
status: "failure"
};
}).then(process.bind(requestPromise));
});
});
});
}
/**
* Cancels page view promise if it's still pending while the route has changed.
*
* @method _cancelPreviousPromiseIfPending
* @private
*/
}, {
key: "_cancelPreviousPromiseIfPending",
value: function _cancelPreviousPromiseIfPending() {
var _this4 = this;
this.routeState = {};
this.transaction.keys().forEach(function (tId) {
var entry = _this4.transaction.get(tId);
if (entry && entry.cancelOnNext) {
entry.shouldCancel = true;
}
});
}
/**
* @method _createTransaction
* @param args
* @private
*/
}, {
key: "_createTransaction",
value: function _createTransaction(args) {
var tId = this.transaction.current();
var cancelOnNext = this.cancelOnNext;
this.transaction.set(tId, {
promise: args[0],
cancelOnNext: cancelOnNext
});
args.push(tId);
}
/**
* @method _clearTransaction
* @param tId
* @private
*/
}, {
key: "_clearTransaction",
value: function _clearTransaction(tId) {
this.transaction.remove(tId);
}
/**
* @method _doTrack
* @param type
* @param promise
* @param tId
* @private
*/
}, {
key: "_doTrack",
value: function _doTrack(type, promise, tId) {
promise = this._callServices(type, promise);
var dispatchEvent = function (status, response, error) {
var eventFacade = {
type: type,
status: status
};
if (response) {
eventFacade.response = response;
} else if (error) {
eventFacade.error = error;
}
if (tId) {
eventFacade.transactionId = tId;
this._clearTransaction(tId);
}
this.emit(type, eventFacade);
if (this.debug) {
console.log("track result", eventFacade);
}
}.bind(this);
promise.then(function (response) {
dispatchEvent(response.every(function (item) {
return item.status === "success";
}) ? "success" : "failure", response);
}).catch(function (error) {
dispatchEvent("failure", null, error);
});
}
/**
* Returns the default tracking data provided by a helper object.
*
* @method __getDefaultData
* @return {Object}
* @private
*/
}, {
key: "_getDefaultData",
value: function _getDefaultData(state) {
return this.pageDefaults(state);
}
/**
* Returns a merged data between the host passed object and the default tracking data provided by a helper object.
*
* @method __mergeWith
* @return {Object}
* @private
*/
}, {
key: "_mergeWith",
value: function _mergeWith(data, state) {
return Object.assign({}, this._getDefaultData(state), this.customParams, data);
}
/**
* Checks if this promise should be cancelled by rejecting it before it's sent to the facade.
*
* @method __addCancelHook
* @param {Promise} promise
* @returns {Promise}
* @private
*/
}, {
key: "_addCancelHook",
value: function _addCancelHook(promise) {
var _this5 = this;
var tId = this.transaction.create();
return promise.then(function (data) {
return _this5.transaction.get(tId).shouldCancel ? Promise.reject(new Error("Page view cancelled")) : data;
});
}
/**
* Modify the data to include 'eventName' before it's sent to the facade.
*
* @method __addEventNameToPromise
* @param {String} eventName
* @param {Promise} promise
* @param {boolean} shouldMerge
* @returns {Promise}
* @private
*/
}, {
key: "_addEventNameToPromise",
value: function _addEventNameToPromise(eventName, promise, shouldMerge) {
return promise.then(function (state, data) {
data = [shouldMerge ? this._mergeWith(data, state) : data];
data.unshift(eventName);
return data;
}.bind(this, this.routeState));
}
/**
* Run checks to the arguments passed to 'pageView' and 'track', set default page view eventName if it's not provided.
* Also merges the default data with the passed pageView data, and optionally for track data if a flag is set.
*
* @method __inspectArguments
* @param {String} type
* @param args
* @returns {Array}
* @private
*/
}, {
key: "_inspectArguments",
value: function _inspectArguments(type) {
for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
args[_key2 - 1] = arguments[_key2];
}
var shouldMerge = true;
if (type !== _ActionTypes2.default.PAGE_VIEW) {
// don't merge `pageDefaults` with track params unless it's explicitly requested by the third argument.
shouldMerge = false;
if (type === _ActionTypes2.default.TRACK) {
(0, _invariant2.default)(typeof args[0] === "string", "Metrics 'track' method requires 'eventName' string as the first argument and object or promise as the second argument.");
}
// this might be confusing but for now, use the last argument as a flag for merge when it's boolean.
if (args.length >= 3 && typeof args[args.length - 1] === "boolean") {
shouldMerge = args[args.length - 1];
}
}
// set default page view event name when missing.
var _args = args,
_args2 = _slicedToArray(_args, 2),
eventName = _args2[0],
params = _args2[1];
if (!params && typeof eventName !== "string") {
params = eventName;
eventName = type === _ActionTypes2.default.PAGE_VIEW ? this.pageViewEvent : null;
}
// make sure `params` is a promise.
if (!(0, _isPromise2.default)(params)) {
params = Promise.resolve(params);
}
// add cancel hook so that it can be cancelled(rejected) if the promise is still pending when the route changes.
if (type === _ActionTypes2.default.PAGE_VIEW) {
params = this._addCancelHook(params);
}
// PAGE_VIEW or TRACK should always have `eventName`.
if (eventName) {
params = this._addEventNameToPromise(eventName, params, shouldMerge);
}
args = [type, params];
if (type === _ActionTypes2.default.PAGE_VIEW) {
this._createTransaction(args);
}
return args;
}
/**
* @method _prepareTrack
* @param type
* @param args
* @private
*/
}, {
key: "_prepareTrack",
value: function _prepareTrack(type) {
for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
args[_key3 - 1] = arguments[_key3];
}
if (!this.enabled) {
return;
}
args = this._inspectArguments.apply(this, [type].concat(_toConsumableArray(args)));
this._doTrack.apply(this, _toConsumableArray(args));
}
/**
* A click handler to perform custom link tracking, any element with 'metrics-*' attribute will be tracked.
*
* @method _handleClick
* @param {Object} params
* @private
*/
}, {
key: "_handleClick",
value: function _handleClick() {
var _api;
(_api = this.api).track.apply(_api, arguments);
}
}, {
key: "_removeListeners",
value: function _removeListeners() {
this.removeAllListeners();
}
}, {
key: "_removeTrackBindingListener",
value: function _removeTrackBindingListener() {
if (this._trackBindingListener) {
this._trackBindingListener.remove();
this._trackBindingListener = null;
}
}
}, {
key: "api",
get: function get() {
return this.apiImpl;
}
}]);
return Metrics;
}(_eventemitter2.default);
function isMetrics(value) {
return value && typeof value.listen === "function" && typeof value.setRouteState === "function" && typeof value.useTrackBinding === "function" && typeof value.destroy === "function" && _typeof(value.api) === "object";
}
function createMetrics(options) {
var metrics = new Metrics(options);
return {
listen: metrics.listen.bind(metrics),
setRouteState: metrics.setRouteState.bind(metrics),
useTrackBinding: metrics.useTrackBinding.bind(metrics),
destroy: metrics.destroy.bind(metrics),
get enabled() {
return metrics.enabled;
},
get api() {
return metrics.api;
}
};
}
/***/ }),
/* 10 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TrackBindingPlugin = undefined;
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
exports.default = useTrackBindingPlugin;
var _EventListener = __webpack_require__(29);
var _EventListener2 = _interopRequireDefault(_EventListener);
var _attr2obj = __webpack_require__(17);
var _attr2obj2 = _interopRequireDefault(_attr2obj);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function isLeftClickEvent(event) {
return event.button === 0;
}
function isModifiedEvent(event) {
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
}
var TrackBindingPlugin = exports.TrackBindingPlugin = function () {
function TrackBindingPlugin() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$attributePrefix = _ref.attributePrefix,
attributePrefix = _ref$attributePrefix === undefined ? "data-metrics" : _ref$attributePrefix,
_ref$traverseParent = _ref.traverseParent,
traverseParent = _ref$traverseParent === undefined ? false : _ref$traverseParent;
_classCallCheck(this, TrackBindingPlugin);
this._attributePrefix = attributePrefix;
this._traverseParent = traverseParent;
}
_createClass(TrackBindingPlugin, [{
key: "listen",
value: function listen(callback) {
var rootElement = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document.body;
if (typeof callback !== "function") {
throw new Error("callback needs to be a function.");
}
if (rootElement && rootElement.nodeType !== 1) {
throw new Error("rootElement needs to be a valid node element.");
}
if (this._clickHandler) {
this.remove();
}
this._rootElement = rootElement;
this._clickHandler = _EventListener2.default.listen(rootElement, "click", this._handleClick.bind(this, callback));
return {
target: this,
remove: this.remove.bind(this)
};
}
}, {
key: "remove",
value: function remove() {
if (this._clickHandler) {
this._clickHandler.remove();
this._clickHandler = null;
}
}
/**
* A click handler to perform custom link tracking, any element with 'metrics-*' attribute will be tracked.
*
* @method _handleClick
* @param {Object} event
* @private
*/
}, {
key: "_handleClick",
value: function _handleClick(callback, event) {
if (isModifiedEvent(event) || !isLeftClickEvent(event)) {
return;
}
var elem = event.target || event.srcElement;
var dataset = this._getData(elem);
if (this._traverseParent) {
var rootElement = this._rootElement;
while (elem !== rootElement) {
elem = elem.parentElement || elem.parentNode;
dataset = _extends({}, this._getData(elem), dataset);
}
}
if (!Object.keys(dataset).length) {
return;
}
var eventName = dataset && dataset.eventName;
var mergePagedefaults = dataset && dataset.mergePagedefaults;
delete dataset.mergePagedefaults;
if (eventName) {
delete dataset.eventName;
callback(eventName, dataset, mergePagedefaults === "true");
}
}
}, {
key: "_getData",
value: function _getData(elem) {
return (0, _attr2obj2.default)(elem, this._attributePrefix);
}
}]);
return TrackBindingPlugin;
}();
function useTrackBindingPlugin(_ref2) {
var callback = _ref2.callback,
rootElement = _ref2.rootElement,
attributePrefix = _ref2.attributePrefix,
traverseParent = _ref2.traverseParent;
var trackBindingPlugin = new TrackBindingPlugin({
attributePrefix: attributePrefix,
traverseParent: traverseParent
});
return trackBindingPlugin.listen(callback, rootElement);
}
/***/ }),
/* 11 */
/***/ (function(module, exports) {
Object.defineProperty(exports, "__esModule", {
value: true
});
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; };
exports.filterKeysByType = filterKeysByType;
exports.aggregateApisByType = aggregateApisByType;
exports.default = extractApis;
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var EXCLUDES = ["constructor"].concat(Object.getOwnPropertyNames(Object.getPrototypeOf({})));
function filterKeysByType(obj) {
var total = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "function";
return Object.getOwnPropertyNames(obj).filter(function (key) {
return total.indexOf(key) === -1 && EXCLUDES.indexOf(key) === -1 && key.indexOf("_") !== 0 && // consider it's private
obj.hasOwnProperty(key) && _typeof(obj[key]) === type;
});
}
function aggregateApisByType(obj) {
var total = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
var keys = [];
while (obj !== null) {
// eslint-disable-line no-eq-null
var arr = filterKeysByType(obj, total);
keys.push.apply(keys, _toConsumableArray(arr));
obj = Object.getPrototypeOf(obj);
}
return keys;
}
// extracts lists of methods from each service object.
function extractApis(services) {
services = Array.isArray(services) ? services : [services];
var apis = services.reduce(function (total, service) {
var obj = service.constructor === Object ? service : Object.getPrototypeOf(service);
var keys = aggregateApisByType(obj, total);
total.push.apply(total, _toConsumableArray(keys));
return total;
}, []);
return apis;
}
/***/ }),
/* 12 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
exports.getMountedInstances = getMountedInstances;
exports.clearMountedInstances = clearMountedInstances;
exports.default = useMetrics;
var _react = __webpack_require__(7);
var _react2 = _interopRequireDefault(_react);
var _ExecutionEnvironment = __webpack_require__(4);
var _hoistNonReactStatics = __webpack_require__(13);
var _hoistNonReactStatics2 = _interopRequireDefault(_hoistNonReactStatics);
var _PropTypes = __webpack_require__(2);
var _PropTypes2 = _interopRequireDefault(_PropTypes);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var mountedInstances = [];
function getMountedInstances() {
return mountedInstances;
}
// convenient method for unit test
function clearMountedInstances() {
mountedInstances.length = 0;
}
function getDisplayName(Comp) {
return Comp.displayName || Comp.name || "Component";
}
function wrap(ComposedComponent) {
var _class, _temp;
var Metrics = (_temp = _class = function (_Component) {
_inherits(Metrics, _Component);
function Metrics() {
_classCallCheck(this, Metrics);
return _possibleConstructorReturn(this, (Metrics.__proto__ || Object.getPrototypeOf(Metrics)).apply(this, arguments));
}
_createClass(Metrics, [{
key: "componentWillMount",
value: function componentWillMount() {
if (!_ExecutionEnvironment.canUseDOM) {
return;
}
mountedInstances.push(Metrics);
}
// context unit test fails w/o this, why??
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
var index = mountedInstances.indexOf(this);
mountedInstances.splice(index, 1);
}
}, {
key: "render",
value: function render() {
return _react2.default.createElement(ComposedComponent, _extends({}, this.props, this.context));
}
}]);
return Metrics;
}(_react.Component), _class.displayName = "Metrics(" + getDisplayName(ComposedComponent) + ")", _class.contextTypes = {
metrics: _PropTypes2.default.metrics
}, _temp);
return (0, _hoistNonReactStatics2.default)(Metrics, ComposedComponent);
}
function useMetrics() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
if (typeof args[0] === "function") {
return wrap.apply(undefined, args);
}
return function (target) {
return wrap.apply(undefined, [target].concat(args));
};
}
/***/ }),
/* 13 */
/***/ (function(module, exports) {
/**
* Copyright 2015, Yahoo! Inc.
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
'use strict';
var REACT_STATICS = {
childContextTypes: true,
contextTypes: true,
defaultProps: true,
displayName: true,
getDefaultProps: true,
mixins: true,
propTypes: true,
type: true
};
var KNOWN_STATICS = {
name: true,
length: true,
prototype: true,
caller: true,
arguments: true,
arity: true
};
var isGetOwnPropertySymbolsAvailable = typeof Object.getOwnPropertySymbols === 'function';
module.exports = function hoistNonReactStatics(targetComponent, sourceComponent, customStatics) {
if (typeof sourceComponent !== 'string') { // don't hoist over string (html) components
var keys = Object.getOwnPropertyNames(sourceComponent);
/* istanbul ignore else */
if (isGetOwnPropertySymbolsAvailable) {
keys = keys.concat(Object.getOwnPropertySymbols(sourceComponent));
}
for (var i = 0; i < keys.length; ++i) {
if (!REACT_STATICS[keys[i]] && !KNOWN_STATICS[keys[i]] && (!customStatics || !customStatics[keys[i]])) {
try {
targetComponent[keys[i]] = sourceComponent[keys[i]];
} catch (error) {
}
}
}
}
return targetComponent;
};
/***/ }),
/* 14 */
/***/ (function(module, exports) {
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
module.exports = ReactPropTypesSecret;
/***/ }),
/* 15 */
/***/ (function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_15__;
/***/ }),
/* 16 */
/***/ (function(module, exports, __webpack_require__) {
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.defaultService = undefined;
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; };
var _defaultService;
exports.default = createService;
var _ActionTypes = __webpack_require__(8);
var _ActionTypes2 = _interopRequireDefault(_ActionTypes);
var _extractApis = __webpack_require__(11);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /* eslint-disable no-empty */
var noop = function noop() {};
function isService(obj) {
var functionProps = (0, _extractApis.aggregateApisByType)(obj);
return functionProps.length > 0;
}
var defaultService = exports.defaultService = (_defaultService = {}, _defineProperty(_defaultService, _ActionTypes2.default.PAGE_VIEW, noop), _defineProperty(_defaultService, _ActionTypes2.default.TRACK, noop), _defaultService);
function createService() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var api = options.api;
var instance = defaultServi