UNPKG

react-metrics

Version:

An analytics library for React.js

1,427 lines (1,143 loc) 117 kB
(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