diff --git a/examples/browser/app.jsx b/examples/browser/app.jsx index 9e901ff..3e250ea 100644 --- a/examples/browser/app.jsx +++ b/examples/browser/app.jsx @@ -1,12 +1,13 @@ var React = require('react'); var ReactDOM = require('react-dom'); +var createReactClass = require('create-react-class'); var Experiment = require("../../lib/Experiment"); var Variant = require("../../lib/Variant"); var experimentDebugger = require("../../lib/debugger"); experimentDebugger.enable(); -var App = React.createClass({ +var App = createReactClass({ render() { return

Experiment 1

diff --git a/examples/isomorphic/Component.jsx b/examples/isomorphic/Component.jsx index 4c041cf..a686466 100644 --- a/examples/isomorphic/Component.jsx +++ b/examples/isomorphic/Component.jsx @@ -1,8 +1,9 @@ var React = require("react"); +var createReactClass = require('create-react-class'); var Experiment = require("../../lib/Experiment"); var Variant = require("../../lib/Variant"); -module.exports = React.createClass({ +module.exports = createReactClass({ propTypes: { userIdentifier: React.PropTypes.string.isRequired }, diff --git a/lib/CoreExperiment.js b/lib/CoreExperiment.js index 500ee73..ea7669d 100644 --- a/lib/CoreExperiment.js +++ b/lib/CoreExperiment.js @@ -53,7 +53,6 @@ var CoreExperiment = function (_Component) { var children = {}; _react2.default.Children.forEach(props.children, function (element) { if (!_react2.default.isValidElement(element) || element.type.displayName !== "Pushtell.Variant") { - console.log(element.type); var error = new Error("Pushtell Experiment children must be Pushtell Variant components."); error.type = "PUSHTELL_INVALID_CHILD"; throw error; diff --git a/lib/Experiment.js b/lib/Experiment.js index 54f0d74..cd95d67 100644 --- a/lib/Experiment.js +++ b/lib/Experiment.js @@ -83,26 +83,47 @@ var Experiment = function (_Component) { return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Experiment.__proto__ || Object.getPrototypeOf(Experiment)).call.apply(_ref, [this].concat(args))), _this), _this.win = function () { _emitter2.default.emitWin(_this.props.name); - }, _this.getRandomValue = function () { + }, _this.getSelectedVariant = function () { + /* + Choosing a weighted variant: + For C, A, B with weights 2, 4, 8 + variants = A, B, C + weights = 4, 8, 2 + weightSum = 14 + weightedIndex = 9 + AAAABBBBBBBBCC + ========^ + Select B + */ + + // Sorted array of the variant names, example: ["A", "B", "C"] var variants = _emitter2.default.getSortedVariants(_this.props.name); + // Array of the variant weights, also sorted by variant name. For example, if + // variant C had weight 2, variant A had weight 4, and variant B had weight 8 + // return [4, 8, 2] to correspond with ["A", "B", "C"] var weights = _emitter2.default.getSortedVariantWeights(_this.props.name); + // Sum the weights var weightSum = weights.reduce(function (a, b) { return a + b; }, 0); + // A random number between 0 and weightSum var weightedIndex = typeof _this.props.userIdentifier === 'string' ? Math.abs((0, _crc2.default)(_this.props.userIdentifier) % weightSum) : Math.floor(Math.random() * weightSum); - var randomValue = variants[variants.length - 1]; + // Iterate through the sorted weights, and deduct each from the weightedIndex. + // If weightedIndex drops < 0, select the variant. If weightedIndex does not + // drop < 0, default to the last variant in the array that is initially assigned. + var selectedVariant = variants[variants.length - 1]; for (var index = 0; index < weights.length; index++) { weightedIndex -= weights[index]; if (weightedIndex < 0) { - randomValue = variants[index]; + selectedVariant = variants[index]; break; } } - _emitter2.default.setActiveVariant(_this.props.name, randomValue); - return randomValue; + _emitter2.default.setActiveVariant(_this.props.name, selectedVariant); + return selectedVariant; }, _this.getLocalStorageValue = function () { if (typeof _this.props.userIdentifier === "string") { - return _this.getRandomValue(); + return _this.getSelectedVariant(); } var activeValue = _emitter2.default.getActiveVariant(_this.props.name); if (typeof activeValue === "string") { @@ -117,7 +138,7 @@ var Experiment = function (_Component) { _emitter2.default.setActiveVariant(_this.props.name, _this.props.defaultVariantName); return _this.props.defaultVariantName; } - return _this.getRandomValue(); + return _this.getSelectedVariant(); }, _temp), _possibleConstructorReturn(_this, _ret); } diff --git a/lib/debugger.js b/lib/debugger.js index d07bb92..c593051 100644 --- a/lib/debugger.js +++ b/lib/debugger.js @@ -8,6 +8,10 @@ var _reactDom = require('react-dom'); var _reactDom2 = _interopRequireDefault(_reactDom); +var _createReactClass = require('create-react-class'); + +var _createReactClass2 = _interopRequireDefault(_createReactClass); + var _emitter = require('./emitter'); var _emitter2 = _interopRequireDefault(_emitter); @@ -94,7 +98,7 @@ if (process.env.NODE_ENV === "production" || !_ExecutionEnvironment.canUseDOM) { var style = null; - var Debugger = _react2.default.createClass({ + var Debugger = (0, _createReactClass2.default)({ displayName: "Pushtell.Debugger", getInitialState: function getInitialState() { return { diff --git a/src/debugger.jsx b/src/debugger.jsx index ffc00ab..badb5c3 100644 --- a/src/debugger.jsx +++ b/src/debugger.jsx @@ -1,5 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import createReactClass from 'create-react-class'; import emitter from "./emitter"; import {canUseDOM} from 'fbjs/lib/ExecutionEnvironment'; @@ -78,7 +79,7 @@ if(process.env.NODE_ENV === "production" || !canUseDOM) { style = null; } } - const Debugger = React.createClass({ + const Debugger = createReactClass({ displayName: "Pushtell.Debugger", getInitialState(){ return { diff --git a/standalone.min.js b/standalone.min.js index f539076..ec39035 100644 --- a/standalone.min.js +++ b/standalone.min.js @@ -48,11 +48,11 @@ module.exports = { Experiment: __webpack_require__(1), - Variant: __webpack_require__(21), - emitter: __webpack_require__(14), - experimentDebugger: __webpack_require__(24), - mixpanelHelper: __webpack_require__(28), - segmentHelper: __webpack_require__(30) + Variant: __webpack_require__(22), + emitter: __webpack_require__(15), + experimentDebugger: __webpack_require__(25), + mixpanelHelper: __webpack_require__(32), + segmentHelper: __webpack_require__(34) }; /***/ }), @@ -86,15 +86,15 @@ var _propTypes2 = _interopRequireDefault(_propTypes); - var _CoreExperiment = __webpack_require__(13); + var _CoreExperiment = __webpack_require__(14); var _CoreExperiment2 = _interopRequireDefault(_CoreExperiment); - var _emitter = __webpack_require__(14); + var _emitter = __webpack_require__(15); var _emitter2 = _interopRequireDefault(_emitter); - var _crc = __webpack_require__(23); + var _crc = __webpack_require__(24); var _crc2 = _interopRequireDefault(_crc); @@ -153,26 +153,47 @@ return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = Experiment.__proto__ || Object.getPrototypeOf(Experiment)).call.apply(_ref, [this].concat(args))), _this), _this.win = function () { _emitter2.default.emitWin(_this.props.name); - }, _this.getRandomValue = function () { + }, _this.getSelectedVariant = function () { + /* + Choosing a weighted variant: + For C, A, B with weights 2, 4, 8 + variants = A, B, C + weights = 4, 8, 2 + weightSum = 14 + weightedIndex = 9 + AAAABBBBBBBBCC + ========^ + Select B + */ + + // Sorted array of the variant names, example: ["A", "B", "C"] var variants = _emitter2.default.getSortedVariants(_this.props.name); + // Array of the variant weights, also sorted by variant name. For example, if + // variant C had weight 2, variant A had weight 4, and variant B had weight 8 + // return [4, 8, 2] to correspond with ["A", "B", "C"] var weights = _emitter2.default.getSortedVariantWeights(_this.props.name); + // Sum the weights var weightSum = weights.reduce(function (a, b) { return a + b; }, 0); + // A random number between 0 and weightSum var weightedIndex = typeof _this.props.userIdentifier === 'string' ? Math.abs((0, _crc2.default)(_this.props.userIdentifier) % weightSum) : Math.floor(Math.random() * weightSum); - var randomValue = variants[variants.length - 1]; + // Iterate through the sorted weights, and deduct each from the weightedIndex. + // If weightedIndex drops < 0, select the variant. If weightedIndex does not + // drop < 0, default to the last variant in the array that is initially assigned. + var selectedVariant = variants[variants.length - 1]; for (var index = 0; index < weights.length; index++) { weightedIndex -= weights[index]; if (weightedIndex < 0) { - randomValue = variants[index]; + selectedVariant = variants[index]; break; } } - _emitter2.default.setActiveVariant(_this.props.name, randomValue); - return randomValue; + _emitter2.default.setActiveVariant(_this.props.name, selectedVariant); + return selectedVariant; }, _this.getLocalStorageValue = function () { if (typeof _this.props.userIdentifier === "string") { - return _this.getRandomValue(); + return _this.getSelectedVariant(); } var activeValue = _emitter2.default.getActiveVariant(_this.props.name); if (typeof activeValue === "string") { @@ -187,7 +208,7 @@ _emitter2.default.setActiveVariant(_this.props.name, _this.props.defaultVariantName); return _this.props.defaultVariantName; } - return _this.getRandomValue(); + return _this.getSelectedVariant(); }, _temp), _possibleConstructorReturn(_this, _ret); } @@ -221,12 +242,10 @@ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) {/** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. + * Copyright (c) 2013-present, Facebook, Inc. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ if (process.env.NODE_ENV !== 'production') { @@ -248,7 +267,7 @@ } else { // By explicitly using `prop-types` you are opting into new production behavior. // http://fb.me/prop-types-in-prod - module.exports = __webpack_require__(12)(); + module.exports = __webpack_require__(13)(); } /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5))) @@ -448,12 +467,10 @@ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) {/** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. + * Copyright (c) 2013-present, Facebook, Inc. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ 'use strict'; @@ -461,9 +478,10 @@ var emptyFunction = __webpack_require__(7); var invariant = __webpack_require__(8); var warning = __webpack_require__(9); + var assign = __webpack_require__(10); - var ReactPropTypesSecret = __webpack_require__(10); - var checkPropTypes = __webpack_require__(11); + var ReactPropTypesSecret = __webpack_require__(11); + var checkPropTypes = __webpack_require__(12); module.exports = function(isValidElement, throwOnDirectAccess) { /* global Symbol */ @@ -559,7 +577,8 @@ objectOf: createObjectOfTypeChecker, oneOf: createEnumTypeChecker, oneOfType: createUnionTypeChecker, - shape: createShapeTypeChecker + shape: createShapeTypeChecker, + exact: createStrictShapeTypeChecker, }; /** @@ -774,7 +793,7 @@ if (typeof checker !== 'function') { warning( false, - 'Invalid argument supplid to oneOfType. Expected an array of check functions, but ' + + 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' + 'received %s at index %s.', getPostfixForTypeWarning(checker), i @@ -828,6 +847,36 @@ return createChainableTypeChecker(validate); } + function createStrictShapeTypeChecker(shapeTypes) { + function validate(props, propName, componentName, location, propFullName) { + var propValue = props[propName]; + var propType = getPropType(propValue); + if (propType !== 'object') { + return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); + } + // We need to check all keys in case some are required but missing from + // props. + var allKeys = assign({}, props[propName], shapeTypes); + for (var key in allKeys) { + var checker = shapeTypes[key]; + if (!checker) { + return new PropTypeError( + 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' + + '\nBad object: ' + JSON.stringify(props[propName], null, ' ') + + '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ') + ); + } + var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); + if (error) { + return error; + } + } + return null; + } + + return createChainableTypeChecker(validate); + } + function isNode(propValue) { switch (typeof propValue) { case 'number': @@ -970,11 +1019,9 @@ /** * Copyright (c) 2013-present, Facebook, Inc. - * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. * * */ @@ -1011,11 +1058,9 @@ /* WEBPACK VAR INJECTION */(function(process) {/** * Copyright (c) 2013-present, Facebook, Inc. - * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. * */ @@ -1071,12 +1116,10 @@ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) {/** - * Copyright 2014-2015, Facebook, Inc. - * All rights reserved. + * Copyright (c) 2014-present, Facebook, Inc. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. * */ @@ -1094,45 +1137,43 @@ var warning = emptyFunction; if (process.env.NODE_ENV !== 'production') { - (function () { - 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) {} - }; + 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]; + } - warning = function warning(condition, format) { - if (format === undefined) { - throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); - } + 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) {} + }; - if (format.indexOf('Failed Composite propType: ') === 0) { - return; // Ignore CompositeComponent proptype check. - } + warning = function warning(condition, format) { + if (format === undefined) { + throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); + } - if (!condition) { - for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { - args[_key2 - 2] = arguments[_key2]; - } + if (format.indexOf('Failed Composite propType: ') === 0) { + return; // Ignore CompositeComponent proptype check. + } - printWarning.apply(undefined, [format].concat(args)); + 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; @@ -1140,15 +1181,109 @@ /***/ }), /* 10 */ +/***/ (function(module, exports) { + + /* + object-assign + (c) Sindre Sorhus + @license MIT + */ + + 'use strict'; + /* eslint-disable no-unused-vars */ + var getOwnPropertySymbols = Object.getOwnPropertySymbols; + var hasOwnProperty = Object.prototype.hasOwnProperty; + var propIsEnumerable = Object.prototype.propertyIsEnumerable; + + function toObject(val) { + if (val === null || val === undefined) { + throw new TypeError('Object.assign cannot be called with null or undefined'); + } + + return Object(val); + } + + function shouldUseNative() { + try { + if (!Object.assign) { + return false; + } + + // Detect buggy property enumeration order in older V8 versions. + + // https://bugs.chromium.org/p/v8/issues/detail?id=4118 + var test1 = new String('abc'); // eslint-disable-line no-new-wrappers + test1[5] = 'de'; + if (Object.getOwnPropertyNames(test1)[0] === '5') { + return false; + } + + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test2 = {}; + for (var i = 0; i < 10; i++) { + test2['_' + String.fromCharCode(i)] = i; + } + var order2 = Object.getOwnPropertyNames(test2).map(function (n) { + return test2[n]; + }); + if (order2.join('') !== '0123456789') { + return false; + } + + // https://bugs.chromium.org/p/v8/issues/detail?id=3056 + var test3 = {}; + 'abcdefghijklmnopqrst'.split('').forEach(function (letter) { + test3[letter] = letter; + }); + if (Object.keys(Object.assign({}, test3)).join('') !== + 'abcdefghijklmnopqrst') { + return false; + } + + return true; + } catch (err) { + // We don't expect any of the above to throw, but better to be safe. + return false; + } + } + + module.exports = shouldUseNative() ? Object.assign : function (target, source) { + var from; + var to = toObject(target); + var symbols; + + for (var s = 1; s < arguments.length; s++) { + from = Object(arguments[s]); + + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; + } + } + + if (getOwnPropertySymbols) { + symbols = getOwnPropertySymbols(from); + for (var i = 0; i < symbols.length; i++) { + if (propIsEnumerable.call(from, symbols[i])) { + to[symbols[i]] = from[symbols[i]]; + } + } + } + } + + return to; + }; + + +/***/ }), +/* 11 */ /***/ (function(module, exports) { /** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. + * Copyright (c) 2013-present, Facebook, Inc. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ 'use strict'; @@ -1159,16 +1294,14 @@ /***/ }), -/* 11 */ +/* 12 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) {/** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. + * Copyright (c) 2013-present, Facebook, Inc. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. */ 'use strict'; @@ -1176,7 +1309,7 @@ if (process.env.NODE_ENV !== 'production') { var invariant = __webpack_require__(8); var warning = __webpack_require__(9); - var ReactPropTypesSecret = __webpack_require__(10); + var ReactPropTypesSecret = __webpack_require__(11); var loggedTypeFailures = {}; } @@ -1202,7 +1335,7 @@ try { // This is intentionally an invariant that gets caught. It's the same // behavior as without this statement except with a better message. - invariant(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'React.PropTypes.', componentName || 'React class', location, typeSpecName); + invariant(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'the `prop-types` package, but received `%s`.', componentName || 'React class', location, typeSpecName, typeof typeSpecs[typeSpecName]); error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret); } catch (ex) { error = ex; @@ -1227,23 +1360,21 @@ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5))) /***/ }), -/* 12 */ +/* 13 */ /***/ (function(module, exports, __webpack_require__) { /** - * Copyright 2013-present, Facebook, Inc. - * All rights reserved. + * Copyright (c) 2013-present, Facebook, Inc. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * 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__(7); var invariant = __webpack_require__(8); - var ReactPropTypesSecret = __webpack_require__(10); + var ReactPropTypesSecret = __webpack_require__(11); module.exports = function() { function shim(props, propName, componentName, location, propFullName, secret) { @@ -1281,7 +1412,8 @@ objectOf: getShim, oneOf: getShim, oneOfType: getShim, - shape: getShim + shape: getShim, + exact: getShim }; ReactPropTypes.checkPropTypes = emptyFunction; @@ -1292,7 +1424,7 @@ /***/ }), -/* 13 */ +/* 14 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) {'use strict'; @@ -1325,11 +1457,11 @@ var _warning2 = _interopRequireDefault(_warning); - var _emitter = __webpack_require__(14); + var _emitter = __webpack_require__(15); var _emitter2 = _interopRequireDefault(_emitter); - var _Variant = __webpack_require__(21); + var _Variant = __webpack_require__(22); var _Variant2 = _interopRequireDefault(_Variant); @@ -1373,7 +1505,6 @@ var children = {}; _react2.default.Children.forEach(props.children, function (element) { if (!_react2.default.isValidElement(element) || element.type.displayName !== "Pushtell.Variant") { - console.log(element.type); var error = new Error("Pushtell Experiment children must be Pushtell Variant components."); error.type = "PUSHTELL_INVALID_CHILD"; throw error; @@ -1450,16 +1581,16 @@ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5))) /***/ }), -/* 14 */ +/* 15 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {"use strict"; - module.exports = global["emitter"] = __webpack_require__(15); + module.exports = global["emitter"] = __webpack_require__(16); /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }), -/* 15 */ +/* 16 */ /***/ (function(module, exports, __webpack_require__) { 'use strict'; @@ -1468,7 +1599,7 @@ value: true }); - var _fbemitter = __webpack_require__(16); + var _fbemitter = __webpack_require__(17); var values = {}; var experiments = {}; @@ -1670,7 +1801,7 @@ module.exports = exports['default']; /***/ }), -/* 16 */ +/* 17 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -1683,15 +1814,15 @@ */ var fbemitter = { - EventEmitter: __webpack_require__(17), - EmitterSubscription : __webpack_require__(18) + EventEmitter: __webpack_require__(18), + EmitterSubscription : __webpack_require__(19) }; module.exports = fbemitter; /***/ }), -/* 17 */ +/* 18 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) {/** @@ -1710,8 +1841,8 @@ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } - var EmitterSubscription = __webpack_require__(18); - var EventSubscriptionVendor = __webpack_require__(20); + var EmitterSubscription = __webpack_require__(19); + var EventSubscriptionVendor = __webpack_require__(21); var emptyFunction = __webpack_require__(7); var invariant = __webpack_require__(8); @@ -1888,7 +2019,7 @@ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5))) /***/ }), -/* 18 */ +/* 19 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -1909,7 +2040,7 @@ 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 EventSubscription = __webpack_require__(19); + var EventSubscription = __webpack_require__(20); /** * EmitterSubscription represents a subscription with listener and context data. @@ -1941,7 +2072,7 @@ module.exports = EmitterSubscription; /***/ }), -/* 19 */ +/* 20 */ /***/ (function(module, exports) { /** @@ -1995,7 +2126,7 @@ module.exports = EventSubscription; /***/ }), -/* 20 */ +/* 21 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) {/** @@ -2104,16 +2235,16 @@ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5))) /***/ }), -/* 21 */ +/* 22 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {"use strict"; - module.exports = global["Variant"] = __webpack_require__(22); + module.exports = global["Variant"] = __webpack_require__(23); /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }), -/* 22 */ +/* 23 */ /***/ (function(module, exports, __webpack_require__) { 'use strict'; @@ -2176,18 +2307,16 @@ module.exports = exports['default']; /***/ }), -/* 23 */ +/* 24 */ /***/ (function(module, exports) { /* WEBPACK VAR INJECTION */(function(global) {"use strict"; /** * Copyright (c) 2013-present, Facebook, Inc. - * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. * * */ @@ -2211,16 +2340,16 @@ /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }), -/* 24 */ +/* 25 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {"use strict"; - module.exports = global["experimentDebugger"] = __webpack_require__(25); + module.exports = global["experimentDebugger"] = __webpack_require__(26); /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }), -/* 25 */ +/* 26 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(process) {'use strict'; @@ -2229,15 +2358,19 @@ var _react2 = _interopRequireDefault(_react); - var _reactDom = __webpack_require__(26); + var _reactDom = __webpack_require__(27); var _reactDom2 = _interopRequireDefault(_reactDom); - var _emitter = __webpack_require__(14); + var _createReactClass = __webpack_require__(28); + + var _createReactClass2 = _interopRequireDefault(_createReactClass); + + var _emitter = __webpack_require__(15); var _emitter2 = _interopRequireDefault(_emitter); - var _ExecutionEnvironment = __webpack_require__(27); + var _ExecutionEnvironment = __webpack_require__(31); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -2319,7 +2452,7 @@ var style = null; - var Debugger = _react2.default.createClass({ + var Debugger = (0, _createReactClass2.default)({ displayName: "Pushtell.Debugger", getInitialState: function getInitialState() { return { @@ -2435,22 +2568,954 @@ /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5))) /***/ }), -/* 26 */ +/* 27 */ /***/ (function(module, exports) { module.exports = ReactDOM; /***/ }), -/* 27 */ +/* 28 */ +/***/ (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'; + + var React = __webpack_require__(3); + var factory = __webpack_require__(29); + + if (typeof React === 'undefined') { + throw Error( + 'create-react-class could not find the React object. If you are using script tags, ' + + 'make sure that React is being loaded before create-react-class.' + ); + } + + // Hack to grab NoopUpdateQueue from isomorphic React + var ReactNoopUpdateQueue = new React.Component().updater; + + module.exports = factory( + React.Component, + React.isValidElement, + ReactNoopUpdateQueue + ); + + +/***/ }), +/* 29 */ +/***/ (function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * 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 _assign = __webpack_require__(10); + + var emptyObject = __webpack_require__(30); + var _invariant = __webpack_require__(8); + + if (process.env.NODE_ENV !== 'production') { + var warning = __webpack_require__(9); + } + + var MIXINS_KEY = 'mixins'; + + // Helper function to allow the creation of anonymous functions which do not + // have .name set to the name of the variable being assigned to. + function identity(fn) { + return fn; + } + + var ReactPropTypeLocationNames; + if (process.env.NODE_ENV !== 'production') { + ReactPropTypeLocationNames = { + prop: 'prop', + context: 'context', + childContext: 'child context' + }; + } else { + ReactPropTypeLocationNames = {}; + } + + function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) { + /** + * Policies that describe methods in `ReactClassInterface`. + */ + + var injectedMixins = []; + + /** + * Composite components are higher-level components that compose other composite + * or host components. + * + * To create a new type of `ReactClass`, pass a specification of + * your new class to `React.createClass`. The only requirement of your class + * specification is that you implement a `render` method. + * + * var MyComponent = React.createClass({ + * render: function() { + * return
Hello World
; + * } + * }); + * + * The class specification supports a specific protocol of methods that have + * special meaning (e.g. `render`). See `ReactClassInterface` for + * more the comprehensive protocol. Any other properties and methods in the + * class specification will be available on the prototype. + * + * @interface ReactClassInterface + * @internal + */ + var ReactClassInterface = { + /** + * An array of Mixin objects to include when defining your component. + * + * @type {array} + * @optional + */ + mixins: 'DEFINE_MANY', + + /** + * An object containing properties and methods that should be defined on + * the component's constructor instead of its prototype (static methods). + * + * @type {object} + * @optional + */ + statics: 'DEFINE_MANY', + + /** + * Definition of prop types for this component. + * + * @type {object} + * @optional + */ + propTypes: 'DEFINE_MANY', + + /** + * Definition of context types for this component. + * + * @type {object} + * @optional + */ + contextTypes: 'DEFINE_MANY', + + /** + * Definition of context types this component sets for its children. + * + * @type {object} + * @optional + */ + childContextTypes: 'DEFINE_MANY', + + // ==== Definition methods ==== + + /** + * Invoked when the component is mounted. Values in the mapping will be set on + * `this.props` if that prop is not specified (i.e. using an `in` check). + * + * This method is invoked before `getInitialState` and therefore cannot rely + * on `this.state` or use `this.setState`. + * + * @return {object} + * @optional + */ + getDefaultProps: 'DEFINE_MANY_MERGED', + + /** + * Invoked once before the component is mounted. The return value will be used + * as the initial value of `this.state`. + * + * getInitialState: function() { + * return { + * isOn: false, + * fooBaz: new BazFoo() + * } + * } + * + * @return {object} + * @optional + */ + getInitialState: 'DEFINE_MANY_MERGED', + + /** + * @return {object} + * @optional + */ + getChildContext: 'DEFINE_MANY_MERGED', + + /** + * Uses props from `this.props` and state from `this.state` to render the + * structure of the component. + * + * No guarantees are made about when or how often this method is invoked, so + * it must not have side effects. + * + * render: function() { + * var name = this.props.name; + * return
Hello, {name}!
; + * } + * + * @return {ReactComponent} + * @required + */ + render: 'DEFINE_ONCE', + + // ==== Delegate methods ==== + + /** + * Invoked when the component is initially created and about to be mounted. + * This may have side effects, but any external subscriptions or data created + * by this method must be cleaned up in `componentWillUnmount`. + * + * @optional + */ + componentWillMount: 'DEFINE_MANY', + + /** + * Invoked when the component has been mounted and has a DOM representation. + * However, there is no guarantee that the DOM node is in the document. + * + * Use this as an opportunity to operate on the DOM when the component has + * been mounted (initialized and rendered) for the first time. + * + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidMount: 'DEFINE_MANY', + + /** + * Invoked before the component receives new props. + * + * Use this as an opportunity to react to a prop transition by updating the + * state using `this.setState`. Current props are accessed via `this.props`. + * + * componentWillReceiveProps: function(nextProps, nextContext) { + * this.setState({ + * likesIncreasing: nextProps.likeCount > this.props.likeCount + * }); + * } + * + * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop + * transition may cause a state change, but the opposite is not true. If you + * need it, you are probably looking for `componentWillUpdate`. + * + * @param {object} nextProps + * @optional + */ + componentWillReceiveProps: 'DEFINE_MANY', + + /** + * Invoked while deciding if the component should be updated as a result of + * receiving new props, state and/or context. + * + * Use this as an opportunity to `return false` when you're certain that the + * transition to the new props/state/context will not require a component + * update. + * + * shouldComponentUpdate: function(nextProps, nextState, nextContext) { + * return !equal(nextProps, this.props) || + * !equal(nextState, this.state) || + * !equal(nextContext, this.context); + * } + * + * @param {object} nextProps + * @param {?object} nextState + * @param {?object} nextContext + * @return {boolean} True if the component should update. + * @optional + */ + shouldComponentUpdate: 'DEFINE_ONCE', + + /** + * Invoked when the component is about to update due to a transition from + * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState` + * and `nextContext`. + * + * Use this as an opportunity to perform preparation before an update occurs. + * + * NOTE: You **cannot** use `this.setState()` in this method. + * + * @param {object} nextProps + * @param {?object} nextState + * @param {?object} nextContext + * @param {ReactReconcileTransaction} transaction + * @optional + */ + componentWillUpdate: 'DEFINE_MANY', + + /** + * Invoked when the component's DOM representation has been updated. + * + * Use this as an opportunity to operate on the DOM when the component has + * been updated. + * + * @param {object} prevProps + * @param {?object} prevState + * @param {?object} prevContext + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidUpdate: 'DEFINE_MANY', + + /** + * Invoked when the component is about to be removed from its parent and have + * its DOM representation destroyed. + * + * Use this as an opportunity to deallocate any external resources. + * + * NOTE: There is no `componentDidUnmount` since your component will have been + * destroyed by that point. + * + * @optional + */ + componentWillUnmount: 'DEFINE_MANY', + + // ==== Advanced methods ==== + + /** + * Updates the component's currently mounted DOM representation. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @internal + * @overridable + */ + updateComponent: 'OVERRIDE_BASE' + }; + + /** + * Mapping from class specification keys to special processing functions. + * + * Although these are declared like instance properties in the specification + * when defining classes using `React.createClass`, they are actually static + * and are accessible on the constructor instead of the prototype. Despite + * being static, they must be defined outside of the "statics" key under + * which all other static methods are defined. + */ + var RESERVED_SPEC_KEYS = { + displayName: function(Constructor, displayName) { + Constructor.displayName = displayName; + }, + mixins: function(Constructor, mixins) { + if (mixins) { + for (var i = 0; i < mixins.length; i++) { + mixSpecIntoComponent(Constructor, mixins[i]); + } + } + }, + childContextTypes: function(Constructor, childContextTypes) { + if (process.env.NODE_ENV !== 'production') { + validateTypeDef(Constructor, childContextTypes, 'childContext'); + } + Constructor.childContextTypes = _assign( + {}, + Constructor.childContextTypes, + childContextTypes + ); + }, + contextTypes: function(Constructor, contextTypes) { + if (process.env.NODE_ENV !== 'production') { + validateTypeDef(Constructor, contextTypes, 'context'); + } + Constructor.contextTypes = _assign( + {}, + Constructor.contextTypes, + contextTypes + ); + }, + /** + * Special case getDefaultProps which should move into statics but requires + * automatic merging. + */ + getDefaultProps: function(Constructor, getDefaultProps) { + if (Constructor.getDefaultProps) { + Constructor.getDefaultProps = createMergedResultFunction( + Constructor.getDefaultProps, + getDefaultProps + ); + } else { + Constructor.getDefaultProps = getDefaultProps; + } + }, + propTypes: function(Constructor, propTypes) { + if (process.env.NODE_ENV !== 'production') { + validateTypeDef(Constructor, propTypes, 'prop'); + } + Constructor.propTypes = _assign({}, Constructor.propTypes, propTypes); + }, + statics: function(Constructor, statics) { + mixStaticSpecIntoComponent(Constructor, statics); + }, + autobind: function() {} + }; + + function validateTypeDef(Constructor, typeDef, location) { + for (var propName in typeDef) { + if (typeDef.hasOwnProperty(propName)) { + // use a warning instead of an _invariant so components + // don't show up in prod but only in __DEV__ + if (process.env.NODE_ENV !== 'production') { + warning( + typeof typeDef[propName] === 'function', + '%s: %s type `%s` is invalid; it must be a function, usually from ' + + 'React.PropTypes.', + Constructor.displayName || 'ReactClass', + ReactPropTypeLocationNames[location], + propName + ); + } + } + } + } + + function validateMethodOverride(isAlreadyDefined, name) { + var specPolicy = ReactClassInterface.hasOwnProperty(name) + ? ReactClassInterface[name] + : null; + + // Disallow overriding of base class methods unless explicitly allowed. + if (ReactClassMixin.hasOwnProperty(name)) { + _invariant( + specPolicy === 'OVERRIDE_BASE', + 'ReactClassInterface: You are attempting to override ' + + '`%s` from your class specification. Ensure that your method names ' + + 'do not overlap with React methods.', + name + ); + } + + // Disallow defining methods more than once unless explicitly allowed. + if (isAlreadyDefined) { + _invariant( + specPolicy === 'DEFINE_MANY' || specPolicy === 'DEFINE_MANY_MERGED', + 'ReactClassInterface: You are attempting to define ' + + '`%s` on your component more than once. This conflict may be due ' + + 'to a mixin.', + name + ); + } + } + + /** + * Mixin helper which handles policy validation and reserved + * specification keys when building React classes. + */ + function mixSpecIntoComponent(Constructor, spec) { + if (!spec) { + if (process.env.NODE_ENV !== 'production') { + var typeofSpec = typeof spec; + var isMixinValid = typeofSpec === 'object' && spec !== null; + + if (process.env.NODE_ENV !== 'production') { + warning( + isMixinValid, + "%s: You're attempting to include a mixin that is either null " + + 'or not an object. Check the mixins included by the component, ' + + 'as well as any mixins they include themselves. ' + + 'Expected object but got %s.', + Constructor.displayName || 'ReactClass', + spec === null ? null : typeofSpec + ); + } + } + + return; + } + + _invariant( + typeof spec !== 'function', + "ReactClass: You're attempting to " + + 'use a component class or function as a mixin. Instead, just use a ' + + 'regular object.' + ); + _invariant( + !isValidElement(spec), + "ReactClass: You're attempting to " + + 'use a component as a mixin. Instead, just use a regular object.' + ); + + var proto = Constructor.prototype; + var autoBindPairs = proto.__reactAutoBindPairs; + + // By handling mixins before any other properties, we ensure the same + // chaining order is applied to methods with DEFINE_MANY policy, whether + // mixins are listed before or after these methods in the spec. + if (spec.hasOwnProperty(MIXINS_KEY)) { + RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins); + } + + for (var name in spec) { + if (!spec.hasOwnProperty(name)) { + continue; + } + + if (name === MIXINS_KEY) { + // We have already handled mixins in a special case above. + continue; + } + + var property = spec[name]; + var isAlreadyDefined = proto.hasOwnProperty(name); + validateMethodOverride(isAlreadyDefined, name); + + if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { + RESERVED_SPEC_KEYS[name](Constructor, property); + } else { + // Setup methods on prototype: + // The following member methods should not be automatically bound: + // 1. Expected ReactClass methods (in the "interface"). + // 2. Overridden methods (that were mixed in). + var isReactClassMethod = ReactClassInterface.hasOwnProperty(name); + var isFunction = typeof property === 'function'; + var shouldAutoBind = + isFunction && + !isReactClassMethod && + !isAlreadyDefined && + spec.autobind !== false; + + if (shouldAutoBind) { + autoBindPairs.push(name, property); + proto[name] = property; + } else { + if (isAlreadyDefined) { + var specPolicy = ReactClassInterface[name]; + + // These cases should already be caught by validateMethodOverride. + _invariant( + isReactClassMethod && + (specPolicy === 'DEFINE_MANY_MERGED' || + specPolicy === 'DEFINE_MANY'), + 'ReactClass: Unexpected spec policy %s for key %s ' + + 'when mixing in component specs.', + specPolicy, + name + ); + + // For methods which are defined more than once, call the existing + // methods before calling the new property, merging if appropriate. + if (specPolicy === 'DEFINE_MANY_MERGED') { + proto[name] = createMergedResultFunction(proto[name], property); + } else if (specPolicy === 'DEFINE_MANY') { + proto[name] = createChainedFunction(proto[name], property); + } + } else { + proto[name] = property; + if (process.env.NODE_ENV !== 'production') { + // Add verbose displayName to the function, which helps when looking + // at profiling tools. + if (typeof property === 'function' && spec.displayName) { + proto[name].displayName = spec.displayName + '_' + name; + } + } + } + } + } + } + } + + function mixStaticSpecIntoComponent(Constructor, statics) { + if (!statics) { + return; + } + for (var name in statics) { + var property = statics[name]; + if (!statics.hasOwnProperty(name)) { + continue; + } + + var isReserved = name in RESERVED_SPEC_KEYS; + _invariant( + !isReserved, + 'ReactClass: You are attempting to define a reserved ' + + 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' + + 'as an instance property instead; it will still be accessible on the ' + + 'constructor.', + name + ); + + var isInherited = name in Constructor; + _invariant( + !isInherited, + 'ReactClass: You are attempting to define ' + + '`%s` on your component more than once. This conflict may be ' + + 'due to a mixin.', + name + ); + Constructor[name] = property; + } + } + + /** + * Merge two objects, but throw if both contain the same key. + * + * @param {object} one The first object, which is mutated. + * @param {object} two The second object + * @return {object} one after it has been mutated to contain everything in two. + */ + function mergeIntoWithNoDuplicateKeys(one, two) { + _invariant( + one && two && typeof one === 'object' && typeof two === 'object', + 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.' + ); + + for (var key in two) { + if (two.hasOwnProperty(key)) { + _invariant( + one[key] === undefined, + 'mergeIntoWithNoDuplicateKeys(): ' + + 'Tried to merge two objects with the same key: `%s`. This conflict ' + + 'may be due to a mixin; in particular, this may be caused by two ' + + 'getInitialState() or getDefaultProps() methods returning objects ' + + 'with clashing keys.', + key + ); + one[key] = two[key]; + } + } + return one; + } + + /** + * Creates a function that invokes two functions and merges their return values. + * + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private + */ + function createMergedResultFunction(one, two) { + return function mergedResult() { + var a = one.apply(this, arguments); + var b = two.apply(this, arguments); + if (a == null) { + return b; + } else if (b == null) { + return a; + } + var c = {}; + mergeIntoWithNoDuplicateKeys(c, a); + mergeIntoWithNoDuplicateKeys(c, b); + return c; + }; + } + + /** + * Creates a function that invokes two functions and ignores their return vales. + * + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private + */ + function createChainedFunction(one, two) { + return function chainedFunction() { + one.apply(this, arguments); + two.apply(this, arguments); + }; + } + + /** + * Binds a method to the component. + * + * @param {object} component Component whose method is going to be bound. + * @param {function} method Method to be bound. + * @return {function} The bound method. + */ + function bindAutoBindMethod(component, method) { + var boundMethod = method.bind(component); + if (process.env.NODE_ENV !== 'production') { + boundMethod.__reactBoundContext = component; + boundMethod.__reactBoundMethod = method; + boundMethod.__reactBoundArguments = null; + var componentName = component.constructor.displayName; + var _bind = boundMethod.bind; + boundMethod.bind = function(newThis) { + for ( + var _len = arguments.length, + args = Array(_len > 1 ? _len - 1 : 0), + _key = 1; + _key < _len; + _key++ + ) { + args[_key - 1] = arguments[_key]; + } + + // User is trying to bind() an autobound method; we effectively will + // ignore the value of "this" that the user is trying to use, so + // let's warn. + if (newThis !== component && newThis !== null) { + if (process.env.NODE_ENV !== 'production') { + warning( + false, + 'bind(): React component methods may only be bound to the ' + + 'component instance. See %s', + componentName + ); + } + } else if (!args.length) { + if (process.env.NODE_ENV !== 'production') { + warning( + false, + 'bind(): You are binding a component method to the component. ' + + 'React does this for you automatically in a high-performance ' + + 'way, so you can safely remove this call. See %s', + componentName + ); + } + return boundMethod; + } + var reboundMethod = _bind.apply(boundMethod, arguments); + reboundMethod.__reactBoundContext = component; + reboundMethod.__reactBoundMethod = method; + reboundMethod.__reactBoundArguments = args; + return reboundMethod; + }; + } + return boundMethod; + } + + /** + * Binds all auto-bound methods in a component. + * + * @param {object} component Component whose method is going to be bound. + */ + function bindAutoBindMethods(component) { + var pairs = component.__reactAutoBindPairs; + for (var i = 0; i < pairs.length; i += 2) { + var autoBindKey = pairs[i]; + var method = pairs[i + 1]; + component[autoBindKey] = bindAutoBindMethod(component, method); + } + } + + var IsMountedPreMixin = { + componentDidMount: function() { + this.__isMounted = true; + } + }; + + var IsMountedPostMixin = { + componentWillUnmount: function() { + this.__isMounted = false; + } + }; + + /** + * Add more to the ReactClass base class. These are all legacy features and + * therefore not already part of the modern ReactComponent. + */ + var ReactClassMixin = { + /** + * TODO: This will be deprecated because state should always keep a consistent + * type signature and the only use case for this, is to avoid that. + */ + replaceState: function(newState, callback) { + this.updater.enqueueReplaceState(this, newState, callback); + }, + + /** + * Checks whether or not this composite component is mounted. + * @return {boolean} True if mounted, false otherwise. + * @protected + * @final + */ + isMounted: function() { + if (process.env.NODE_ENV !== 'production') { + warning( + this.__didWarnIsMounted, + '%s: isMounted is deprecated. Instead, make sure to clean up ' + + 'subscriptions and pending requests in componentWillUnmount to ' + + 'prevent memory leaks.', + (this.constructor && this.constructor.displayName) || + this.name || + 'Component' + ); + this.__didWarnIsMounted = true; + } + return !!this.__isMounted; + } + }; + + var ReactClassComponent = function() {}; + _assign( + ReactClassComponent.prototype, + ReactComponent.prototype, + ReactClassMixin + ); + + /** + * Creates a composite component class given a class specification. + * See https://facebook.github.io/react/docs/top-level-api.html#react.createclass + * + * @param {object} spec Class specification (which must define `render`). + * @return {function} Component constructor function. + * @public + */ + function createClass(spec) { + // To keep our warnings more understandable, we'll use a little hack here to + // ensure that Constructor.name !== 'Constructor'. This makes sure we don't + // unnecessarily identify a class without displayName as 'Constructor'. + var Constructor = identity(function(props, context, updater) { + // This constructor gets overridden by mocks. The argument is used + // by mocks to assert on what gets mounted. + + if (process.env.NODE_ENV !== 'production') { + warning( + this instanceof Constructor, + 'Something is calling a React component directly. Use a factory or ' + + 'JSX instead. See: https://fb.me/react-legacyfactory' + ); + } + + // Wire up auto-binding + if (this.__reactAutoBindPairs.length) { + bindAutoBindMethods(this); + } + + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + + this.state = null; + + // ReactClasses doesn't have constructors. Instead, they use the + // getInitialState and componentWillMount methods for initialization. + + var initialState = this.getInitialState ? this.getInitialState() : null; + if (process.env.NODE_ENV !== 'production') { + // We allow auto-mocks to proceed as if they're returning null. + if ( + initialState === undefined && + this.getInitialState._isMockFunction + ) { + // This is probably bad practice. Consider warning here and + // deprecating this convenience. + initialState = null; + } + } + _invariant( + typeof initialState === 'object' && !Array.isArray(initialState), + '%s.getInitialState(): must return an object or null', + Constructor.displayName || 'ReactCompositeComponent' + ); + + this.state = initialState; + }); + Constructor.prototype = new ReactClassComponent(); + Constructor.prototype.constructor = Constructor; + Constructor.prototype.__reactAutoBindPairs = []; + + injectedMixins.forEach(mixSpecIntoComponent.bind(null, Constructor)); + + mixSpecIntoComponent(Constructor, IsMountedPreMixin); + mixSpecIntoComponent(Constructor, spec); + mixSpecIntoComponent(Constructor, IsMountedPostMixin); + + // Initialize the defaultProps property after all mixins have been merged. + if (Constructor.getDefaultProps) { + Constructor.defaultProps = Constructor.getDefaultProps(); + } + + if (process.env.NODE_ENV !== 'production') { + // This is a tag to indicate that the use of these method names is ok, + // since it's used with createClass. If it's not, then it's likely a + // mistake so we'll warn you to use the static property, property + // initializer or constructor respectively. + if (Constructor.getDefaultProps) { + Constructor.getDefaultProps.isReactClassApproved = {}; + } + if (Constructor.prototype.getInitialState) { + Constructor.prototype.getInitialState.isReactClassApproved = {}; + } + } + + _invariant( + Constructor.prototype.render, + 'createClass(...): Class specification must implement a `render` method.' + ); + + if (process.env.NODE_ENV !== 'production') { + warning( + !Constructor.prototype.componentShouldUpdate, + '%s has a method called ' + + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + + 'The name is phrased as a question because the function is ' + + 'expected to return a value.', + spec.displayName || 'A component' + ); + warning( + !Constructor.prototype.componentWillRecieveProps, + '%s has a method called ' + + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', + spec.displayName || 'A component' + ); + } + + // Reduce time spent doing lookups by setting these on the prototype. + for (var methodName in ReactClassInterface) { + if (!Constructor.prototype[methodName]) { + Constructor.prototype[methodName] = null; + } + } + + return Constructor; + } + + return createClass; + } + + module.exports = factory; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5))) + +/***/ }), +/* 30 */ +/***/ (function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * 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 emptyObject = {}; + + if (process.env.NODE_ENV !== 'production') { + Object.freeze(emptyObject); + } + + module.exports = emptyObject; + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(5))) + +/***/ }), +/* 31 */ /***/ (function(module, exports) { /** * Copyright (c) 2013-present, Facebook, Inc. - * All rights reserved. * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. * */ @@ -2481,16 +3546,16 @@ module.exports = ExecutionEnvironment; /***/ }), -/* 28 */ +/* 32 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {"use strict"; - module.exports = global["mixpanelHelper"] = __webpack_require__(29); + module.exports = global["mixpanelHelper"] = __webpack_require__(33); /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }), -/* 29 */ +/* 33 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -2499,11 +3564,11 @@ value: true }); - var _emitter = __webpack_require__(14); + var _emitter = __webpack_require__(15); var _emitter2 = _interopRequireDefault(_emitter); - var _ExecutionEnvironment = __webpack_require__(27); + var _ExecutionEnvironment = __webpack_require__(31); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } @@ -2551,16 +3616,16 @@ module.exports = exports['default']; /***/ }), -/* 30 */ +/* 34 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {"use strict"; - module.exports = global["segmentHelper"] = __webpack_require__(31); + module.exports = global["segmentHelper"] = __webpack_require__(35); /* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()))) /***/ }), -/* 31 */ +/* 35 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -2569,11 +3634,11 @@ value: true }); - var _emitter = __webpack_require__(14); + var _emitter = __webpack_require__(15); var _emitter2 = _interopRequireDefault(_emitter); - var _ExecutionEnvironment = __webpack_require__(27); + var _ExecutionEnvironment = __webpack_require__(31); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } diff --git a/test/browser/core.test.jsx b/test/browser/core.test.jsx index 6515120..5291405 100644 --- a/test/browser/core.test.jsx +++ b/test/browser/core.test.jsx @@ -1,5 +1,6 @@ import React from "react"; import ReactDOM from "react-dom"; +import createReactClass from 'create-react-class'; import Experiment from "../../src/CoreExperiment.jsx"; import Variant from "../../src/Variant.jsx"; import emitter from "../../src/emitter.jsx"; @@ -22,7 +23,7 @@ describe("Core Experiment", function() { }); it("should render the correct variant.", co.wrap(function *(){ let experimentName = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return
@@ -41,7 +42,7 @@ describe("Core Experiment", function() { })); it("should error if invalid children exist.", co.wrap(function *(){ let experimentName = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return
@@ -71,7 +72,7 @@ describe("Core Experiment", function() { let getValueB = function() { return "B"; } - let App = React.createClass({ + let App = createReactClass({ getInitialState: function(){ return { value: getValueA @@ -105,7 +106,7 @@ describe("Core Experiment", function() { })); it("should update the children when props change.", co.wrap(function *(){ let experimentName = UUID.v4(); - let SubComponent = React.createClass({ + let SubComponent = createReactClass({ render(){ return (
@@ -114,7 +115,7 @@ describe("Core Experiment", function() { ) } }); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return diff --git a/test/browser/debugger.test.jsx b/test/browser/debugger.test.jsx index fdd5d21..e199dc4 100644 --- a/test/browser/debugger.test.jsx +++ b/test/browser/debugger.test.jsx @@ -1,5 +1,6 @@ import React from "react"; import ReactDOM from "react-dom"; +import createReactClass from 'create-react-class'; import Experiment from "../../src/CoreExperiment.jsx"; import Variant from "../../src/Variant.jsx"; import experimentDebugger from "../../src/debugger.jsx"; @@ -45,7 +46,7 @@ describe("Debugger", function() { }); it("should enable and disable.", co.wrap(function *(){ let experimentName = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return
@@ -72,7 +73,7 @@ describe("Debugger", function() { }); it("should change an experiment's value.", co.wrap(function *(){ let experimentName = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return
diff --git a/test/browser/emitter.test.jsx b/test/browser/emitter.test.jsx index 814e912..a228e95 100644 --- a/test/browser/emitter.test.jsx +++ b/test/browser/emitter.test.jsx @@ -1,5 +1,6 @@ import React from "react"; import ReactDOM from "react-dom"; +import createReactClass from 'create-react-class'; import Experiment from "../../src/CoreExperiment.jsx"; import Variant from "../../src/Variant.jsx"; import emitter from "../../src/emitter.jsx"; @@ -38,7 +39,7 @@ describe("Emitter", function() { }; let playSubscription = emitter.addPlayListener(experimentName, playCallback); let playSubscriptionGlobal = emitter.addPlayListener(playCallbackGlobal); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return
@@ -70,7 +71,7 @@ describe("Emitter", function() { }; let winSubscription = emitter.addWinListener(experimentName, winCallback); let winSubscriptionGlobal = emitter.addWinListener(winCallbackGlobal); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return
@@ -103,7 +104,7 @@ describe("Emitter", function() { }; let winSubscription = emitter.addWinListener(experimentName, winCallback); let winSubscriptionGlobal = emitter.addWinListener(winCallbackGlobal); - let App = React.createClass({ + let App = createReactClass({ onClickVariant: function(e){ this.refs.experiment.win(); }, @@ -140,7 +141,7 @@ describe("Emitter", function() { }; let activeVariantSubscription = emitter.addActiveVariantListener(experimentName, activeVariantCallback); let activeVariantSubscriptionGlobal = emitter.addActiveVariantListener(activeVariantCallbackGlobal); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return A @@ -160,7 +161,7 @@ describe("Emitter", function() { })); it("should get the experiment value.", co.wrap(function *(){ let experimentName = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return A @@ -176,7 +177,7 @@ describe("Emitter", function() { })); it("should update the rendered component.", co.wrap(function *(){ let experimentName = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return
@@ -201,7 +202,7 @@ describe("Emitter", function() { it("should report active components.", co.wrap(function *(){ let experimentNameA = UUID.v4(); let experimentNameB = UUID.v4(); - let AppA = React.createClass({ + let AppA = createReactClass({ render: function(){ return
@@ -209,7 +210,7 @@ describe("Emitter", function() { ; } }); - let AppB = React.createClass({ + let AppB = createReactClass({ render: function(){ return
@@ -217,7 +218,7 @@ describe("Emitter", function() { ; } }); - let AppCombined = React.createClass({ + let AppCombined = createReactClass({ render: function(){ return
diff --git a/test/browser/experiment.test.jsx b/test/browser/experiment.test.jsx index e17b6c6..91874a1 100644 --- a/test/browser/experiment.test.jsx +++ b/test/browser/experiment.test.jsx @@ -1,5 +1,6 @@ import React from "react"; import ReactDOM from "react-dom"; +import createReactClass from 'create-react-class'; import Experiment from "../../src/Experiment.jsx"; import Variant from "../../src/Variant.jsx"; import emitter from "../../src/emitter.jsx"; @@ -52,7 +53,7 @@ describe("Experiment", function() { for(let i = 0; i < 100; i++) { variantNames.push(UUID.v4()); } - let App = React.createClass({ + let App = createReactClass({ render: function(){ return {variantNames.map(name => { @@ -73,7 +74,7 @@ describe("Experiment", function() { variantNames.push(UUID.v4()); } let defaultVariantName = variantNames[Math.floor(Math.random() * variantNames.length)]; - let AppWithdefaultVariantName = React.createClass({ + let AppWithdefaultVariantName = createReactClass({ render: function(){ return {variantNames.map(name => { @@ -82,7 +83,7 @@ describe("Experiment", function() { ; } }); - let AppWithoutdefaultVariantName = React.createClass({ + let AppWithoutdefaultVariantName = createReactClass({ render: function(){ return {variantNames.map(name => { @@ -106,7 +107,7 @@ describe("Experiment", function() { })); it("should error if variants are added to a experiment after a variant was selected.", co.wrap(function *(){ let experimentName = UUID.v4(); - let AppPart1 = React.createClass({ + let AppPart1 = createReactClass({ onClickVariant: function(e){ this.refs.experiment.win(); }, @@ -117,7 +118,7 @@ describe("Experiment", function() { ; } }); - let AppPart2 = React.createClass({ + let AppPart2 = createReactClass({ onClickVariant: function(e){ this.refs.experiment.win(); }, @@ -148,7 +149,7 @@ describe("Experiment", function() { it("should not error if variants are added to a experiment after a variant was selected if variants were defined.", co.wrap(function *(){ let experimentName = UUID.v4(); emitter.defineVariants(experimentName, ["A", "B", "C", "D"]); - let AppPart1 = React.createClass({ + let AppPart1 = createReactClass({ onClickVariant: function(e){ this.refs.experiment.win(); }, @@ -159,7 +160,7 @@ describe("Experiment", function() { ; } }); - let AppPart2 = React.createClass({ + let AppPart2 = createReactClass({ onClickVariant: function(e){ this.refs.experiment.win(); }, @@ -182,7 +183,7 @@ describe("Experiment", function() { it("should error if a variant is added to an experiment after variants were defined.", co.wrap(function *(){ let experimentName = UUID.v4(); emitter.defineVariants(experimentName, ["A", "B", "C"]); - let AppPart1 = React.createClass({ + let AppPart1 = createReactClass({ onClickVariant: function(e){ this.refs.experiment.win(); }, @@ -193,7 +194,7 @@ describe("Experiment", function() { ; } }); - let AppPart2 = React.createClass({ + let AppPart2 = createReactClass({ onClickVariant: function(e){ this.refs.experiment.win(); }, @@ -224,7 +225,7 @@ describe("Experiment", function() { it("should not error if an older test variant is set.", co.wrap(function *(){ let experimentName = UUID.v4(); localStorage.setItem("PUSHTELL-" + experimentName, "C"); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return A @@ -251,7 +252,7 @@ describe("Experiment", function() { }; let winSubscription = emitter.addWinListener(experimentName, winCallback); let winSubscriptionGlobal = emitter.addWinListener(winCallbackGlobal); - let App = React.createClass({ + let App = createReactClass({ onClickVariant: function(e){ this.refs.experiment.win(); }, @@ -281,7 +282,7 @@ describe("Experiment", function() { for(let i = 0; i < 100; i++) { variantNames.push(UUID.v4()); } - let App = React.createClass({ + let App = createReactClass({ render: function(){ return {variantNames.map(name => { diff --git a/test/browser/helpers.mixpanel.test.jsx b/test/browser/helpers.mixpanel.test.jsx index 9ffb853..748c84e 100644 --- a/test/browser/helpers.mixpanel.test.jsx +++ b/test/browser/helpers.mixpanel.test.jsx @@ -1,5 +1,6 @@ import React from "react"; import ReactDOM from "react-dom"; +import createReactClass from 'create-react-class'; import Experiment from "../../src/CoreExperiment.jsx"; import Variant from "../../src/Variant.jsx"; import emitter from "../../src/emitter.jsx"; @@ -72,7 +73,7 @@ describe("Mixpanel Helper", function() { } mixpanelHelper.enable(); let experimentName = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return
diff --git a/test/browser/helpers.segment.test.jsx b/test/browser/helpers.segment.test.jsx index 87ee484..98fc91f 100644 --- a/test/browser/helpers.segment.test.jsx +++ b/test/browser/helpers.segment.test.jsx @@ -1,5 +1,6 @@ import React from "react"; import ReactDOM from "react-dom"; +import createReactClass from 'create-react-class'; import Experiment from "../../src/CoreExperiment.jsx"; import Variant from "../../src/Variant.jsx"; import emitter from "../../src/emitter.jsx"; @@ -73,7 +74,7 @@ describe("Segment Helper", function() { } segmentHelper.enable(); let experimentName = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return
diff --git a/test/browser/variant.test.jsx b/test/browser/variant.test.jsx index f9d1d08..0a07d33 100644 --- a/test/browser/variant.test.jsx +++ b/test/browser/variant.test.jsx @@ -1,5 +1,6 @@ import React from "react"; import ReactDOM from "react-dom"; +import createReactClass from 'create-react-class'; import Experiment from "../../src/CoreExperiment.jsx"; import Variant from "../../src/Variant.jsx"; import emitter from "../../src/emitter.jsx"; @@ -24,7 +25,7 @@ describe("Variant", function() { let experimentName = UUID.v4(); let variantTextA = UUID.v4(); let variantTextB = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return {variantTextA} @@ -39,7 +40,7 @@ describe("Variant", function() { })); it("should render components.", co.wrap(function *(){ let experimentName = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return
@@ -58,7 +59,7 @@ describe("Variant", function() { })); it("should render arrays of components.", co.wrap(function *(){ let experimentName = UUID.v4(); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return diff --git a/test/browser/weighted.test.jsx b/test/browser/weighted.test.jsx index 00d2703..2ac5de4 100644 --- a/test/browser/weighted.test.jsx +++ b/test/browser/weighted.test.jsx @@ -1,5 +1,6 @@ import React from "react"; import ReactDOM from "react-dom"; +import createReactClass from 'create-react-class'; import Experiment from "../../src/Experiment.jsx"; import Variant from "../../src/Variant.jsx"; import emitter from "../../src/emitter.jsx"; @@ -63,7 +64,7 @@ describe("Weighted Experiment", function() { const weightSum = variantWeights.reduce(add, 0); emitter.defineVariants(experimentName, variantNames, variantWeights); assert.equal(emitter.getSortedVariantWeights(experimentName).reduce(add, 0), weightSum); - let App = React.createClass({ + let App = createReactClass({ render: function(){ return {variantNames.map(name => {