From 445a89e8428d4bbbdf38f86d068f5d66fbf144e0 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 5 Jun 2016 18:20:15 -0700 Subject: [PATCH 1/3] web: fix list reducer --- web/src/js/ducks/utils/list.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/js/ducks/utils/list.js b/web/src/js/ducks/utils/list.js index a5ce7250f..6668e85ed 100644 --- a/web/src/js/ducks/utils/list.js +++ b/web/src/js/ducks/utils/list.js @@ -62,7 +62,7 @@ export default function makeList(actionType, fetchURL) { itemIndex = state.indexOf[action.item.id] list[itemIndex] = action.item return { - ...defaultState, + ...state, list } @@ -71,7 +71,7 @@ export default function makeList(actionType, fetchURL) { itemIndex = state.indexOf[action.item.id] list.splice(itemIndex, 1) return { - ...defaultState, + ...state, list, byId: {...state.byId, [action.item.id]: undefined}, indexOf: {...state.indexOf, [action.item.id]: undefined}, @@ -79,7 +79,7 @@ export default function makeList(actionType, fetchURL) { case REQUEST_LIST: return { - ...defaultState, + ...state, isFetching: true } From efed5ab967e2d416aec1c6b437063841436fa3da Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 5 Jun 2016 18:20:51 -0700 Subject: [PATCH 2/3] web: update react --- web/package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/web/package.json b/web/package.json index 3bbed9e8f..97a5ad3ea 100644 --- a/web/package.json +++ b/web/package.json @@ -21,8 +21,8 @@ "flux": "^2.1.1", "jquery": "^2.2.3", "lodash": "^4.11.2", - "react": "^15.0.2", - "react-dom": "^15.0.2", + "react": "^15.1.0", + "react-dom": "^15.1.0", "react-redux": "^4.4.5", "react-router": "^2.4.0", "redux": "^3.5.2", @@ -53,7 +53,6 @@ "gulp-sourcemaps": "^1.6.0", "gulp-util": "^3.0.7", "jest": "^0.1.40", - "redux-thunk": "^2.1.0", "uglifyify": "^3.0.1", "vinyl-buffer": "^1.0.0", "vinyl-source-stream": "^1.1.0", From e6ef149a03b37d74c7ebbf3a5f3a51e3c7341311 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 5 Jun 2016 18:23:06 -0700 Subject: [PATCH 3/3] web: modernize flow table columns --- mitmproxy/web/static/app.js | 470 +++-- mitmproxy/web/static/vendor.js | 1881 +++++++++++--------- web/src/js/components/flowtable-columns.js | 271 ++- web/src/js/components/flowtable.js | 78 +- 4 files changed, 1396 insertions(+), 1304 deletions(-) diff --git a/mitmproxy/web/static/app.js b/mitmproxy/web/static/app.js index 88b5e85a7..7a4deae88 100644 --- a/mitmproxy/web/static/app.js +++ b/mitmproxy/web/static/app.js @@ -1212,251 +1212,221 @@ var _utils2 = require("../utils.js"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var TLSColumn = _react2.default.createClass({ - displayName: "TLSColumn", +function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } - statics: { - Title: _react2.default.createClass({ - displayName: "Title", +function TLSColumn(_ref) { + var flow = _ref.flow; - render: function render() { - return _react2.default.createElement("th", _extends({}, this.props, { className: "col-tls " + (this.props.className || "") })); - } - }), - sortKeyFun: function sortKeyFun(flow) { - return flow.request.scheme; - } - }, - render: function render() { - var flow = this.props.flow; - var ssl = flow.request.scheme === "https"; - var classes; - if (ssl) { - classes = "col-tls col-tls-https"; - } else { - classes = "col-tls col-tls-http"; - } - return _react2.default.createElement("td", { className: classes }); + var ssl = flow.request.scheme === "https"; + var classes = void 0; + if (ssl) { + classes = "col-tls col-tls-https"; + } else { + classes = "col-tls col-tls-http"; } -}); + return _react2.default.createElement("td", { className: classes }); +} +TLSColumn.Title = function (_ref2) { + var _ref2$className = _ref2.className; + var className = _ref2$className === undefined ? "" : _ref2$className; -var IconColumn = _react2.default.createClass({ - displayName: "IconColumn", + var props = _objectWithoutProperties(_ref2, ["className"]); - statics: { - Title: _react2.default.createClass({ - displayName: "Title", + return _react2.default.createElement("th", _extends({}, props, { className: "col-tls " + className })); +}; +TLSColumn.sortKeyFun = function (flow) { + return flow.request.scheme; +}; - render: function render() { - return _react2.default.createElement("th", _extends({}, this.props, { className: "col-icon " + (this.props.className || "") })); - } - }) - }, - render: function render() { - var flow = this.props.flow; +function IconColumn(_ref3) { + var flow = _ref3.flow; - var icon; - if (flow.response) { - var contentType = _utils.ResponseUtils.getContentType(flow.response); + var icon = void 0; + if (flow.response) { + var contentType = _utils.ResponseUtils.getContentType(flow.response); - //TODO: We should assign a type to the flow somewhere else. - if (flow.response.status_code === 304) { - icon = "resource-icon-not-modified"; - } else if (300 <= flow.response.status_code && flow.response.status_code < 400) { - icon = "resource-icon-redirect"; - } else if (contentType && contentType.indexOf("image") >= 0) { - icon = "resource-icon-image"; - } else if (contentType && contentType.indexOf("javascript") >= 0) { - icon = "resource-icon-js"; - } else if (contentType && contentType.indexOf("css") >= 0) { - icon = "resource-icon-css"; - } else if (contentType && contentType.indexOf("html") >= 0) { - icon = "resource-icon-document"; - } + //TODO: We should assign a type to the flow somewhere else. + if (flow.response.status_code === 304) { + icon = "resource-icon-not-modified"; + } else if (300 <= flow.response.status_code && flow.response.status_code < 400) { + icon = "resource-icon-redirect"; + } else if (contentType && contentType.indexOf("image") >= 0) { + icon = "resource-icon-image"; + } else if (contentType && contentType.indexOf("javascript") >= 0) { + icon = "resource-icon-js"; + } else if (contentType && contentType.indexOf("css") >= 0) { + icon = "resource-icon-css"; + } else if (contentType && contentType.indexOf("html") >= 0) { + icon = "resource-icon-document"; } - if (!icon) { - icon = "resource-icon-plain"; - } - - icon += " resource-icon"; - return _react2.default.createElement( - "td", - { className: "col-icon" }, - _react2.default.createElement("div", { className: icon }) - ); } -}); - -var PathColumn = _react2.default.createClass({ - displayName: "PathColumn", - - statics: { - Title: _react2.default.createClass({ - displayName: "Title", - - render: function render() { - return _react2.default.createElement( - "th", - _extends({}, this.props, { className: "col-path " + (this.props.className || "") }), - "Path" - ); - } - }), - sortKeyFun: function sortKeyFun(flow) { - return _utils.RequestUtils.pretty_url(flow.request); - } - }, - render: function render() { - var flow = this.props.flow; - return _react2.default.createElement( - "td", - { className: "col-path" }, - flow.request.is_replay ? _react2.default.createElement("i", { className: "fa fa-fw fa-repeat pull-right" }) : null, - flow.intercepted ? _react2.default.createElement("i", { className: "fa fa-fw fa-pause pull-right" }) : null, - _utils.RequestUtils.pretty_url(flow.request) - ); + if (!icon) { + icon = "resource-icon-plain"; } -}); -var MethodColumn = _react2.default.createClass({ - displayName: "MethodColumn", + icon += " resource-icon"; + return _react2.default.createElement( + "td", + { className: "col-icon" }, + _react2.default.createElement("div", { className: icon }) + ); +} +IconColumn.Title = function (_ref4) { + var _ref4$className = _ref4.className; + var className = _ref4$className === undefined ? "" : _ref4$className; - statics: { - Title: _react2.default.createClass({ - displayName: "Title", + var props = _objectWithoutProperties(_ref4, ["className"]); - render: function render() { - return _react2.default.createElement( - "th", - _extends({}, this.props, { className: "col-method " + (this.props.className || "") }), - "Method" - ); - } - }), - sortKeyFun: function sortKeyFun(flow) { - return flow.request.method; - } - }, - render: function render() { - var flow = this.props.flow; - return _react2.default.createElement( - "td", - { className: "col-method" }, - flow.request.method - ); + return _react2.default.createElement("th", _extends({}, props, { className: "col-icon " + className })); +}; + +function PathColumn(_ref5) { + var flow = _ref5.flow; + + return _react2.default.createElement( + "td", + { className: "col-path" }, + flow.request.is_replay ? _react2.default.createElement("i", { className: "fa fa-fw fa-repeat pull-right" }) : null, + flow.intercepted ? _react2.default.createElement("i", { className: "fa fa-fw fa-pause pull-right" }) : null, + _utils.RequestUtils.pretty_url(flow.request) + ); +} +PathColumn.Title = function (_ref6) { + var _ref6$className = _ref6.className; + var className = _ref6$className === undefined ? "" : _ref6$className; + + var props = _objectWithoutProperties(_ref6, ["className"]); + + return _react2.default.createElement( + "th", + _extends({}, props, { className: "col-path " + className }), + "Path" + ); +}; +PathColumn.sortKeyFun = function (flow) { + return _utils.RequestUtils.pretty_url(flow.request); +}; + +function MethodColumn(_ref7) { + var flow = _ref7.flow; + + return _react2.default.createElement( + "td", + { className: "col-method" }, + flow.request.method + ); +} +MethodColumn.Title = function (_ref8) { + var _ref8$className = _ref8.className; + var className = _ref8$className === undefined ? "" : _ref8$className; + + var props = _objectWithoutProperties(_ref8, ["className"]); + + return _react2.default.createElement( + "th", + _extends({}, props, { className: "col-method " + className }), + "Method" + ); +}; +MethodColumn.sortKeyFun = function (flow) { + return flow.request.method; +}; + +function StatusColumn(_ref9) { + var flow = _ref9.flow; + + var status = void 0; + if (flow.response) { + status = flow.response.status_code; + } else { + status = null; } -}); + return _react2.default.createElement( + "td", + { className: "col-status" }, + status + ); +} +StatusColumn.Title = function (_ref10) { + var _ref10$className = _ref10.className; + var className = _ref10$className === undefined ? "" : _ref10$className; -var StatusColumn = _react2.default.createClass({ - displayName: "StatusColumn", + var props = _objectWithoutProperties(_ref10, ["className"]); - statics: { - Title: _react2.default.createClass({ - displayName: "Title", + return _react2.default.createElement( + "th", + _extends({}, props, { className: "col-status " + className }), + "Status" + ); +}; +StatusColumn.sortKeyFun = function (flow) { + return flow.response ? flow.response.status_code : undefined; +}; - render: function render() { - return _react2.default.createElement( - "th", - _extends({}, this.props, { className: "col-status " + (this.props.className || "") }), - "Status" - ); - } - }), - sortKeyFun: function sortKeyFun(flow) { - return flow.response ? flow.response.status_code : undefined; - } - }, - render: function render() { - var flow = this.props.flow; - var status; - if (flow.response) { - status = flow.response.status_code; - } else { - status = null; - } - return _react2.default.createElement( - "td", - { className: "col-status" }, - status - ); +function SizeColumn(_ref11) { + var flow = _ref11.flow; + + var total = flow.request.contentLength; + if (flow.response) { + total += flow.response.contentLength || 0; } -}); + var size = (0, _utils2.formatSize)(total); + return _react2.default.createElement( + "td", + { className: "col-size" }, + size + ); +} +SizeColumn.Title = function (_ref12) { + var _ref12$className = _ref12.className; + var className = _ref12$className === undefined ? "" : _ref12$className; -var SizeColumn = _react2.default.createClass({ - displayName: "SizeColumn", + var props = _objectWithoutProperties(_ref12, ["className"]); - statics: { - Title: _react2.default.createClass({ - displayName: "Title", - - render: function render() { - return _react2.default.createElement( - "th", - _extends({}, this.props, { className: "col-size " + (this.props.className || "") }), - "Size" - ); - } - }), - sortKeyFun: function sortKeyFun(flow) { - var total = flow.request.contentLength; - if (flow.response) { - total += flow.response.contentLength || 0; - } - return total; - } - }, - render: function render() { - var flow = this.props.flow; - - var total = flow.request.contentLength; - if (flow.response) { - total += flow.response.contentLength || 0; - } - var size = (0, _utils2.formatSize)(total); - return _react2.default.createElement( - "td", - { className: "col-size" }, - size - ); + return _react2.default.createElement( + "th", + _extends({}, props, { className: "col-size " + className }), + "Size" + ); +}; +SizeColumn.sortKeyFun = function (flow) { + var total = flow.request.contentLength; + if (flow.response) { + total += flow.response.contentLength || 0; } -}); + return total; +}; -var TimeColumn = _react2.default.createClass({ - displayName: "TimeColumn", +function TimeColumn(_ref13) { + var flow = _ref13.flow; - statics: { - Title: _react2.default.createClass({ - displayName: "Title", - - render: function render() { - return _react2.default.createElement( - "th", - _extends({}, this.props, { className: "col-time " + (this.props.className || "") }), - "Time" - ); - } - }), - sortKeyFun: function sortKeyFun(flow) { - if (flow.response) { - return flow.response.timestamp_end - flow.request.timestamp_start; - } - } - }, - render: function render() { - var flow = this.props.flow; - var time; - if (flow.response) { - time = (0, _utils2.formatTimeDelta)(1000 * (flow.response.timestamp_end - flow.request.timestamp_start)); - } else { - time = "..."; - } - return _react2.default.createElement( - "td", - { className: "col-time" }, - time - ); + var time = void 0; + if (flow.response) { + time = (0, _utils2.formatTimeDelta)(1000 * (flow.response.timestamp_end - flow.request.timestamp_start)); + } else { + time = "..."; } -}); + return _react2.default.createElement( + "td", + { className: "col-time" }, + time + ); +} +TimeColumn.Title = function (_ref14) { + var _ref14$className = _ref14.className; + var className = _ref14$className === undefined ? "" : _ref14$className; + + var props = _objectWithoutProperties(_ref14, ["className"]); + + return _react2.default.createElement( + "th", + _extends({}, props, { className: "col-time " + className }), + "Time" + ); +}; +TimeColumn.sortKeyFun = function (flow) { + return flow.response.timestamp_end - flow.request.timestamp_start; +}; var all_columns = [TLSColumn, IconColumn, PathColumn, MethodColumn, StatusColumn, SizeColumn, TimeColumn]; @@ -1525,12 +1495,17 @@ FlowRow.propTypes = { selected: _react2.default.PropTypes.bool }; -function FlowRow(props) { - var flow = props.flow; +function FlowRow(_ref) { + var flow = _ref.flow; + var selected = _ref.selected; + var highlight = _ref.highlight; + var columns = _ref.columns; + var selectFlow = _ref.selectFlow; + var className = (0, _classnames2.default)({ - "selected": props.selected, - "highlighted": props.highlight && parseFilter(props.highlight)(flow), + "selected": selected, + "highlighted": highlight && parseFilter(highlight)(flow), "intercepted": flow.intercepted, "has-request": flow.request, "has-response": flow.response @@ -1539,10 +1514,10 @@ function FlowRow(props) { return _react2.default.createElement( "tr", { className: className, onClick: function onClick() { - return props.selectFlow(flow); + return selectFlow(flow); } }, - props.columns.map(function (Column) { - return _react2.default.createElement(Column, { key: Column.displayName, flow: flow }); + columns.map(function (Column) { + return _react2.default.createElement(Column, { key: Column.name, flow: flow }); }) ); } @@ -1553,8 +1528,6 @@ var FlowRowContainer = (0, _reactRedux.connect)(function (state, ownProps) { highlight: state.flows.highlight, selected: state.flows.selected.indexOf(ownProps.flowId) >= 0 }; -}, function (dispatch, ownProps) { - return {}; })(FlowRow); var FlowTableHead = function (_React$Component) { @@ -1608,11 +1581,11 @@ var FlowTableHead = function (_React$Component) { null, this.props.columns.map(function (Column) { return _react2.default.createElement(Column.Title, { - key: Column.displayName, + key: Column.name, onClick: function onClick() { return _this2.onClick(Column); }, - className: sortColumn === Column && sortType + className: sortColumn === Column ? sortType : undefined }); }) ); @@ -1769,8 +1742,6 @@ var FlowTableContainer = (0, _reactRedux.connect)(function (state) { return { flows: state.flows.view }; -}, function (dispatch) { - return {}; })(FlowTable); exports.default = FlowTableContainer; @@ -3831,7 +3802,7 @@ var MainView = _react2.default.createClass({ componentWillReceiveProps: function componentWillReceiveProps(nextProps) { // Update redux store with route changes if (nextProps.routeParams.flowId !== (nextProps.selectedFlow || {}).id) { - this.props.selectFlow(nextProps.routeParams.flowId); + // FIXME this.props.selectFlow(nextProps.routeParams.flowId) } if (nextProps.location.query[_actions.Query.SEARCH] !== nextProps.filter) { this.props.setFilter(nextProps.location.query[_actions.Query.SEARCH], false); @@ -3844,6 +3815,7 @@ var MainView = _react2.default.createClass({ // FIXME: Move to redux. This requires that sortKeyFun is not a function anymore. }, selectFlow: function selectFlow(flow) { + return this.props.selectFlow(flow.id); // TODO: This belongs into redux if (flow) { var tab = this.props.routeParams.detailTab || "request"; @@ -4145,7 +4117,7 @@ exports.default = Prompt; Object.defineProperty(exports, "__esModule", { value: true }); -exports.App = undefined; +exports.history = exports.App = undefined; var _react = require("react"); @@ -4326,6 +4298,7 @@ var App = exports.App = _react2.default.createElement( _react2.default.createElement(_reactRouter.Route, { path: "reports", component: Reports }) ) ); +exports.history = _reactRouter.hashHistory; },{"../store/store.js":31,"../utils.js":32,"./common.js":4,"./eventlog.js":6,"./footer.js":14,"./header.js":15,"./mainview.js":18,"lodash":"lodash","react":"react","react-dom":"react-dom","react-redux":"react-redux","react-router":"react-router"}],21:[function(require,module,exports){ "use strict"; @@ -4544,6 +4517,8 @@ var _filt2 = _interopRequireDefault(_filt); var _view = require("./utils/view"); +var _proxyapp = require("../components/proxyapp"); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var UPDATE_FLOWS = exports.UPDATE_FLOWS = "UPDATE_FLOWS"; @@ -4614,6 +4589,23 @@ function setHighlight(highlight) { }; } function selectFlow(flowId) { + var detailTab = arguments.length <= 1 || arguments[1] === undefined ? "request" : arguments[1]; + + var pathname = void 0; + if (flowId) { + pathname = "/flows/" + flowId + "/" + detailTab; + } else { + pathname = "/flows"; + } + + /* + let location + history.listen(l => {location = l})() + history.replace({ + ...location, + pathname + }) + */ return { type: SELECT_FLOW, flowId: flowId @@ -4623,7 +4615,7 @@ function selectFlow(flowId) { exports.updateFlows = updateList; exports.fetchFlows = fetchList; -},{"../filt/filt":29,"./utils/list":26,"./utils/view":27}],25:[function(require,module,exports){ +},{"../components/proxyapp":20,"../filt/filt":29,"./utils/list":26,"./utils/view":27}],25:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, "__esModule", { @@ -4757,7 +4749,7 @@ function makeList(actionType, fetchURL) { list = [].concat(_toConsumableArray(state.list)); itemIndex = state.indexOf[action.item.id]; list[itemIndex] = action.item; - return _extends({}, defaultState, { + return _extends({}, state, { list: list }); @@ -4765,14 +4757,14 @@ function makeList(actionType, fetchURL) { list = [].concat(_toConsumableArray(state.list)); itemIndex = state.indexOf[action.item.id]; list.splice(itemIndex, 1); - return _extends({}, defaultState, { + return _extends({}, state, { list: list, byId: _extends({}, state.byId, _defineProperty({}, action.item.id, undefined)), indexOf: _extends({}, state.indexOf, _defineProperty({}, action.item.id, undefined)) }); case REQUEST_LIST: - return _extends({}, defaultState, { + return _extends({}, state, { isFetching: true }); diff --git a/mitmproxy/web/static/vendor.js b/mitmproxy/web/static/vendor.js index 7fab13f51..b2e490436 100644 --- a/mitmproxy/web/static/vendor.js +++ b/mitmproxy/web/static/vendor.js @@ -7089,7 +7089,7 @@ var AutoFocusUtils = { }; module.exports = AutoFocusUtils; -},{"./ReactDOMComponentTree":116,"fbjs/lib/focusNode":223}],78:[function(require,module,exports){ +},{"./ReactDOMComponentTree":117,"fbjs/lib/focusNode":223}],78:[function(require,module,exports){ /** * Copyright 2013-present Facebook, Inc. * All rights reserved. @@ -7644,7 +7644,7 @@ module.exports = CSSProperty; var CSSProperty = require('./CSSProperty'); var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); -var ReactPerf = require('./ReactPerf'); +var ReactInstrumentation = require('./ReactInstrumentation'); var camelizeStyleName = require('fbjs/lib/camelizeStyleName'); var dangerousStyleValue = require('./dangerousStyleValue'); @@ -7798,6 +7798,10 @@ var CSSPropertyOperations = { * @param {ReactDOMComponent} component */ setValueForStyles: function (node, styles, component) { + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onNativeOperation(component._debugID, 'update styles', styles); + } + var style = node.style; for (var styleName in styles) { if (!styles.hasOwnProperty(styleName)) { @@ -7829,14 +7833,10 @@ var CSSPropertyOperations = { }; -ReactPerf.measureMethods(CSSPropertyOperations, 'CSSPropertyOperations', { - setValueForStyles: 'setValueForStyles' -}); - module.exports = CSSPropertyOperations; }).call(this,require('_process')) -},{"./CSSProperty":79,"./ReactPerf":157,"./dangerousStyleValue":189,"_process":33,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/camelizeStyleName":217,"fbjs/lib/hyphenateStyleName":228,"fbjs/lib/memoizeStringOnly":235,"fbjs/lib/warning":239}],81:[function(require,module,exports){ +},{"./CSSProperty":79,"./ReactInstrumentation":146,"./dangerousStyleValue":189,"_process":33,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/camelizeStyleName":217,"fbjs/lib/hyphenateStyleName":228,"fbjs/lib/memoizeStringOnly":235,"fbjs/lib/warning":239}],81:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -8271,7 +8271,8 @@ var ChangeEventPlugin = { }; module.exports = ChangeEventPlugin; -},{"./EventConstants":92,"./EventPluginHub":93,"./EventPropagators":96,"./ReactDOMComponentTree":116,"./ReactUpdates":165,"./SyntheticEvent":174,"./getEventTarget":197,"./isEventSupported":204,"./isTextInputElement":205,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/keyOf":233}],83:[function(require,module,exports){ +},{"./EventConstants":92,"./EventPluginHub":93,"./EventPropagators":96,"./ReactDOMComponentTree":117,"./ReactUpdates":165,"./SyntheticEvent":174,"./getEventTarget":197,"./isEventSupported":204,"./isTextInputElement":205,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/keyOf":233}],83:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -8288,7 +8289,8 @@ module.exports = ChangeEventPlugin; var DOMLazyTree = require('./DOMLazyTree'); var Danger = require('./Danger'); var ReactMultiChildUpdateTypes = require('./ReactMultiChildUpdateTypes'); -var ReactPerf = require('./ReactPerf'); +var ReactDOMComponentTree = require('./ReactDOMComponentTree'); +var ReactInstrumentation = require('./ReactInstrumentation'); var createMicrosoftUnsafeLocalFunction = require('./createMicrosoftUnsafeLocalFunction'); var setInnerHTML = require('./setInnerHTML'); @@ -8383,6 +8385,25 @@ function replaceDelimitedText(openingComment, closingComment, stringText) { removeDelimitedText(parentNode, openingComment, closingComment); } } + + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onNativeOperation(ReactDOMComponentTree.getInstanceFromNode(openingComment)._debugID, 'replace text', stringText); + } +} + +var dangerouslyReplaceNodeWithMarkup = Danger.dangerouslyReplaceNodeWithMarkup; +if (process.env.NODE_ENV !== 'production') { + dangerouslyReplaceNodeWithMarkup = function (oldChild, markup, prevInstance) { + Danger.dangerouslyReplaceNodeWithMarkup(oldChild, markup); + if (prevInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onNativeOperation(prevInstance._debugID, 'replace with', markup.toString()); + } else { + var nextInstance = ReactDOMComponentTree.getInstanceFromNode(markup.node); + if (nextInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onNativeOperation(nextInstance._debugID, 'mount', markup.toString()); + } + } + }; } /** @@ -8390,7 +8411,7 @@ function replaceDelimitedText(openingComment, closingComment, stringText) { */ var DOMChildrenOperations = { - dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, + dangerouslyReplaceNodeWithMarkup: dangerouslyReplaceNodeWithMarkup, replaceDelimitedText: replaceDelimitedText, @@ -8402,23 +8423,42 @@ var DOMChildrenOperations = { * @internal */ processUpdates: function (parentNode, updates) { + if (process.env.NODE_ENV !== 'production') { + var parentNodeDebugID = ReactDOMComponentTree.getInstanceFromNode(parentNode)._debugID; + } + for (var k = 0; k < updates.length; k++) { var update = updates[k]; switch (update.type) { case ReactMultiChildUpdateTypes.INSERT_MARKUP: insertLazyTreeChildAt(parentNode, update.content, getNodeAfter(parentNode, update.afterNode)); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onNativeOperation(parentNodeDebugID, 'insert child', { toIndex: update.toIndex, content: update.content.toString() }); + } break; case ReactMultiChildUpdateTypes.MOVE_EXISTING: moveChild(parentNode, update.fromNode, getNodeAfter(parentNode, update.afterNode)); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onNativeOperation(parentNodeDebugID, 'move child', { fromIndex: update.fromIndex, toIndex: update.toIndex }); + } break; case ReactMultiChildUpdateTypes.SET_MARKUP: setInnerHTML(parentNode, update.content); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onNativeOperation(parentNodeDebugID, 'replace children', update.content.toString()); + } break; case ReactMultiChildUpdateTypes.TEXT_CONTENT: setTextContent(parentNode, update.content); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onNativeOperation(parentNodeDebugID, 'replace text', update.content.toString()); + } break; case ReactMultiChildUpdateTypes.REMOVE_NODE: removeChild(parentNode, update.fromNode); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onNativeOperation(parentNodeDebugID, 'remove child', { fromIndex: update.fromIndex }); + } break; } } @@ -8426,12 +8466,10 @@ var DOMChildrenOperations = { }; -ReactPerf.measureMethods(DOMChildrenOperations, 'DOMChildrenOperations', { - replaceDelimitedText: 'replaceDelimitedText' -}); - module.exports = DOMChildrenOperations; -},{"./DOMLazyTree":84,"./Danger":88,"./ReactMultiChildUpdateTypes":152,"./ReactPerf":157,"./createMicrosoftUnsafeLocalFunction":188,"./setInnerHTML":209,"./setTextContent":210}],84:[function(require,module,exports){ +}).call(this,require('_process')) + +},{"./DOMLazyTree":84,"./Danger":88,"./ReactDOMComponentTree":117,"./ReactInstrumentation":146,"./ReactMultiChildUpdateTypes":151,"./createMicrosoftUnsafeLocalFunction":188,"./setInnerHTML":209,"./setTextContent":210,"_process":33}],84:[function(require,module,exports){ /** * Copyright 2015-present, Facebook, Inc. * All rights reserved. @@ -8445,9 +8483,14 @@ module.exports = DOMChildrenOperations; 'use strict'; +var DOMNamespaces = require('./DOMNamespaces'); + var createMicrosoftUnsafeLocalFunction = require('./createMicrosoftUnsafeLocalFunction'); var setTextContent = require('./setTextContent'); +var ELEMENT_NODE_TYPE = 1; +var DOCUMENT_FRAGMENT_NODE_TYPE = 11; + /** * In IE (8-11) and Edge, appending nodes with no children is dramatically * faster than appending a full subtree, so we essentially queue up the @@ -8482,8 +8525,10 @@ var insertTreeBefore = createMicrosoftUnsafeLocalFunction(function (parentNode, // DocumentFragments aren't actually part of the DOM after insertion so // appending children won't update the DOM. We need to ensure the fragment // is properly populated first, breaking out of our lazy approach for just - // this level. - if (tree.node.nodeType === 11) { + // this level. Also, some plugins (like Flash Player) will read + // nodes immediately upon insertion into the DOM, so + // must also be populated prior to insertion into the DOM. + if (tree.node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE || tree.node.nodeType === ELEMENT_NODE_TYPE && tree.node.nodeName.toLowerCase() === 'object' && (tree.node.namespaceURI == null || tree.node.namespaceURI === DOMNamespaces.html)) { insertTreeChildren(tree); parentNode.insertBefore(tree.node, referenceNode); } else { @@ -8521,12 +8566,17 @@ function queueText(tree, text) { } } +function toString() { + return this.node.nodeName; +} + function DOMLazyTree(node) { return { node: node, children: [], html: null, - text: null + text: null, + toString: toString }; } @@ -8537,7 +8587,7 @@ DOMLazyTree.queueHTML = queueHTML; DOMLazyTree.queueText = queueText; module.exports = DOMLazyTree; -},{"./createMicrosoftUnsafeLocalFunction":188,"./setTextContent":210}],85:[function(require,module,exports){ +},{"./DOMNamespaces":85,"./createMicrosoftUnsafeLocalFunction":188,"./setTextContent":210}],85:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -8791,8 +8841,9 @@ module.exports = DOMProperty; 'use strict'; var DOMProperty = require('./DOMProperty'); +var ReactDOMComponentTree = require('./ReactDOMComponentTree'); var ReactDOMInstrumentation = require('./ReactDOMInstrumentation'); -var ReactPerf = require('./ReactPerf'); +var ReactInstrumentation = require('./ReactInstrumentation'); var quoteAttributeValueForBrowser = require('./quoteAttributeValueForBrowser'); var warning = require('fbjs/lib/warning'); @@ -8900,9 +8951,6 @@ var DOMPropertyOperations = { * @param {*} value */ setValueForProperty: function (node, name, value) { - if (process.env.NODE_ENV !== 'production') { - ReactDOMInstrumentation.debugTool.onSetValueForProperty(node, name, value); - } var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null; if (propertyInfo) { var mutationMethod = propertyInfo.mutationMethod; @@ -8910,6 +8958,7 @@ var DOMPropertyOperations = { mutationMethod(node, value); } else if (shouldIgnoreValue(propertyInfo, value)) { this.deleteValueForProperty(node, name); + return; } else if (propertyInfo.mustUseProperty) { var propName = propertyInfo.propertyName; // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the @@ -8934,6 +8983,14 @@ var DOMPropertyOperations = { } } else if (DOMProperty.isCustomAttribute(name)) { DOMPropertyOperations.setValueForAttribute(node, name, value); + return; + } + + if (process.env.NODE_ENV !== 'production') { + ReactDOMInstrumentation.debugTool.onSetValueForProperty(node, name, value); + var payload = {}; + payload[name] = value; + ReactInstrumentation.debugTool.onNativeOperation(ReactDOMComponentTree.getInstanceFromNode(node)._debugID, 'update attribute', payload); } }, @@ -8946,6 +9003,12 @@ var DOMPropertyOperations = { } else { node.setAttribute(name, '' + value); } + + if (process.env.NODE_ENV !== 'production') { + var payload = {}; + payload[name] = value; + ReactInstrumentation.debugTool.onNativeOperation(ReactDOMComponentTree.getInstanceFromNode(node)._debugID, 'update attribute', payload); + } }, /** @@ -8955,9 +9018,6 @@ var DOMPropertyOperations = { * @param {string} name */ deleteValueForProperty: function (node, name) { - if (process.env.NODE_ENV !== 'production') { - ReactDOMInstrumentation.debugTool.onDeleteValueForProperty(node, name); - } var propertyInfo = DOMProperty.properties.hasOwnProperty(name) ? DOMProperty.properties[name] : null; if (propertyInfo) { var mutationMethod = propertyInfo.mutationMethod; @@ -8979,20 +9039,19 @@ var DOMPropertyOperations = { } else if (DOMProperty.isCustomAttribute(name)) { node.removeAttribute(name); } + + if (process.env.NODE_ENV !== 'production') { + ReactDOMInstrumentation.debugTool.onDeleteValueForProperty(node, name); + ReactInstrumentation.debugTool.onNativeOperation(ReactDOMComponentTree.getInstanceFromNode(node)._debugID, 'remove attribute', name); + } } }; -ReactPerf.measureMethods(DOMPropertyOperations, 'DOMPropertyOperations', { - setValueForProperty: 'setValueForProperty', - setValueForAttribute: 'setValueForAttribute', - deleteValueForProperty: 'deleteValueForProperty' -}); - module.exports = DOMPropertyOperations; }).call(this,require('_process')) -},{"./DOMProperty":86,"./ReactDOMInstrumentation":124,"./ReactPerf":157,"./quoteAttributeValueForBrowser":207,"_process":33,"fbjs/lib/warning":239}],88:[function(require,module,exports){ +},{"./DOMProperty":86,"./ReactDOMComponentTree":117,"./ReactDOMInstrumentation":125,"./ReactInstrumentation":146,"./quoteAttributeValueForBrowser":207,"_process":33,"fbjs/lib/warning":239}],88:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -9325,7 +9384,7 @@ var EnterLeaveEventPlugin = { }; module.exports = EnterLeaveEventPlugin; -},{"./EventConstants":92,"./EventPropagators":96,"./ReactDOMComponentTree":116,"./SyntheticMouseEvent":178,"fbjs/lib/keyOf":233}],92:[function(require,module,exports){ +},{"./EventConstants":92,"./EventPropagators":96,"./ReactDOMComponentTree":117,"./SyntheticMouseEvent":178,"fbjs/lib/keyOf":233}],92:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -9662,7 +9721,7 @@ var EventPluginHub = { module.exports = EventPluginHub; }).call(this,require('_process')) -},{"./EventPluginRegistry":94,"./EventPluginUtils":95,"./ReactErrorUtils":140,"./accumulateInto":185,"./forEachAccumulated":193,"_process":33,"fbjs/lib/invariant":229}],94:[function(require,module,exports){ +},{"./EventPluginRegistry":94,"./EventPluginUtils":95,"./ReactErrorUtils":139,"./accumulateInto":185,"./forEachAccumulated":193,"_process":33,"fbjs/lib/invariant":229}],94:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -10138,7 +10197,7 @@ var EventPluginUtils = { module.exports = EventPluginUtils; }).call(this,require('_process')) -},{"./EventConstants":92,"./ReactErrorUtils":140,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],96:[function(require,module,exports){ +},{"./EventConstants":92,"./ReactErrorUtils":139,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],96:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -10781,7 +10840,7 @@ var LinkedValueUtils = { module.exports = LinkedValueUtils; }).call(this,require('_process')) -},{"./ReactPropTypeLocations":159,"./ReactPropTypes":160,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],101:[function(require,module,exports){ +},{"./ReactPropTypeLocations":158,"./ReactPropTypes":159,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],101:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -10995,7 +11054,7 @@ var React = { module.exports = React; }).call(this,require('_process')) -},{"./ReactChildren":105,"./ReactClass":106,"./ReactComponent":107,"./ReactDOMFactories":120,"./ReactElement":137,"./ReactElementValidator":138,"./ReactPropTypes":160,"./ReactVersion":166,"./onlyChild":206,"_process":33,"fbjs/lib/warning":239,"object-assign":32}],103:[function(require,module,exports){ +},{"./ReactChildren":105,"./ReactClass":106,"./ReactComponent":107,"./ReactDOMFactories":121,"./ReactElement":136,"./ReactElementValidator":137,"./ReactPropTypes":159,"./ReactVersion":166,"./onlyChild":206,"_process":33,"fbjs/lib/warning":239,"object-assign":32}],103:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -11313,7 +11372,7 @@ var ReactBrowserEventEmitter = _assign({}, ReactEventEmitterMixin, { }); module.exports = ReactBrowserEventEmitter; -},{"./EventConstants":92,"./EventPluginRegistry":94,"./ReactEventEmitterMixin":141,"./ViewportMetrics":184,"./getVendorPrefixedEventName":202,"./isEventSupported":204,"object-assign":32}],104:[function(require,module,exports){ +},{"./EventConstants":92,"./EventPluginRegistry":94,"./ReactEventEmitterMixin":140,"./ViewportMetrics":184,"./getVendorPrefixedEventName":202,"./isEventSupported":204,"object-assign":32}],104:[function(require,module,exports){ (function (process){ /** * Copyright 2014-present, Facebook, Inc. @@ -11442,7 +11501,7 @@ var ReactChildReconciler = { module.exports = ReactChildReconciler; }).call(this,require('_process')) -},{"./KeyEscapeUtils":99,"./ReactReconciler":162,"./instantiateReactComponent":203,"./shouldUpdateReactComponent":211,"./traverseAllChildren":212,"_process":33,"fbjs/lib/warning":239}],105:[function(require,module,exports){ +},{"./KeyEscapeUtils":99,"./ReactReconciler":161,"./instantiateReactComponent":203,"./shouldUpdateReactComponent":211,"./traverseAllChildren":212,"_process":33,"fbjs/lib/warning":239}],105:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -11500,6 +11559,8 @@ function forEachSingleChild(bookKeeping, child, name) { /** * Iterates through children that are typically specified as `props.children`. * + * See https://facebook.github.io/react/docs/top-level-api.html#react.children.foreach + * * The provided forEachFunc(child, index) will be called for each * leaf child. * @@ -11575,7 +11636,9 @@ function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) { /** * Maps children that are typically specified as `props.children`. * - * The provided mapFunction(child, index) will be called for each + * See https://facebook.github.io/react/docs/top-level-api.html#react.children.map + * + * The provided mapFunction(child, key, index) will be called for each * leaf child. * * @param {?*} children Children tree container. @@ -11600,6 +11663,8 @@ function forEachSingleChildDummy(traverseContext, child, name) { * Count the number of children that are typically specified as * `props.children`. * + * See https://facebook.github.io/react/docs/top-level-api.html#react.children.count + * * @param {?*} children Children tree container. * @return {number} The number of children. */ @@ -11610,6 +11675,8 @@ function countChildren(children, context) { /** * Flatten a children object (typically specified as `props.children`) and * return an array with appropriately re-keyed children. + * + * See https://facebook.github.io/react/docs/top-level-api.html#react.children.toarray */ function toArray(children) { var result = []; @@ -11626,7 +11693,7 @@ var ReactChildren = { }; module.exports = ReactChildren; -},{"./PooledClass":101,"./ReactElement":137,"./traverseAllChildren":212,"fbjs/lib/emptyFunction":221}],106:[function(require,module,exports){ +},{"./PooledClass":101,"./ReactElement":136,"./traverseAllChildren":212,"fbjs/lib/emptyFunction":221}],106:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -12257,6 +12324,7 @@ var ReactClass = { /** * 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. @@ -12353,7 +12421,7 @@ var ReactClass = { module.exports = ReactClass; }).call(this,require('_process')) -},{"./ReactComponent":107,"./ReactElement":137,"./ReactNoopUpdateQueue":155,"./ReactPropTypeLocationNames":158,"./ReactPropTypeLocations":159,"_process":33,"fbjs/lib/emptyObject":222,"fbjs/lib/invariant":229,"fbjs/lib/keyMirror":232,"fbjs/lib/keyOf":233,"fbjs/lib/warning":239,"object-assign":32}],107:[function(require,module,exports){ +},{"./ReactComponent":107,"./ReactElement":136,"./ReactNoopUpdateQueue":155,"./ReactPropTypeLocationNames":157,"./ReactPropTypeLocations":158,"_process":33,"fbjs/lib/emptyObject":222,"fbjs/lib/invariant":229,"fbjs/lib/keyMirror":232,"fbjs/lib/keyOf":233,"fbjs/lib/warning":239,"object-assign":32}],107:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -12478,7 +12546,7 @@ if (process.env.NODE_ENV !== 'production') { module.exports = ReactComponent; }).call(this,require('_process')) -},{"./ReactInstrumentation":147,"./ReactNoopUpdateQueue":155,"./canDefineProperty":187,"_process":33,"fbjs/lib/emptyObject":222,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],108:[function(require,module,exports){ +},{"./ReactInstrumentation":146,"./ReactNoopUpdateQueue":155,"./canDefineProperty":187,"_process":33,"fbjs/lib/emptyObject":222,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],108:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -12494,7 +12562,6 @@ module.exports = ReactComponent; var DOMChildrenOperations = require('./DOMChildrenOperations'); var ReactDOMIDOperations = require('./ReactDOMIDOperations'); -var ReactPerf = require('./ReactPerf'); /** * Abstracts away all functionality of the reconciler that requires knowledge of @@ -12518,12 +12585,8 @@ var ReactComponentBrowserEnvironment = { }; -ReactPerf.measureMethods(ReactComponentBrowserEnvironment, 'ReactComponentBrowserEnvironment', { - replaceNodeWithMarkup: 'replaceNodeWithMarkup' -}); - module.exports = ReactComponentBrowserEnvironment; -},{"./DOMChildrenOperations":83,"./ReactDOMIDOperations":122,"./ReactPerf":157}],109:[function(require,module,exports){ +},{"./DOMChildrenOperations":83,"./ReactDOMIDOperations":123}],109:[function(require,module,exports){ (function (process){ /** * Copyright 2014-present, Facebook, Inc. @@ -12580,6 +12643,155 @@ module.exports = ReactComponentEnvironment; },{"_process":33,"fbjs/lib/invariant":229}],110:[function(require,module,exports){ (function (process){ +/** + * Copyright 2016-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. + * + * @providesModule ReactComponentTreeDevtool + */ + +'use strict'; + +var invariant = require('fbjs/lib/invariant'); + +var tree = {}; +var rootIDs = []; + +function updateTree(id, update) { + if (!tree[id]) { + tree[id] = { + parentID: null, + ownerID: null, + text: null, + childIDs: [], + displayName: 'Unknown', + isMounted: false, + updateCount: 0 + }; + } + update(tree[id]); +} + +function purgeDeep(id) { + var item = tree[id]; + if (item) { + var childIDs = item.childIDs; + + delete tree[id]; + childIDs.forEach(purgeDeep); + } +} + +var ReactComponentTreeDevtool = { + onSetDisplayName: function (id, displayName) { + updateTree(id, function (item) { + return item.displayName = displayName; + }); + }, + onSetChildren: function (id, nextChildIDs) { + updateTree(id, function (item) { + var prevChildIDs = item.childIDs; + item.childIDs = nextChildIDs; + + nextChildIDs.forEach(function (nextChildID) { + var nextChild = tree[nextChildID]; + !nextChild ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected devtool events to fire for the child ' + 'before its parent includes it in onSetChildren().') : invariant(false) : void 0; + !(nextChild.displayName != null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected onSetDisplayName() to fire for the child ' + 'before its parent includes it in onSetChildren().') : invariant(false) : void 0; + !(nextChild.childIDs != null || nextChild.text != null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected onSetChildren() or onSetText() to fire for the child ' + 'before its parent includes it in onSetChildren().') : invariant(false) : void 0; + !nextChild.isMounted ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Expected onMountComponent() to fire for the child ' + 'before its parent includes it in onSetChildren().') : invariant(false) : void 0; + + if (prevChildIDs.indexOf(nextChildID) === -1) { + nextChild.parentID = id; + } + }); + }); + }, + onSetOwner: function (id, ownerID) { + updateTree(id, function (item) { + return item.ownerID = ownerID; + }); + }, + onSetText: function (id, text) { + updateTree(id, function (item) { + return item.text = text; + }); + }, + onMountComponent: function (id) { + updateTree(id, function (item) { + return item.isMounted = true; + }); + }, + onMountRootComponent: function (id) { + rootIDs.push(id); + }, + onUpdateComponent: function (id) { + updateTree(id, function (item) { + return item.updateCount++; + }); + }, + onUnmountComponent: function (id) { + updateTree(id, function (item) { + return item.isMounted = false; + }); + rootIDs = rootIDs.filter(function (rootID) { + return rootID !== id; + }); + }, + purgeUnmountedComponents: function () { + if (ReactComponentTreeDevtool._preventPurging) { + // Should only be used for testing. + return; + } + + Object.keys(tree).filter(function (id) { + return !tree[id].isMounted; + }).forEach(purgeDeep); + }, + isMounted: function (id) { + var item = tree[id]; + return item ? item.isMounted : false; + }, + getChildIDs: function (id) { + var item = tree[id]; + return item ? item.childIDs : []; + }, + getDisplayName: function (id) { + var item = tree[id]; + return item ? item.displayName : 'Unknown'; + }, + getOwnerID: function (id) { + var item = tree[id]; + return item ? item.ownerID : null; + }, + getParentID: function (id) { + var item = tree[id]; + return item ? item.parentID : null; + }, + getText: function (id) { + var item = tree[id]; + return item ? item.text : null; + }, + getUpdateCount: function (id) { + var item = tree[id]; + return item ? item.updateCount : 0; + }, + getRootIDs: function () { + return rootIDs; + }, + getRegisteredIDs: function () { + return Object.keys(tree); + } +}; + +module.exports = ReactComponentTreeDevtool; +}).call(this,require('_process')) + +},{"_process":33,"fbjs/lib/invariant":229}],111:[function(require,module,exports){ +(function (process){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -12602,7 +12814,6 @@ var ReactErrorUtils = require('./ReactErrorUtils'); var ReactInstanceMap = require('./ReactInstanceMap'); var ReactInstrumentation = require('./ReactInstrumentation'); var ReactNodeTypes = require('./ReactNodeTypes'); -var ReactPerf = require('./ReactPerf'); var ReactPropTypeLocations = require('./ReactPropTypeLocations'); var ReactPropTypeLocationNames = require('./ReactPropTypeLocationNames'); var ReactReconciler = require('./ReactReconciler'); @@ -12638,6 +12849,28 @@ function warnIfInvalidElement(Component, element) { } } +function invokeComponentDidMountWithTimer() { + var publicInstance = this._instance; + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginLifeCycleTimer(this._debugID, 'componentDidMount'); + } + publicInstance.componentDidMount(); + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onEndLifeCycleTimer(this._debugID, 'componentDidMount'); + } +} + +function invokeComponentDidUpdateWithTimer(prevProps, prevState, prevContext) { + var publicInstance = this._instance; + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginLifeCycleTimer(this._debugID, 'componentDidUpdate'); + } + publicInstance.componentDidUpdate(prevProps, prevState, prevContext); + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onEndLifeCycleTimer(this._debugID, 'componentDidUpdate'); + } +} + function shouldConstruct(Component) { return Component.prototype && Component.prototype.isReactComponent; } @@ -12697,6 +12930,7 @@ var ReactCompositeComponentMixin = { this._nativeContainerInfo = null; // See ReactUpdateQueue + this._updateBatchNumber = null; this._pendingElement = null; this._pendingStateQueue = null; this._pendingReplaceState = false; @@ -12805,7 +13039,11 @@ var ReactCompositeComponentMixin = { } if (inst.componentDidMount) { - transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); + if (process.env.NODE_ENV !== 'production') { + transaction.getReactMountReady().enqueue(invokeComponentDidMountWithTimer, this); + } else { + transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); + } } return markup; @@ -12826,11 +13064,35 @@ var ReactCompositeComponentMixin = { _constructComponentWithoutOwner: function (publicProps, publicContext) { var Component = this._currentElement.type; + var instanceOrElement; if (shouldConstruct(Component)) { - return new Component(publicProps, publicContext, ReactUpdateQueue); + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginLifeCycleTimer(this._debugID, 'ctor'); + } + } + instanceOrElement = new Component(publicProps, publicContext, ReactUpdateQueue); + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onEndLifeCycleTimer(this._debugID, 'ctor'); + } + } } else { - return Component(publicProps, publicContext, ReactUpdateQueue); + // This can still be an instance in case of factory components + // but we'll count this as time spent rendering as the more common case. + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginLifeCycleTimer(this._debugID, 'render'); + } + } + instanceOrElement = Component(publicProps, publicContext, ReactUpdateQueue); + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onEndLifeCycleTimer(this._debugID, 'render'); + } + } } + return instanceOrElement; }, performInitialMountWithErrorHandling: function (renderedElement, nativeParent, nativeContainerInfo, transaction, context) { @@ -12860,7 +13122,17 @@ var ReactCompositeComponentMixin = { performInitialMount: function (renderedElement, nativeParent, nativeContainerInfo, transaction, context) { var inst = this._instance; if (inst.componentWillMount) { + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginLifeCycleTimer(this._debugID, 'componentWillMount'); + } + } inst.componentWillMount(); + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onEndLifeCycleTimer(this._debugID, 'componentWillMount'); + } + } // When mounting, calls to `setState` by `componentWillMount` will set // `this._pendingStateQueue` without triggering a re-render. if (this._pendingStateQueue) { @@ -12878,6 +13150,12 @@ var ReactCompositeComponentMixin = { var markup = ReactReconciler.mountComponent(this._renderedComponent, transaction, nativeParent, nativeContainerInfo, this._processChildContext(context)); + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onSetChildren(this._debugID, this._renderedComponent._debugID !== 0 ? [this._renderedComponent._debugID] : []); + } + } + return markup; }, @@ -12899,12 +13177,22 @@ var ReactCompositeComponentMixin = { if (inst.componentWillUnmount && !inst._calledComponentWillUnmount) { inst._calledComponentWillUnmount = true; + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginLifeCycleTimer(this._debugID, 'componentWillUnmount'); + } + } if (safely) { var name = this.getName() + '.componentWillUnmount()'; ReactErrorUtils.invokeGuardedCallback(name, inst.componentWillUnmount.bind(inst)); } else { inst.componentWillUnmount(); } + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onEndLifeCycleTimer(this._debugID, 'componentWillUnmount'); + } + } } if (this._renderedComponent) { @@ -13087,10 +13375,10 @@ var ReactCompositeComponentMixin = { performUpdateIfNecessary: function (transaction) { if (this._pendingElement != null) { ReactReconciler.receiveComponent(this, this._pendingElement, transaction, this._context); - } - - if (this._pendingStateQueue !== null || this._pendingForceUpdate) { + } else if (this._pendingStateQueue !== null || this._pendingForceUpdate) { this.updateComponent(transaction, this._currentElement, this._currentElement, this._context, this._context); + } else { + this._updateBatchNumber = null; } }, @@ -13137,17 +13425,41 @@ var ReactCompositeComponentMixin = { // _pendingStateQueue which will ensure that any state updates gets // immediately reconciled instead of waiting for the next batch. if (willReceive && inst.componentWillReceiveProps) { + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginLifeCycleTimer(this._debugID, 'componentWillReceiveProps'); + } + } inst.componentWillReceiveProps(nextProps, nextContext); + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onEndLifeCycleTimer(this._debugID, 'componentWillReceiveProps'); + } + } } var nextState = this._processPendingState(nextProps, nextContext); + var shouldUpdate = true; - var shouldUpdate = this._pendingForceUpdate || !inst.shouldComponentUpdate || inst.shouldComponentUpdate(nextProps, nextState, nextContext); + if (!this._pendingForceUpdate && inst.shouldComponentUpdate) { + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginLifeCycleTimer(this._debugID, 'shouldComponentUpdate'); + } + } + shouldUpdate = inst.shouldComponentUpdate(nextProps, nextState, nextContext); + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onEndLifeCycleTimer(this._debugID, 'shouldComponentUpdate'); + } + } + } if (process.env.NODE_ENV !== 'production') { process.env.NODE_ENV !== 'production' ? warning(shouldUpdate !== undefined, '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', this.getName() || 'ReactCompositeComponent') : void 0; } + this._updateBatchNumber = null; if (shouldUpdate) { this._pendingForceUpdate = false; // Will set `this.props`, `this.state` and `this.context`. @@ -13213,7 +13525,17 @@ var ReactCompositeComponentMixin = { } if (inst.componentWillUpdate) { + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginLifeCycleTimer(this._debugID, 'componentWillUpdate'); + } + } inst.componentWillUpdate(nextProps, nextState, nextContext); + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onEndLifeCycleTimer(this._debugID, 'componentWillUpdate'); + } + } } this._currentElement = nextElement; @@ -13225,7 +13547,11 @@ var ReactCompositeComponentMixin = { this._updateRenderedComponent(transaction, unmaskedContext); if (hasComponentDidUpdate) { - transaction.getReactMountReady().enqueue(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), inst); + if (process.env.NODE_ENV !== 'production') { + transaction.getReactMountReady().enqueue(invokeComponentDidUpdateWithTimer.bind(this, prevProps, prevState, prevContext), this); + } else { + transaction.getReactMountReady().enqueue(inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), inst); + } } }, @@ -13247,8 +13573,16 @@ var ReactCompositeComponentMixin = { this._renderedNodeType = ReactNodeTypes.getType(nextRenderedElement); this._renderedComponent = this._instantiateReactComponent(nextRenderedElement); + var nextMarkup = ReactReconciler.mountComponent(this._renderedComponent, transaction, this._nativeParent, this._nativeContainerInfo, this._processChildContext(context)); - this._replaceNodeWithMarkup(oldNativeNode, nextMarkup); + + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onSetChildren(this._debugID, this._renderedComponent._debugID !== 0 ? [this._renderedComponent._debugID] : []); + } + } + + this._replaceNodeWithMarkup(oldNativeNode, nextMarkup, prevComponentInstance); } }, @@ -13257,8 +13591,8 @@ var ReactCompositeComponentMixin = { * * @protected */ - _replaceNodeWithMarkup: function (oldNativeNode, nextMarkup) { - ReactComponentEnvironment.replaceNodeWithMarkup(oldNativeNode, nextMarkup); + _replaceNodeWithMarkup: function (oldNativeNode, nextMarkup, prevInstance) { + ReactComponentEnvironment.replaceNodeWithMarkup(oldNativeNode, nextMarkup, prevInstance); }, /** @@ -13266,7 +13600,19 @@ var ReactCompositeComponentMixin = { */ _renderValidatedComponentWithoutOwnerOrContext: function () { var inst = this._instance; + + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginLifeCycleTimer(this._debugID, 'render'); + } + } var renderedComponent = inst.render(); + if (process.env.NODE_ENV !== 'production') { + if (this._debugID !== 0) { + ReactInstrumentation.debugTool.onEndLifeCycleTimer(this._debugID, 'render'); + } + } + if (process.env.NODE_ENV !== 'production') { // We allow auto-mocks to proceed as if they're returning null. if (renderedComponent === undefined && inst.render._isMockFunction) { @@ -13293,6 +13639,7 @@ var ReactCompositeComponentMixin = { !( // TODO: An `isValidNode` function would probably be more appropriate renderedComponent === null || renderedComponent === false || ReactElement.isValidElement(renderedComponent)) ? process.env.NODE_ENV !== 'production' ? invariant(false, '%s.render(): A valid React element (or null) must be returned. You may have ' + 'returned undefined, an array or some other invalid object.', this.getName() || 'ReactCompositeComponent') : invariant(false) : void 0; + return renderedComponent; }, @@ -13361,12 +13708,6 @@ var ReactCompositeComponentMixin = { }; -ReactPerf.measureMethods(ReactCompositeComponentMixin, 'ReactCompositeComponent', { - mountComponent: 'mountComponent', - updateComponent: 'updateComponent', - _renderValidatedComponent: '_renderValidatedComponent' -}); - var ReactCompositeComponent = { Mixin: ReactCompositeComponentMixin @@ -13376,7 +13717,7 @@ var ReactCompositeComponent = { module.exports = ReactCompositeComponent; }).call(this,require('_process')) -},{"./ReactComponentEnvironment":109,"./ReactCurrentOwner":111,"./ReactElement":137,"./ReactErrorUtils":140,"./ReactInstanceMap":146,"./ReactInstrumentation":147,"./ReactNodeTypes":154,"./ReactPerf":157,"./ReactPropTypeLocationNames":158,"./ReactPropTypeLocations":159,"./ReactReconciler":162,"./ReactUpdateQueue":164,"./shouldUpdateReactComponent":211,"_process":33,"fbjs/lib/emptyObject":222,"fbjs/lib/invariant":229,"fbjs/lib/warning":239,"object-assign":32}],111:[function(require,module,exports){ +},{"./ReactComponentEnvironment":109,"./ReactCurrentOwner":112,"./ReactElement":136,"./ReactErrorUtils":139,"./ReactInstanceMap":145,"./ReactInstrumentation":146,"./ReactNodeTypes":154,"./ReactPropTypeLocationNames":157,"./ReactPropTypeLocations":158,"./ReactReconciler":161,"./ReactUpdateQueue":164,"./shouldUpdateReactComponent":211,"_process":33,"fbjs/lib/emptyObject":222,"fbjs/lib/invariant":229,"fbjs/lib/warning":239,"object-assign":32}],112:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -13408,7 +13749,7 @@ var ReactCurrentOwner = { }; module.exports = ReactCurrentOwner; -},{}],112:[function(require,module,exports){ +},{}],113:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -13428,7 +13769,6 @@ module.exports = ReactCurrentOwner; var ReactDOMComponentTree = require('./ReactDOMComponentTree'); var ReactDefaultInjection = require('./ReactDefaultInjection'); var ReactMount = require('./ReactMount'); -var ReactPerf = require('./ReactPerf'); var ReactReconciler = require('./ReactReconciler'); var ReactUpdates = require('./ReactUpdates'); var ReactVersion = require('./ReactVersion'); @@ -13440,11 +13780,9 @@ var warning = require('fbjs/lib/warning'); ReactDefaultInjection.inject(); -var render = ReactPerf.measure('React', 'render', ReactMount.render); - var React = { findDOMNode: findDOMNode, - render: render, + render: ReactMount.render, unmountComponentAtNode: ReactMount.unmountComponentAtNode, version: ReactVersion, @@ -13516,7 +13854,7 @@ if (process.env.NODE_ENV !== 'production') { module.exports = React; }).call(this,require('_process')) -},{"./ReactDOMComponentTree":116,"./ReactDefaultInjection":134,"./ReactMount":150,"./ReactPerf":157,"./ReactReconciler":162,"./ReactUpdates":165,"./ReactVersion":166,"./findDOMNode":191,"./getNativeComponentFromComposite":199,"./renderSubtreeIntoContainer":208,"_process":33,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/warning":239}],113:[function(require,module,exports){ +},{"./ReactDOMComponentTree":117,"./ReactDefaultInjection":135,"./ReactMount":149,"./ReactReconciler":161,"./ReactUpdates":165,"./ReactVersion":166,"./findDOMNode":191,"./getNativeComponentFromComposite":199,"./renderSubtreeIntoContainer":208,"_process":33,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/warning":239}],114:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -13541,7 +13879,7 @@ var ReactDOMButton = { }; module.exports = ReactDOMButton; -},{"./DisabledInputUtils":90}],114:[function(require,module,exports){ +},{"./DisabledInputUtils":90}],115:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -13578,9 +13916,11 @@ var ReactDOMInput = require('./ReactDOMInput'); var ReactDOMOption = require('./ReactDOMOption'); var ReactDOMSelect = require('./ReactDOMSelect'); var ReactDOMTextarea = require('./ReactDOMTextarea'); +var ReactInstrumentation = require('./ReactInstrumentation'); var ReactMultiChild = require('./ReactMultiChild'); -var ReactPerf = require('./ReactPerf'); +var ReactServerRenderingTransaction = require('./ReactServerRenderingTransaction'); +var emptyFunction = require('fbjs/lib/emptyFunction'); var escapeTextContentForBrowser = require('./escapeTextContentForBrowser'); var invariant = require('fbjs/lib/invariant'); var isEventSupported = require('./isEventSupported'); @@ -13699,6 +14039,9 @@ function assertValidProps(component, props) { } function enqueuePutListener(inst, registrationName, listener, transaction) { + if (transaction instanceof ReactServerRenderingTransaction) { + return; + } if (process.env.NODE_ENV !== 'production') { // IE8 has no API for event capturing and the `onScroll` event doesn't // bubble. @@ -13707,10 +14050,6 @@ function enqueuePutListener(inst, registrationName, listener, transaction) { var containerInfo = inst._nativeContainerInfo; var isDocumentFragment = containerInfo._node && containerInfo._node.nodeType === DOC_FRAGMENT_TYPE; var doc = isDocumentFragment ? containerInfo._node : containerInfo._ownerDocument; - if (!doc) { - // Server rendering. - return; - } listenTo(registrationName, doc); transaction.getReactMountReady().enqueue(putListener, { inst: inst, @@ -13729,6 +14068,19 @@ function optionPostMount() { ReactDOMOption.postMountWrapper(inst); } +var setContentChildForInstrumentation = emptyFunction; +if (process.env.NODE_ENV !== 'production') { + setContentChildForInstrumentation = function (contentToUse) { + var debugID = this._debugID; + var contentDebugID = debugID + '#text'; + this._contentDebugID = contentDebugID; + ReactInstrumentation.debugTool.onSetDisplayName(contentDebugID, '#text'); + ReactInstrumentation.debugTool.onSetText(contentDebugID, '' + contentToUse); + ReactInstrumentation.debugTool.onMountComponent(contentDebugID); + ReactInstrumentation.debugTool.onSetChildren(debugID, [contentDebugID]); + }; +} + // There are so many media events, it makes sense to just // maintain a list rather than create a `trapBubbledEvent` for each var mediaEvents = { @@ -13889,6 +14241,7 @@ function ReactDOMComponent(element) { this._flags = 0; if (process.env.NODE_ENV !== 'production') { this._ancestorInfo = null; + this._contentDebugID = null; } } @@ -14004,7 +14357,7 @@ ReactDOMComponent.Mixin = { div.innerHTML = '<' + type + '>'; el = div.removeChild(div.firstChild); } else { - el = ownerDocument.createElement(this._currentElement.type); + el = ownerDocument.createElement(this._currentElement.type, props.is || null); } } else { el = ownerDocument.createElementNS(namespaceURI, this._currentElement.type); @@ -14134,6 +14487,9 @@ ReactDOMComponent.Mixin = { if (contentToUse != null) { // TODO: Validate that text is allowed as a child of this node ret = escapeTextContentForBrowser(contentToUse); + if (process.env.NODE_ENV !== 'production') { + setContentChildForInstrumentation.call(this, contentToUse); + } } else if (childrenToUse != null) { var mountImages = this.mountChildren(childrenToUse, transaction, context); ret = mountImages.join(''); @@ -14168,6 +14524,9 @@ ReactDOMComponent.Mixin = { var childrenToUse = contentToUse != null ? null : props.children; if (contentToUse != null) { // TODO: Validate that text is allowed as a child of this node + if (process.env.NODE_ENV !== 'production') { + setContentChildForInstrumentation.call(this, contentToUse); + } DOMLazyTree.queueText(lazyTree, contentToUse); } else if (childrenToUse != null) { var mountImages = this.mountChildren(childrenToUse, transaction, context); @@ -14376,17 +14735,34 @@ ReactDOMComponent.Mixin = { this.updateChildren(null, transaction, context); } else if (lastHasContentOrHtml && !nextHasContentOrHtml) { this.updateTextContent(''); + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onSetChildren(this._debugID, []); + } } if (nextContent != null) { if (lastContent !== nextContent) { this.updateTextContent('' + nextContent); + if (process.env.NODE_ENV !== 'production') { + this._contentDebugID = this._debugID + '#text'; + setContentChildForInstrumentation.call(this, nextContent); + } } } else if (nextHtml != null) { if (lastHtml !== nextHtml) { this.updateMarkup('' + nextHtml); } + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onSetChildren(this._debugID, []); + } } else if (nextChildren != null) { + if (process.env.NODE_ENV !== 'production') { + if (this._contentDebugID) { + ReactInstrumentation.debugTool.onUnmountComponent(this._contentDebugID); + this._contentDebugID = null; + } + } + this.updateChildren(nextChildren, transaction, context); } }, @@ -14436,6 +14812,13 @@ ReactDOMComponent.Mixin = { this._rootNodeID = null; this._domID = null; this._wrapperState = null; + + if (process.env.NODE_ENV !== 'production') { + if (this._contentDebugID) { + ReactInstrumentation.debugTool.onUnmountComponent(this._contentDebugID); + this._contentDebugID = null; + } + } }, getPublicInstance: function () { @@ -14444,17 +14827,12 @@ ReactDOMComponent.Mixin = { }; -ReactPerf.measureMethods(ReactDOMComponent.Mixin, 'ReactDOMComponent', { - mountComponent: 'mountComponent', - receiveComponent: 'receiveComponent' -}); - _assign(ReactDOMComponent.prototype, ReactDOMComponent.Mixin, ReactMultiChild.Mixin); module.exports = ReactDOMComponent; }).call(this,require('_process')) -},{"./AutoFocusUtils":77,"./CSSPropertyOperations":80,"./DOMLazyTree":84,"./DOMNamespaces":85,"./DOMProperty":86,"./DOMPropertyOperations":87,"./EventConstants":92,"./EventPluginHub":93,"./EventPluginRegistry":94,"./ReactBrowserEventEmitter":103,"./ReactComponentBrowserEnvironment":108,"./ReactDOMButton":113,"./ReactDOMComponentFlags":115,"./ReactDOMComponentTree":116,"./ReactDOMInput":123,"./ReactDOMOption":125,"./ReactDOMSelect":126,"./ReactDOMTextarea":129,"./ReactMultiChild":151,"./ReactPerf":157,"./escapeTextContentForBrowser":190,"./isEventSupported":204,"./validateDOMNesting":213,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/keyOf":233,"fbjs/lib/shallowEqual":238,"fbjs/lib/warning":239,"object-assign":32}],115:[function(require,module,exports){ +},{"./AutoFocusUtils":77,"./CSSPropertyOperations":80,"./DOMLazyTree":84,"./DOMNamespaces":85,"./DOMProperty":86,"./DOMPropertyOperations":87,"./EventConstants":92,"./EventPluginHub":93,"./EventPluginRegistry":94,"./ReactBrowserEventEmitter":103,"./ReactComponentBrowserEnvironment":108,"./ReactDOMButton":114,"./ReactDOMComponentFlags":116,"./ReactDOMComponentTree":117,"./ReactDOMInput":124,"./ReactDOMOption":126,"./ReactDOMSelect":127,"./ReactDOMTextarea":130,"./ReactInstrumentation":146,"./ReactMultiChild":150,"./ReactServerRenderingTransaction":163,"./escapeTextContentForBrowser":190,"./isEventSupported":204,"./validateDOMNesting":213,"_process":33,"fbjs/lib/emptyFunction":221,"fbjs/lib/invariant":229,"fbjs/lib/keyOf":233,"fbjs/lib/shallowEqual":238,"fbjs/lib/warning":239,"object-assign":32}],116:[function(require,module,exports){ /** * Copyright 2015-present, Facebook, Inc. * All rights reserved. @@ -14473,7 +14851,7 @@ var ReactDOMComponentFlags = { }; module.exports = ReactDOMComponentFlags; -},{}],116:[function(require,module,exports){ +},{}],117:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -14663,7 +15041,7 @@ var ReactDOMComponentTree = { module.exports = ReactDOMComponentTree; }).call(this,require('_process')) -},{"./DOMProperty":86,"./ReactDOMComponentFlags":115,"_process":33,"fbjs/lib/invariant":229}],117:[function(require,module,exports){ +},{"./DOMProperty":86,"./ReactDOMComponentFlags":116,"_process":33,"fbjs/lib/invariant":229}],118:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -14700,7 +15078,7 @@ function ReactDOMContainerInfo(topLevelWrapper, node) { module.exports = ReactDOMContainerInfo; }).call(this,require('_process')) -},{"./validateDOMNesting":213,"_process":33}],118:[function(require,module,exports){ +},{"./validateDOMNesting":213,"_process":33}],119:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -14765,7 +15143,7 @@ ReactDOMDebugTool.addDevtool(ReactDOMUnknownPropertyDevtool); module.exports = ReactDOMDebugTool; }).call(this,require('_process')) -},{"./ReactDOMUnknownPropertyDevtool":131,"_process":33,"fbjs/lib/warning":239}],119:[function(require,module,exports){ +},{"./ReactDOMUnknownPropertyDevtool":132,"_process":33,"fbjs/lib/warning":239}],120:[function(require,module,exports){ /** * Copyright 2014-present, Facebook, Inc. * All rights reserved. @@ -14826,7 +15204,7 @@ _assign(ReactDOMEmptyComponent.prototype, { }); module.exports = ReactDOMEmptyComponent; -},{"./DOMLazyTree":84,"./ReactDOMComponentTree":116,"object-assign":32}],120:[function(require,module,exports){ +},{"./DOMLazyTree":84,"./ReactDOMComponentTree":117,"object-assign":32}],121:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -15006,7 +15384,7 @@ var ReactDOMFactories = mapObject({ module.exports = ReactDOMFactories; }).call(this,require('_process')) -},{"./ReactElement":137,"./ReactElementValidator":138,"_process":33,"fbjs/lib/mapObject":234}],121:[function(require,module,exports){ +},{"./ReactElement":136,"./ReactElementValidator":137,"_process":33,"fbjs/lib/mapObject":234}],122:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -15025,7 +15403,7 @@ var ReactDOMFeatureFlags = { }; module.exports = ReactDOMFeatureFlags; -},{}],122:[function(require,module,exports){ +},{}],123:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -15041,7 +15419,6 @@ module.exports = ReactDOMFeatureFlags; var DOMChildrenOperations = require('./DOMChildrenOperations'); var ReactDOMComponentTree = require('./ReactDOMComponentTree'); -var ReactPerf = require('./ReactPerf'); /** * Operations used to process updates to DOM nodes. @@ -15060,12 +15437,8 @@ var ReactDOMIDOperations = { } }; -ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', { - dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates' -}); - module.exports = ReactDOMIDOperations; -},{"./DOMChildrenOperations":83,"./ReactDOMComponentTree":116,"./ReactPerf":157}],123:[function(require,module,exports){ +},{"./DOMChildrenOperations":83,"./ReactDOMComponentTree":117}],124:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -15154,6 +15527,8 @@ var ReactDOMInput = { if (process.env.NODE_ENV !== 'production') { LinkedValueUtils.checkPropTypes('input', props, inst._currentElement._owner); + var owner = inst._currentElement._owner; + if (props.valueLink !== undefined && !didWarnValueLink) { process.env.NODE_ENV !== 'production' ? warning(false, '`valueLink` prop on `input` is deprecated; set `value` and `onChange` instead.') : void 0; didWarnValueLink = true; @@ -15163,11 +15538,11 @@ var ReactDOMInput = { didWarnCheckedLink = true; } if (props.checked !== undefined && props.defaultChecked !== undefined && !didWarnCheckedDefaultChecked) { - process.env.NODE_ENV !== 'production' ? warning(false, 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components') : void 0; + process.env.NODE_ENV !== 'production' ? warning(false, '%s contains an input of type %s with both checked and defaultChecked props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the checked prop, or the defaultChecked prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : void 0; didWarnCheckedDefaultChecked = true; } if (props.value !== undefined && props.defaultValue !== undefined && !didWarnValueDefaultValue) { - process.env.NODE_ENV !== 'production' ? warning(false, 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components') : void 0; + process.env.NODE_ENV !== 'production' ? warning(false, '%s contains an input of type %s with both value and defaultValue props. ' + 'Input elements must be either controlled or uncontrolled ' + '(specify either the value prop, or the defaultValue prop, but not ' + 'both). Decide between using a controlled or uncontrolled input ' + 'element and remove one of these props. More info: ' + 'https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : void 0; didWarnValueDefaultValue = true; } warnIfValueIsNull(props); @@ -15198,7 +15573,7 @@ var ReactDOMInput = { var owner = inst._currentElement._owner; if ((initialValue || !inst._wrapperState.controlled) && controlled && !didWarnUncontrolledToControlled) { - process.env.NODE_ENV !== 'production' ? warning(false, '%s is changing a uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : void 0; + process.env.NODE_ENV !== 'production' ? warning(false, '%s is changing an uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or vice versa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type) : void 0; didWarnUncontrolledToControlled = true; } if (inst._wrapperState.controlled && (defaultValue || !controlled) && !didWarnControlledToUncontrolled) { @@ -15273,7 +15648,7 @@ function _handleChange(event) { module.exports = ReactDOMInput; }).call(this,require('_process')) -},{"./DOMPropertyOperations":87,"./DisabledInputUtils":90,"./LinkedValueUtils":100,"./ReactDOMComponentTree":116,"./ReactUpdates":165,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239,"object-assign":32}],124:[function(require,module,exports){ +},{"./DOMPropertyOperations":87,"./DisabledInputUtils":90,"./LinkedValueUtils":100,"./ReactDOMComponentTree":117,"./ReactUpdates":165,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239,"object-assign":32}],125:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -15290,7 +15665,7 @@ module.exports = ReactDOMInput; var ReactDOMDebugTool = require('./ReactDOMDebugTool'); module.exports = { debugTool: ReactDOMDebugTool }; -},{"./ReactDOMDebugTool":118}],125:[function(require,module,exports){ +},{"./ReactDOMDebugTool":119}],126:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -15403,7 +15778,7 @@ var ReactDOMOption = { module.exports = ReactDOMOption; }).call(this,require('_process')) -},{"./ReactChildren":105,"./ReactDOMComponentTree":116,"./ReactDOMSelect":126,"_process":33,"fbjs/lib/warning":239,"object-assign":32}],126:[function(require,module,exports){ +},{"./ReactChildren":105,"./ReactDOMComponentTree":117,"./ReactDOMSelect":127,"_process":33,"fbjs/lib/warning":239,"object-assign":32}],127:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -15620,7 +15995,7 @@ function _handleChange(event) { module.exports = ReactDOMSelect; }).call(this,require('_process')) -},{"./DisabledInputUtils":90,"./LinkedValueUtils":100,"./ReactDOMComponentTree":116,"./ReactUpdates":165,"_process":33,"fbjs/lib/warning":239,"object-assign":32}],127:[function(require,module,exports){ +},{"./DisabledInputUtils":90,"./LinkedValueUtils":100,"./ReactDOMComponentTree":117,"./ReactUpdates":165,"_process":33,"fbjs/lib/warning":239,"object-assign":32}],128:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -15833,7 +16208,7 @@ var ReactDOMSelection = { }; module.exports = ReactDOMSelection; -},{"./getNodeForCharacterOffset":200,"./getTextContentAccessor":201,"fbjs/lib/ExecutionEnvironment":215}],128:[function(require,module,exports){ +},{"./getNodeForCharacterOffset":200,"./getTextContentAccessor":201,"fbjs/lib/ExecutionEnvironment":215}],129:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -15853,7 +16228,7 @@ var _assign = require('object-assign'); var DOMChildrenOperations = require('./DOMChildrenOperations'); var DOMLazyTree = require('./DOMLazyTree'); var ReactDOMComponentTree = require('./ReactDOMComponentTree'); -var ReactPerf = require('./ReactPerf'); +var ReactInstrumentation = require('./ReactInstrumentation'); var escapeTextContentForBrowser = require('./escapeTextContentForBrowser'); var invariant = require('fbjs/lib/invariant'); @@ -15901,6 +16276,8 @@ _assign(ReactDOMTextComponent.prototype, { */ mountComponent: function (transaction, nativeParent, nativeContainerInfo, context) { if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onSetText(this._debugID, this._stringText); + var parentInfo; if (nativeParent != null) { parentInfo = nativeParent._ancestorInfo; @@ -15964,6 +16341,10 @@ _assign(ReactDOMTextComponent.prototype, { this._stringText = nextStringText; var commentNodes = this.getNativeNode(); DOMChildrenOperations.replaceDelimitedText(commentNodes[0], commentNodes[1], nextStringText); + + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onSetText(this._debugID, nextStringText); + } } } }, @@ -15998,15 +16379,10 @@ _assign(ReactDOMTextComponent.prototype, { }); -ReactPerf.measureMethods(ReactDOMTextComponent.prototype, 'ReactDOMTextComponent', { - mountComponent: 'mountComponent', - receiveComponent: 'receiveComponent' -}); - module.exports = ReactDOMTextComponent; }).call(this,require('_process')) -},{"./DOMChildrenOperations":83,"./DOMLazyTree":84,"./ReactDOMComponentTree":116,"./ReactPerf":157,"./escapeTextContentForBrowser":190,"./validateDOMNesting":213,"_process":33,"fbjs/lib/invariant":229,"object-assign":32}],129:[function(require,module,exports){ +},{"./DOMChildrenOperations":83,"./DOMLazyTree":84,"./ReactDOMComponentTree":117,"./ReactInstrumentation":146,"./escapeTextContentForBrowser":190,"./validateDOMNesting":213,"_process":33,"fbjs/lib/invariant":229,"object-assign":32}],130:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -16152,7 +16528,7 @@ function _handleChange(event) { module.exports = ReactDOMTextarea; }).call(this,require('_process')) -},{"./DOMPropertyOperations":87,"./DisabledInputUtils":90,"./LinkedValueUtils":100,"./ReactDOMComponentTree":116,"./ReactUpdates":165,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239,"object-assign":32}],130:[function(require,module,exports){ +},{"./DOMPropertyOperations":87,"./DisabledInputUtils":90,"./LinkedValueUtils":100,"./ReactDOMComponentTree":117,"./ReactUpdates":165,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239,"object-assign":32}],131:[function(require,module,exports){ (function (process){ /** * Copyright 2015-present, Facebook, Inc. @@ -16290,7 +16666,7 @@ module.exports = { }; }).call(this,require('_process')) -},{"_process":33,"fbjs/lib/invariant":229}],131:[function(require,module,exports){ +},{"_process":33,"fbjs/lib/invariant":229}],132:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -16358,7 +16734,7 @@ var ReactDOMUnknownPropertyDevtool = { module.exports = ReactDOMUnknownPropertyDevtool; }).call(this,require('_process')) -},{"./DOMProperty":86,"./EventPluginRegistry":94,"_process":33,"fbjs/lib/warning":239}],132:[function(require,module,exports){ +},{"./DOMProperty":86,"./EventPluginRegistry":94,"_process":33,"fbjs/lib/warning":239}],133:[function(require,module,exports){ (function (process){ /** * Copyright 2016-present, Facebook, Inc. @@ -16373,7 +16749,9 @@ module.exports = ReactDOMUnknownPropertyDevtool; 'use strict'; -var ReactInvalidSetStateWarningDevTool = require('./ReactInvalidSetStateWarningDevTool'); +var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); + +var performanceNow = require('fbjs/lib/performanceNow'); var warning = require('fbjs/lib/warning'); var eventHandlers = []; @@ -16394,6 +16772,70 @@ function emitEvent(handlerFunctionName, arg1, arg2, arg3, arg4, arg5) { } } +var isProfiling = false; +var flushHistory = []; +var currentFlushNesting = 0; +var currentFlushMeasurements = null; +var currentFlushStartTime = null; +var currentTimerDebugID = null; +var currentTimerStartTime = null; +var currentTimerType = null; + +function clearHistory() { + ReactComponentTreeDevtool.purgeUnmountedComponents(); + ReactNativeOperationHistoryDevtool.clearHistory(); +} + +function getTreeSnapshot(registeredIDs) { + return registeredIDs.reduce(function (tree, id) { + var ownerID = ReactComponentTreeDevtool.getOwnerID(id); + var parentID = ReactComponentTreeDevtool.getParentID(id); + tree[id] = { + displayName: ReactComponentTreeDevtool.getDisplayName(id), + text: ReactComponentTreeDevtool.getText(id), + updateCount: ReactComponentTreeDevtool.getUpdateCount(id), + childIDs: ReactComponentTreeDevtool.getChildIDs(id), + // Text nodes don't have owners but this is close enough. + ownerID: ownerID || ReactComponentTreeDevtool.getOwnerID(parentID), + parentID: parentID + }; + return tree; + }, {}); +} + +function resetMeasurements() { + if (process.env.NODE_ENV !== 'production') { + var previousStartTime = currentFlushStartTime; + var previousMeasurements = currentFlushMeasurements || []; + var previousOperations = ReactNativeOperationHistoryDevtool.getHistory(); + + if (!isProfiling || currentFlushNesting === 0) { + currentFlushStartTime = null; + currentFlushMeasurements = null; + clearHistory(); + return; + } + + if (previousMeasurements.length || previousOperations.length) { + var registeredIDs = ReactComponentTreeDevtool.getRegisteredIDs(); + flushHistory.push({ + duration: performanceNow() - previousStartTime, + measurements: previousMeasurements || [], + operations: previousOperations || [], + treeSnapshot: getTreeSnapshot(registeredIDs) + }); + } + + clearHistory(); + currentFlushStartTime = performanceNow(); + currentFlushMeasurements = []; + } +} + +function checkDebugID(debugID) { + process.env.NODE_ENV !== 'production' ? warning(debugID, 'ReactDebugTool: debugID may not be empty.') : void 0; +} + var ReactDebugTool = { addDevtool: function (devtool) { eventHandlers.push(devtool); @@ -16406,35 +16848,147 @@ var ReactDebugTool = { } } }, + beginProfiling: function () { + if (process.env.NODE_ENV !== 'production') { + if (isProfiling) { + return; + } + + isProfiling = true; + flushHistory.length = 0; + resetMeasurements(); + } + }, + endProfiling: function () { + if (process.env.NODE_ENV !== 'production') { + if (!isProfiling) { + return; + } + + isProfiling = false; + resetMeasurements(); + } + }, + getFlushHistory: function () { + if (process.env.NODE_ENV !== 'production') { + return flushHistory; + } + }, + onBeginFlush: function () { + if (process.env.NODE_ENV !== 'production') { + currentFlushNesting++; + resetMeasurements(); + } + emitEvent('onBeginFlush'); + }, + onEndFlush: function () { + if (process.env.NODE_ENV !== 'production') { + resetMeasurements(); + currentFlushNesting--; + } + emitEvent('onEndFlush'); + }, + onBeginLifeCycleTimer: function (debugID, timerType) { + checkDebugID(debugID); + emitEvent('onBeginLifeCycleTimer', debugID, timerType); + if (process.env.NODE_ENV !== 'production') { + if (isProfiling && currentFlushNesting > 0) { + process.env.NODE_ENV !== 'production' ? warning(!currentTimerType, 'There is an internal error in the React performance measurement code. ' + 'Did not expect %s timer to start while %s timer is still in ' + 'progress for %s instance.', timerType, currentTimerType || 'no', debugID === currentTimerDebugID ? 'the same' : 'another') : void 0; + currentTimerStartTime = performanceNow(); + currentTimerDebugID = debugID; + currentTimerType = timerType; + } + } + }, + onEndLifeCycleTimer: function (debugID, timerType) { + checkDebugID(debugID); + if (process.env.NODE_ENV !== 'production') { + if (isProfiling && currentFlushNesting > 0) { + process.env.NODE_ENV !== 'production' ? warning(currentTimerType === timerType, 'There is an internal error in the React performance measurement code. ' + 'We did not expect %s timer to stop while %s timer is still in ' + 'progress for %s instance. Please report this as a bug in React.', timerType, currentTimerType || 'no', debugID === currentTimerDebugID ? 'the same' : 'another') : void 0; + currentFlushMeasurements.push({ + timerType: timerType, + instanceID: debugID, + duration: performanceNow() - currentTimerStartTime + }); + currentTimerStartTime = null; + currentTimerDebugID = null; + currentTimerType = null; + } + } + emitEvent('onEndLifeCycleTimer', debugID, timerType); + }, + onBeginReconcilerTimer: function (debugID, timerType) { + checkDebugID(debugID); + emitEvent('onBeginReconcilerTimer', debugID, timerType); + }, + onEndReconcilerTimer: function (debugID, timerType) { + checkDebugID(debugID); + emitEvent('onEndReconcilerTimer', debugID, timerType); + }, onBeginProcessingChildContext: function () { emitEvent('onBeginProcessingChildContext'); }, onEndProcessingChildContext: function () { emitEvent('onEndProcessingChildContext'); }, + onNativeOperation: function (debugID, type, payload) { + checkDebugID(debugID); + emitEvent('onNativeOperation', debugID, type, payload); + }, onSetState: function () { emitEvent('onSetState'); }, - onMountRootComponent: function (internalInstance) { - emitEvent('onMountRootComponent', internalInstance); + onSetDisplayName: function (debugID, displayName) { + checkDebugID(debugID); + emitEvent('onSetDisplayName', debugID, displayName); }, - onMountComponent: function (internalInstance) { - emitEvent('onMountComponent', internalInstance); + onSetChildren: function (debugID, childDebugIDs) { + checkDebugID(debugID); + emitEvent('onSetChildren', debugID, childDebugIDs); }, - onUpdateComponent: function (internalInstance) { - emitEvent('onUpdateComponent', internalInstance); + onSetOwner: function (debugID, ownerDebugID) { + checkDebugID(debugID); + emitEvent('onSetOwner', debugID, ownerDebugID); }, - onUnmountComponent: function (internalInstance) { - emitEvent('onUnmountComponent', internalInstance); + onSetText: function (debugID, text) { + checkDebugID(debugID); + emitEvent('onSetText', debugID, text); + }, + onMountRootComponent: function (debugID) { + checkDebugID(debugID); + emitEvent('onMountRootComponent', debugID); + }, + onMountComponent: function (debugID) { + checkDebugID(debugID); + emitEvent('onMountComponent', debugID); + }, + onUpdateComponent: function (debugID) { + checkDebugID(debugID); + emitEvent('onUpdateComponent', debugID); + }, + onUnmountComponent: function (debugID) { + checkDebugID(debugID); + emitEvent('onUnmountComponent', debugID); } }; -ReactDebugTool.addDevtool(ReactInvalidSetStateWarningDevTool); +if (process.env.NODE_ENV !== 'production') { + var ReactInvalidSetStateWarningDevTool = require('./ReactInvalidSetStateWarningDevTool'); + var ReactNativeOperationHistoryDevtool = require('./ReactNativeOperationHistoryDevtool'); + var ReactComponentTreeDevtool = require('./ReactComponentTreeDevtool'); + ReactDebugTool.addDevtool(ReactInvalidSetStateWarningDevTool); + ReactDebugTool.addDevtool(ReactComponentTreeDevtool); + ReactDebugTool.addDevtool(ReactNativeOperationHistoryDevtool); + var url = ExecutionEnvironment.canUseDOM && window.location.href || ''; + if (/[?&]react_perf\b/.test(url)) { + ReactDebugTool.beginProfiling(); + } +} module.exports = ReactDebugTool; }).call(this,require('_process')) -},{"./ReactInvalidSetStateWarningDevTool":148,"_process":33,"fbjs/lib/warning":239}],133:[function(require,module,exports){ +},{"./ReactComponentTreeDevtool":110,"./ReactInvalidSetStateWarningDevTool":147,"./ReactNativeOperationHistoryDevtool":153,"_process":33,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/performanceNow":237,"fbjs/lib/warning":239}],134:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -16503,8 +17057,7 @@ var ReactDefaultBatchingStrategy = { }; module.exports = ReactDefaultBatchingStrategy; -},{"./ReactUpdates":165,"./Transaction":183,"fbjs/lib/emptyFunction":221,"object-assign":32}],134:[function(require,module,exports){ -(function (process){ +},{"./ReactUpdates":165,"./Transaction":183,"fbjs/lib/emptyFunction":221,"object-assign":32}],135:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -16522,7 +17075,6 @@ var BeforeInputEventPlugin = require('./BeforeInputEventPlugin'); var ChangeEventPlugin = require('./ChangeEventPlugin'); var DefaultEventPluginOrder = require('./DefaultEventPluginOrder'); var EnterLeaveEventPlugin = require('./EnterLeaveEventPlugin'); -var ExecutionEnvironment = require('fbjs/lib/ExecutionEnvironment'); var HTMLDOMPropertyConfig = require('./HTMLDOMPropertyConfig'); var ReactComponentBrowserEnvironment = require('./ReactComponentBrowserEnvironment'); var ReactDOMComponent = require('./ReactDOMComponent'); @@ -16585,553 +17137,12 @@ function inject() { ReactInjection.Updates.injectBatchingStrategy(ReactDefaultBatchingStrategy); ReactInjection.Component.injectEnvironment(ReactComponentBrowserEnvironment); - - if (process.env.NODE_ENV !== 'production') { - var url = ExecutionEnvironment.canUseDOM && window.location.href || ''; - if (/[?&]react_perf\b/.test(url)) { - var ReactDefaultPerf = require('./ReactDefaultPerf'); - ReactDefaultPerf.start(); - } - } } module.exports = { inject: inject }; -}).call(this,require('_process')) - -},{"./BeforeInputEventPlugin":78,"./ChangeEventPlugin":82,"./DefaultEventPluginOrder":89,"./EnterLeaveEventPlugin":91,"./HTMLDOMPropertyConfig":98,"./ReactComponentBrowserEnvironment":108,"./ReactDOMComponent":114,"./ReactDOMComponentTree":116,"./ReactDOMEmptyComponent":119,"./ReactDOMTextComponent":128,"./ReactDOMTreeTraversal":130,"./ReactDefaultBatchingStrategy":133,"./ReactDefaultPerf":135,"./ReactEventListener":142,"./ReactInjection":144,"./ReactReconcileTransaction":161,"./SVGDOMPropertyConfig":167,"./SelectEventPlugin":168,"./SimpleEventPlugin":169,"_process":33,"fbjs/lib/ExecutionEnvironment":215}],135:[function(require,module,exports){ -(function (process){ -/** - * Copyright 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. - * - * @providesModule ReactDefaultPerf - */ - -'use strict'; - -var DOMProperty = require('./DOMProperty'); -var ReactDOMComponentTree = require('./ReactDOMComponentTree'); -var ReactDefaultPerfAnalysis = require('./ReactDefaultPerfAnalysis'); -var ReactMount = require('./ReactMount'); -var ReactPerf = require('./ReactPerf'); - -var performanceNow = require('fbjs/lib/performanceNow'); -var warning = require('fbjs/lib/warning'); - -function roundFloat(val) { - return Math.floor(val * 100) / 100; -} - -function addValue(obj, key, val) { - obj[key] = (obj[key] || 0) + val; -} - -// Composite/text components don't have any built-in ID: we have to make our own -var compositeIDMap; -var compositeIDCounter = 17000; -function getIDOfComposite(inst) { - if (!compositeIDMap) { - compositeIDMap = new WeakMap(); - } - if (compositeIDMap.has(inst)) { - return compositeIDMap.get(inst); - } else { - var id = compositeIDCounter++; - compositeIDMap.set(inst, id); - return id; - } -} - -function getID(inst) { - if (inst.hasOwnProperty('_rootNodeID')) { - return inst._rootNodeID; - } else { - return getIDOfComposite(inst); - } -} - -function stripComplexValues(key, value) { - if (typeof value !== 'object' || Array.isArray(value) || value == null) { - return value; - } - var prototype = Object.getPrototypeOf(value); - if (!prototype || prototype === Object.prototype) { - return value; - } - return ''; -} - -// This implementation of ReactPerf is going away some time mid 15.x. -// While we plan to keep most of the API, the actual format of measurements -// will change dramatically. To signal this, we wrap them into an opaque-ish -// object to discourage reaching into it until the API stabilizes. -function wrapLegacyMeasurements(measurements) { - return { __unstable_this_format_will_change: measurements }; -} -function unwrapLegacyMeasurements(measurements) { - return measurements && measurements.__unstable_this_format_will_change || measurements; -} - -var warnedAboutPrintDOM = false; -var warnedAboutGetMeasurementsSummaryMap = false; - -var ReactDefaultPerf = { - _allMeasurements: [], // last item in the list is the current one - _mountStack: [0], - _compositeStack: [], - _injected: false, - - start: function () { - if (!ReactDefaultPerf._injected) { - ReactPerf.injection.injectMeasure(ReactDefaultPerf.measure); - } - - ReactDefaultPerf._allMeasurements.length = 0; - ReactPerf.enableMeasure = true; - }, - - stop: function () { - ReactPerf.enableMeasure = false; - }, - - getLastMeasurements: function () { - return wrapLegacyMeasurements(ReactDefaultPerf._allMeasurements); - }, - - printExclusive: function (measurements) { - measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements); - var summary = ReactDefaultPerfAnalysis.getExclusiveSummary(measurements); - console.table(summary.map(function (item) { - return { - 'Component class name': item.componentName, - 'Total inclusive time (ms)': roundFloat(item.inclusive), - 'Exclusive mount time (ms)': roundFloat(item.exclusive), - 'Exclusive render time (ms)': roundFloat(item.render), - 'Mount time per instance (ms)': roundFloat(item.exclusive / item.count), - 'Render time per instance (ms)': roundFloat(item.render / item.count), - 'Instances': item.count - }; - })); - // TODO: ReactDefaultPerfAnalysis.getTotalTime() does not return the correct - // number. - }, - - printInclusive: function (measurements) { - measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements); - var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements); - console.table(summary.map(function (item) { - return { - 'Owner > component': item.componentName, - 'Inclusive time (ms)': roundFloat(item.time), - 'Instances': item.count - }; - })); - console.log('Total time:', ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'); - }, - - getMeasurementsSummaryMap: function (measurements) { - process.env.NODE_ENV !== 'production' ? warning(warnedAboutGetMeasurementsSummaryMap, '`ReactPerf.getMeasurementsSummaryMap(...)` is deprecated. Use ' + '`ReactPerf.getWasted(...)` instead.') : void 0; - warnedAboutGetMeasurementsSummaryMap = true; - return ReactDefaultPerf.getWasted(measurements); - }, - - getWasted: function (measurements) { - measurements = unwrapLegacyMeasurements(measurements); - var summary = ReactDefaultPerfAnalysis.getInclusiveSummary(measurements, true); - return summary.map(function (item) { - return { - 'Owner > component': item.componentName, - 'Wasted time (ms)': item.time, - 'Instances': item.count - }; - }); - }, - - printWasted: function (measurements) { - measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements); - console.table(ReactDefaultPerf.getWasted(measurements)); - console.log('Total time:', ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'); - }, - - printDOM: function (measurements) { - process.env.NODE_ENV !== 'production' ? warning(warnedAboutPrintDOM, '`ReactPerf.printDOM(...)` is deprecated. Use ' + '`ReactPerf.printOperations(...)` instead.') : void 0; - warnedAboutPrintDOM = true; - return ReactDefaultPerf.printOperations(measurements); - }, - - printOperations: function (measurements) { - measurements = unwrapLegacyMeasurements(measurements || ReactDefaultPerf._allMeasurements); - var summary = ReactDefaultPerfAnalysis.getDOMSummary(measurements); - console.table(summary.map(function (item) { - var result = {}; - result[DOMProperty.ID_ATTRIBUTE_NAME] = item.id; - result.type = item.type; - result.args = JSON.stringify(item.args, stripComplexValues); - return result; - })); - console.log('Total time:', ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms'); - }, - - _recordWrite: function (id, fnName, totalTime, args) { - // TODO: totalTime isn't that useful since it doesn't count paints/reflows - var entry = ReactDefaultPerf._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]; - var writes = entry.writes; - writes[id] = writes[id] || []; - writes[id].push({ - type: fnName, - time: totalTime, - args: args - }); - }, - - measure: function (moduleName, fnName, func) { - return function () { - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - var totalTime; - var rv; - var start; - - var entry = ReactDefaultPerf._allMeasurements[ReactDefaultPerf._allMeasurements.length - 1]; - - if (fnName === '_renderNewRootComponent' || fnName === 'flushBatchedUpdates') { - // A "measurement" is a set of metrics recorded for each flush. We want - // to group the metrics for a given flush together so we can look at the - // components that rendered and the DOM operations that actually - // happened to determine the amount of "wasted work" performed. - ReactDefaultPerf._allMeasurements.push(entry = { - exclusive: {}, - inclusive: {}, - render: {}, - counts: {}, - writes: {}, - displayNames: {}, - hierarchy: {}, - totalTime: 0, - created: {} - }); - start = performanceNow(); - rv = func.apply(this, args); - entry.totalTime = performanceNow() - start; - return rv; - } else if (fnName === '_mountImageIntoNode' || moduleName === 'ReactDOMIDOperations' || moduleName === 'CSSPropertyOperations' || moduleName === 'DOMChildrenOperations' || moduleName === 'DOMPropertyOperations' || moduleName === 'ReactComponentBrowserEnvironment') { - start = performanceNow(); - rv = func.apply(this, args); - totalTime = performanceNow() - start; - - if (fnName === '_mountImageIntoNode') { - ReactDefaultPerf._recordWrite('', fnName, totalTime, args[0]); - } else if (fnName === 'dangerouslyProcessChildrenUpdates') { - // special format - args[1].forEach(function (update) { - var writeArgs = {}; - if (update.fromIndex !== null) { - writeArgs.fromIndex = update.fromIndex; - } - if (update.toIndex !== null) { - writeArgs.toIndex = update.toIndex; - } - if (update.content !== null) { - writeArgs.content = update.content; - } - ReactDefaultPerf._recordWrite(args[0]._rootNodeID, update.type, totalTime, writeArgs); - }); - } else { - // basic format - var id = args[0]; - if (moduleName === 'EventPluginHub') { - id = id._rootNodeID; - } else if (fnName === 'replaceNodeWithMarkup') { - // Old node is already unmounted; can't get its instance - id = ReactDOMComponentTree.getInstanceFromNode(args[1].node)._rootNodeID; - } else if (fnName === 'replaceDelimitedText') { - id = getID(ReactDOMComponentTree.getInstanceFromNode(args[0])); - } else if (typeof id === 'object') { - id = getID(ReactDOMComponentTree.getInstanceFromNode(args[0])); - } - ReactDefaultPerf._recordWrite(id, fnName, totalTime, Array.prototype.slice.call(args, 1)); - } - return rv; - } else if (moduleName === 'ReactCompositeComponent' && (fnName === 'mountComponent' || fnName === 'updateComponent' || // TODO: receiveComponent()? - fnName === '_renderValidatedComponent')) { - - if (this._currentElement.type === ReactMount.TopLevelWrapper) { - return func.apply(this, args); - } - - var rootNodeID = getIDOfComposite(this); - var isRender = fnName === '_renderValidatedComponent'; - var isMount = fnName === 'mountComponent'; - - var mountStack = ReactDefaultPerf._mountStack; - - if (isRender) { - addValue(entry.counts, rootNodeID, 1); - } else if (isMount) { - entry.created[rootNodeID] = true; - mountStack.push(0); - } - - ReactDefaultPerf._compositeStack.push(rootNodeID); - - start = performanceNow(); - rv = func.apply(this, args); - totalTime = performanceNow() - start; - - ReactDefaultPerf._compositeStack.pop(); - - if (isRender) { - addValue(entry.render, rootNodeID, totalTime); - } else if (isMount) { - var subMountTime = mountStack.pop(); - mountStack[mountStack.length - 1] += totalTime; - addValue(entry.exclusive, rootNodeID, totalTime - subMountTime); - addValue(entry.inclusive, rootNodeID, totalTime); - } else { - addValue(entry.inclusive, rootNodeID, totalTime); - } - - entry.displayNames[rootNodeID] = { - current: this.getName(), - owner: this._currentElement._owner ? this._currentElement._owner.getName() : '' - }; - - return rv; - } else if ((moduleName === 'ReactDOMComponent' || moduleName === 'ReactDOMTextComponent') && (fnName === 'mountComponent' || fnName === 'receiveComponent')) { - - rv = func.apply(this, args); - entry.hierarchy[getID(this)] = ReactDefaultPerf._compositeStack.slice(); - return rv; - } else { - return func.apply(this, args); - } - }; - } -}; - -module.exports = ReactDefaultPerf; -}).call(this,require('_process')) - -},{"./DOMProperty":86,"./ReactDOMComponentTree":116,"./ReactDefaultPerfAnalysis":136,"./ReactMount":150,"./ReactPerf":157,"_process":33,"fbjs/lib/performanceNow":237,"fbjs/lib/warning":239}],136:[function(require,module,exports){ -/** - * Copyright 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. - * - * @providesModule ReactDefaultPerfAnalysis - */ - -'use strict'; - -// Don't try to save users less than 1.2ms (a number I made up) - -var _assign = require('object-assign'); - -var DONT_CARE_THRESHOLD = 1.2; -var DOM_OPERATION_TYPES = { - '_mountImageIntoNode': 'set innerHTML', - INSERT_MARKUP: 'set innerHTML', - MOVE_EXISTING: 'move', - REMOVE_NODE: 'remove', - SET_MARKUP: 'set innerHTML', - TEXT_CONTENT: 'set textContent', - 'setValueForProperty': 'update attribute', - 'setValueForAttribute': 'update attribute', - 'deleteValueForProperty': 'remove attribute', - 'setValueForStyles': 'update styles', - 'replaceNodeWithMarkup': 'replace', - 'replaceDelimitedText': 'replace' -}; - -function getTotalTime(measurements) { - // TODO: return number of DOM ops? could be misleading. - // TODO: measure dropped frames after reconcile? - // TODO: log total time of each reconcile and the top-level component - // class that triggered it. - var totalTime = 0; - for (var i = 0; i < measurements.length; i++) { - var measurement = measurements[i]; - totalTime += measurement.totalTime; - } - return totalTime; -} - -function getDOMSummary(measurements) { - var items = []; - measurements.forEach(function (measurement) { - Object.keys(measurement.writes).forEach(function (id) { - measurement.writes[id].forEach(function (write) { - items.push({ - id: id, - type: DOM_OPERATION_TYPES[write.type] || write.type, - args: write.args - }); - }); - }); - }); - return items; -} - -function getExclusiveSummary(measurements) { - var candidates = {}; - var displayName; - - for (var i = 0; i < measurements.length; i++) { - var measurement = measurements[i]; - var allIDs = _assign({}, measurement.exclusive, measurement.inclusive); - - for (var id in allIDs) { - displayName = measurement.displayNames[id].current; - - candidates[displayName] = candidates[displayName] || { - componentName: displayName, - inclusive: 0, - exclusive: 0, - render: 0, - count: 0 - }; - if (measurement.render[id]) { - candidates[displayName].render += measurement.render[id]; - } - if (measurement.exclusive[id]) { - candidates[displayName].exclusive += measurement.exclusive[id]; - } - if (measurement.inclusive[id]) { - candidates[displayName].inclusive += measurement.inclusive[id]; - } - if (measurement.counts[id]) { - candidates[displayName].count += measurement.counts[id]; - } - } - } - - // Now make a sorted array with the results. - var arr = []; - for (displayName in candidates) { - if (candidates[displayName].exclusive >= DONT_CARE_THRESHOLD) { - arr.push(candidates[displayName]); - } - } - - arr.sort(function (a, b) { - return b.exclusive - a.exclusive; - }); - - return arr; -} - -function getInclusiveSummary(measurements, onlyClean) { - var candidates = {}; - var inclusiveKey; - - for (var i = 0; i < measurements.length; i++) { - var measurement = measurements[i]; - var allIDs = _assign({}, measurement.exclusive, measurement.inclusive); - var cleanComponents; - - if (onlyClean) { - cleanComponents = getUnchangedComponents(measurement); - } - - for (var id in allIDs) { - if (onlyClean && !cleanComponents[id]) { - continue; - } - - var displayName = measurement.displayNames[id]; - - // Inclusive time is not useful for many components without knowing where - // they are instantiated. So we aggregate inclusive time with both the - // owner and current displayName as the key. - inclusiveKey = displayName.owner + ' > ' + displayName.current; - - candidates[inclusiveKey] = candidates[inclusiveKey] || { - componentName: inclusiveKey, - time: 0, - count: 0 - }; - - if (measurement.inclusive[id]) { - candidates[inclusiveKey].time += measurement.inclusive[id]; - } - if (measurement.counts[id]) { - candidates[inclusiveKey].count += measurement.counts[id]; - } - } - } - - // Now make a sorted array with the results. - var arr = []; - for (inclusiveKey in candidates) { - if (candidates[inclusiveKey].time >= DONT_CARE_THRESHOLD) { - arr.push(candidates[inclusiveKey]); - } - } - - arr.sort(function (a, b) { - return b.time - a.time; - }); - - return arr; -} - -function getUnchangedComponents(measurement) { - // For a given reconcile, look at which components did not actually - // render anything to the DOM and return a mapping of their ID to - // the amount of time it took to render the entire subtree. - var cleanComponents = {}; - var writes = measurement.writes; - var hierarchy = measurement.hierarchy; - var dirtyComposites = {}; - Object.keys(writes).forEach(function (id) { - writes[id].forEach(function (write) { - // Root mounting (innerHTML set) is recorded with an ID of '' - if (id !== '' && hierarchy.hasOwnProperty(id)) { - hierarchy[id].forEach(function (c) { - return dirtyComposites[c] = true; - }); - } - }); - }); - var allIDs = _assign({}, measurement.exclusive, measurement.inclusive); - - for (var id in allIDs) { - var isDirty = false; - // See if any of the DOM operations applied to this component's subtree. - if (dirtyComposites[id]) { - isDirty = true; - } - // check if component newly created - if (measurement.created[id]) { - isDirty = true; - } - if (!isDirty && measurement.counts[id] > 0) { - cleanComponents[id] = true; - } - } - return cleanComponents; -} - -var ReactDefaultPerfAnalysis = { - getExclusiveSummary: getExclusiveSummary, - getInclusiveSummary: getInclusiveSummary, - getDOMSummary: getDOMSummary, - getTotalTime: getTotalTime -}; - -module.exports = ReactDefaultPerfAnalysis; -},{"object-assign":32}],137:[function(require,module,exports){ +},{"./BeforeInputEventPlugin":78,"./ChangeEventPlugin":82,"./DefaultEventPluginOrder":89,"./EnterLeaveEventPlugin":91,"./HTMLDOMPropertyConfig":98,"./ReactComponentBrowserEnvironment":108,"./ReactDOMComponent":115,"./ReactDOMComponentTree":117,"./ReactDOMEmptyComponent":120,"./ReactDOMTextComponent":129,"./ReactDOMTreeTraversal":131,"./ReactDefaultBatchingStrategy":134,"./ReactEventListener":141,"./ReactInjection":143,"./ReactReconcileTransaction":160,"./SVGDOMPropertyConfig":167,"./SelectEventPlugin":168,"./SimpleEventPlugin":169}],136:[function(require,module,exports){ (function (process){ /** * Copyright 2014-present, Facebook, Inc. @@ -17248,6 +17259,10 @@ var ReactElement = function (type, key, ref, self, source, owner, props) { return element; }; +/** + * Create and return a new ReactElement of the given type. + * See https://facebook.github.io/react/docs/top-level-api.html#react.createelement + */ ReactElement.createElement = function (type, config, children) { var propName; @@ -17261,6 +17276,11 @@ ReactElement.createElement = function (type, config, children) { if (config != null) { if (process.env.NODE_ENV !== 'production') { + process.env.NODE_ENV !== 'production' ? warning( + /* eslint-disable no-proto */ + config.__proto__ == null || config.__proto__ === Object.prototype, + /* eslint-enable no-proto */ + 'React.createElement(...): Expected props argument to be a plain object. ' + 'Properties defined in its prototype chain will be ignored.') : void 0; ref = !config.hasOwnProperty('ref') || Object.getOwnPropertyDescriptor(config, 'ref').get ? null : config.ref; key = !config.hasOwnProperty('key') || Object.getOwnPropertyDescriptor(config, 'key').get ? null : '' + config.key; } else { @@ -17332,6 +17352,10 @@ ReactElement.createElement = function (type, config, children) { return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props); }; +/** + * Return a function that produces ReactElements of a given type. + * See https://facebook.github.io/react/docs/top-level-api.html#react.createfactory + */ ReactElement.createFactory = function (type) { var factory = ReactElement.createElement.bind(null, type); // Expose the type on the factory and the prototype so that it can be @@ -17349,6 +17373,10 @@ ReactElement.cloneAndReplaceKey = function (oldElement, newKey) { return newElement; }; +/** + * Clone and return a new ReactElement using element as the starting point. + * See https://facebook.github.io/react/docs/top-level-api.html#react.cloneelement + */ ReactElement.cloneElement = function (element, config, children) { var propName; @@ -17369,6 +17397,13 @@ ReactElement.cloneElement = function (element, config, children) { var owner = element._owner; if (config != null) { + if (process.env.NODE_ENV !== 'production') { + process.env.NODE_ENV !== 'production' ? warning( + /* eslint-disable no-proto */ + config.__proto__ == null || config.__proto__ === Object.prototype, + /* eslint-enable no-proto */ + 'React.cloneElement(...): Expected props argument to be a plain object. ' + 'Properties defined in its prototype chain will be ignored.') : void 0; + } if (config.ref !== undefined) { // Silently steal the ref from the parent. ref = config.ref; @@ -17411,6 +17446,8 @@ ReactElement.cloneElement = function (element, config, children) { }; /** + * Verifies the object is a ReactElement. + * See https://facebook.github.io/react/docs/top-level-api.html#react.isvalidelement * @param {?object} object * @return {boolean} True if `object` is a valid component. * @final @@ -17422,7 +17459,7 @@ ReactElement.isValidElement = function (object) { module.exports = ReactElement; }).call(this,require('_process')) -},{"./ReactCurrentOwner":111,"./canDefineProperty":187,"_process":33,"fbjs/lib/warning":239,"object-assign":32}],138:[function(require,module,exports){ +},{"./ReactCurrentOwner":112,"./canDefineProperty":187,"_process":33,"fbjs/lib/warning":239,"object-assign":32}],137:[function(require,module,exports){ (function (process){ /** * Copyright 2014-present, Facebook, Inc. @@ -17707,7 +17744,7 @@ var ReactElementValidator = { module.exports = ReactElementValidator; }).call(this,require('_process')) -},{"./ReactCurrentOwner":111,"./ReactElement":137,"./ReactPropTypeLocationNames":158,"./ReactPropTypeLocations":159,"./canDefineProperty":187,"./getIteratorFn":198,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],139:[function(require,module,exports){ +},{"./ReactCurrentOwner":112,"./ReactElement":136,"./ReactPropTypeLocationNames":157,"./ReactPropTypeLocations":158,"./canDefineProperty":187,"./getIteratorFn":198,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],138:[function(require,module,exports){ /** * Copyright 2014-present, Facebook, Inc. * All rights reserved. @@ -17738,7 +17775,7 @@ var ReactEmptyComponent = { ReactEmptyComponent.injection = ReactEmptyComponentInjection; module.exports = ReactEmptyComponent; -},{}],140:[function(require,module,exports){ +},{}],139:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -17818,7 +17855,7 @@ if (process.env.NODE_ENV !== 'production') { module.exports = ReactErrorUtils; }).call(this,require('_process')) -},{"_process":33}],141:[function(require,module,exports){ +},{"_process":33}],140:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -17852,7 +17889,7 @@ var ReactEventEmitterMixin = { }; module.exports = ReactEventEmitterMixin; -},{"./EventPluginHub":93}],142:[function(require,module,exports){ +},{"./EventPluginHub":93}],141:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -18010,7 +18047,7 @@ var ReactEventListener = { }; module.exports = ReactEventListener; -},{"./PooledClass":101,"./ReactDOMComponentTree":116,"./ReactUpdates":165,"./getEventTarget":197,"fbjs/lib/EventListener":214,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/getUnboundedScrollPosition":226,"object-assign":32}],143:[function(require,module,exports){ +},{"./PooledClass":101,"./ReactDOMComponentTree":117,"./ReactUpdates":165,"./getEventTarget":197,"fbjs/lib/EventListener":214,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/getUnboundedScrollPosition":226,"object-assign":32}],142:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -18032,7 +18069,7 @@ var ReactFeatureFlags = { }; module.exports = ReactFeatureFlags; -},{}],144:[function(require,module,exports){ +},{}],143:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -18054,7 +18091,6 @@ var ReactClass = require('./ReactClass'); var ReactEmptyComponent = require('./ReactEmptyComponent'); var ReactBrowserEventEmitter = require('./ReactBrowserEventEmitter'); var ReactNativeComponent = require('./ReactNativeComponent'); -var ReactPerf = require('./ReactPerf'); var ReactUpdates = require('./ReactUpdates'); var ReactInjection = { @@ -18066,12 +18102,11 @@ var ReactInjection = { EventPluginUtils: EventPluginUtils.injection, EventEmitter: ReactBrowserEventEmitter.injection, NativeComponent: ReactNativeComponent.injection, - Perf: ReactPerf.injection, Updates: ReactUpdates.injection }; module.exports = ReactInjection; -},{"./DOMProperty":86,"./EventPluginHub":93,"./EventPluginUtils":95,"./ReactBrowserEventEmitter":103,"./ReactClass":106,"./ReactComponentEnvironment":109,"./ReactEmptyComponent":139,"./ReactNativeComponent":153,"./ReactPerf":157,"./ReactUpdates":165}],145:[function(require,module,exports){ +},{"./DOMProperty":86,"./EventPluginHub":93,"./EventPluginUtils":95,"./ReactBrowserEventEmitter":103,"./ReactClass":106,"./ReactComponentEnvironment":109,"./ReactEmptyComponent":138,"./ReactNativeComponent":152,"./ReactUpdates":165}],144:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -18196,7 +18231,7 @@ var ReactInputSelection = { }; module.exports = ReactInputSelection; -},{"./ReactDOMSelection":127,"fbjs/lib/containsNode":218,"fbjs/lib/focusNode":223,"fbjs/lib/getActiveElement":224}],146:[function(require,module,exports){ +},{"./ReactDOMSelection":128,"fbjs/lib/containsNode":218,"fbjs/lib/focusNode":223,"fbjs/lib/getActiveElement":224}],145:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -18245,7 +18280,7 @@ var ReactInstanceMap = { }; module.exports = ReactInstanceMap; -},{}],147:[function(require,module,exports){ +},{}],146:[function(require,module,exports){ /** * Copyright 2016-present, Facebook, Inc. * All rights reserved. @@ -18262,7 +18297,7 @@ module.exports = ReactInstanceMap; var ReactDebugTool = require('./ReactDebugTool'); module.exports = { debugTool: ReactDebugTool }; -},{"./ReactDebugTool":132}],148:[function(require,module,exports){ +},{"./ReactDebugTool":133}],147:[function(require,module,exports){ (function (process){ /** * Copyright 2016-present, Facebook, Inc. @@ -18302,7 +18337,7 @@ var ReactInvalidSetStateWarningDevTool = { module.exports = ReactInvalidSetStateWarningDevTool; }).call(this,require('_process')) -},{"_process":33,"fbjs/lib/warning":239}],149:[function(require,module,exports){ +},{"_process":33,"fbjs/lib/warning":239}],148:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -18353,7 +18388,7 @@ var ReactMarkupChecksum = { }; module.exports = ReactMarkupChecksum; -},{"./adler32":186}],150:[function(require,module,exports){ +},{"./adler32":186}],149:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -18379,7 +18414,6 @@ var ReactElement = require('./ReactElement'); var ReactFeatureFlags = require('./ReactFeatureFlags'); var ReactInstrumentation = require('./ReactInstrumentation'); var ReactMarkupChecksum = require('./ReactMarkupChecksum'); -var ReactPerf = require('./ReactPerf'); var ReactReconciler = require('./ReactReconciler'); var ReactUpdateQueue = require('./ReactUpdateQueue'); var ReactUpdates = require('./ReactUpdates'); @@ -18617,6 +18651,10 @@ var ReactMount = { * @return {ReactComponent} nextComponent */ _renderNewRootComponent: function (nextElement, container, shouldReuseMarkup, context) { + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onBeginFlush(); + } + // Various parts of our code (such as ReactCompositeComponent's // _renderValidatedComponent) assume that calls to render aren't nested; // verify that that's the case. @@ -18627,6 +18665,12 @@ var ReactMount = { ReactBrowserEventEmitter.ensureScrollValueMonitoring(); var componentInstance = instantiateReactComponent(nextElement); + if (process.env.NODE_ENV !== 'production') { + // Mute future events from the top level wrapper. + // It is an implementation detail that devtools should not know about. + componentInstance._debugID = 0; + } + // The initial render is synchronous but any updates that happen during // rendering, in componentWillMount or componentDidMount, will be batched // according to the current batching strategy. @@ -18637,7 +18681,9 @@ var ReactMount = { instancesByReactRootID[wrapperID] = componentInstance; if (process.env.NODE_ENV !== 'production') { - ReactInstrumentation.debugTool.onMountRootComponent(componentInstance); + // The instance here is TopLevelWrapper so we report mount for its child. + ReactInstrumentation.debugTool.onMountRootComponent(componentInstance._renderedComponent._debugID); + ReactInstrumentation.debugTool.onEndFlush(); } return componentInstance; @@ -18717,6 +18763,7 @@ var ReactMount = { /** * Renders a React component into the DOM in the supplied `container`. + * See https://facebook.github.io/react/docs/top-level-api.html#reactdom.render * * If the React component was previously rendered into `container`, this will * perform an update on it and only mutate the DOM as necessary to reflect the @@ -18733,6 +18780,7 @@ var ReactMount = { /** * Unmounts and destroys the React component rendered in the `container`. + * See https://facebook.github.io/react/docs/top-level-api.html#reactdom.unmountcomponentatnode * * @param {DOMElement} container DOM element containing a React component. * @return {boolean} True if a component was found in and unmounted from @@ -18824,18 +18872,20 @@ var ReactMount = { setInnerHTML(container, markup); ReactDOMComponentTree.precacheNode(instance, container.firstChild); } + + if (process.env.NODE_ENV !== 'production') { + var nativeNode = ReactDOMComponentTree.getInstanceFromNode(container.firstChild); + if (nativeNode._debugID !== 0) { + ReactInstrumentation.debugTool.onNativeOperation(nativeNode._debugID, 'mount', markup.toString()); + } + } } }; -ReactPerf.measureMethods(ReactMount, 'ReactMount', { - _renderNewRootComponent: '_renderNewRootComponent', - _mountImageIntoNode: '_mountImageIntoNode' -}); - module.exports = ReactMount; }).call(this,require('_process')) -},{"./DOMLazyTree":84,"./DOMProperty":86,"./ReactBrowserEventEmitter":103,"./ReactCurrentOwner":111,"./ReactDOMComponentTree":116,"./ReactDOMContainerInfo":117,"./ReactDOMFeatureFlags":121,"./ReactElement":137,"./ReactFeatureFlags":143,"./ReactInstrumentation":147,"./ReactMarkupChecksum":149,"./ReactPerf":157,"./ReactReconciler":162,"./ReactUpdateQueue":164,"./ReactUpdates":165,"./instantiateReactComponent":203,"./setInnerHTML":209,"./shouldUpdateReactComponent":211,"_process":33,"fbjs/lib/emptyObject":222,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],151:[function(require,module,exports){ +},{"./DOMLazyTree":84,"./DOMProperty":86,"./ReactBrowserEventEmitter":103,"./ReactCurrentOwner":112,"./ReactDOMComponentTree":117,"./ReactDOMContainerInfo":118,"./ReactDOMFeatureFlags":122,"./ReactElement":136,"./ReactFeatureFlags":142,"./ReactInstrumentation":146,"./ReactMarkupChecksum":148,"./ReactReconciler":161,"./ReactUpdateQueue":164,"./ReactUpdates":165,"./instantiateReactComponent":203,"./setInnerHTML":209,"./shouldUpdateReactComponent":211,"_process":33,"fbjs/lib/emptyObject":222,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],150:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -18851,12 +18901,14 @@ module.exports = ReactMount; 'use strict'; var ReactComponentEnvironment = require('./ReactComponentEnvironment'); +var ReactInstrumentation = require('./ReactInstrumentation'); var ReactMultiChildUpdateTypes = require('./ReactMultiChildUpdateTypes'); var ReactCurrentOwner = require('./ReactCurrentOwner'); var ReactReconciler = require('./ReactReconciler'); var ReactChildReconciler = require('./ReactChildReconciler'); +var emptyFunction = require('fbjs/lib/emptyFunction'); var flattenChildren = require('./flattenChildren'); var invariant = require('fbjs/lib/invariant'); @@ -18973,6 +19025,15 @@ function processQueue(inst, updateQueue) { ReactComponentEnvironment.processChildrenUpdates(inst, updateQueue); } +var setChildrenForInstrumentation = emptyFunction; +if (process.env.NODE_ENV !== 'production') { + setChildrenForInstrumentation = function (children) { + ReactInstrumentation.debugTool.onSetChildren(this._debugID, children ? Object.keys(children).map(function (key) { + return children[key]._debugID; + }) : []); + }; +} + /** * ReactMultiChild are capable of reconciling multiple children. * @@ -19034,6 +19095,7 @@ var ReactMultiChild = { mountChildren: function (nestedChildren, transaction, context) { var children = this._reconcilerInstantiateChildren(nestedChildren, transaction, context); this._renderedChildren = children; + var mountImages = []; var index = 0; for (var name in children) { @@ -19044,6 +19106,11 @@ var ReactMultiChild = { mountImages.push(mountImage); } } + + if (process.env.NODE_ENV !== 'production') { + setChildrenForInstrumentation.call(this, children); + } + return mountImages; }, @@ -19150,6 +19217,10 @@ var ReactMultiChild = { processQueue(this, updates); } this._renderedChildren = nextChildren; + + if (process.env.NODE_ENV !== 'production') { + setChildrenForInstrumentation.call(this, nextChildren); + } }, /** @@ -19241,7 +19312,7 @@ var ReactMultiChild = { module.exports = ReactMultiChild; }).call(this,require('_process')) -},{"./ReactChildReconciler":104,"./ReactComponentEnvironment":109,"./ReactCurrentOwner":111,"./ReactMultiChildUpdateTypes":152,"./ReactReconciler":162,"./flattenChildren":192,"_process":33,"fbjs/lib/invariant":229}],152:[function(require,module,exports){ +},{"./ReactChildReconciler":104,"./ReactComponentEnvironment":109,"./ReactCurrentOwner":112,"./ReactInstrumentation":146,"./ReactMultiChildUpdateTypes":151,"./ReactReconciler":161,"./flattenChildren":192,"_process":33,"fbjs/lib/emptyFunction":221,"fbjs/lib/invariant":229}],151:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -19274,7 +19345,7 @@ var ReactMultiChildUpdateTypes = keyMirror({ }); module.exports = ReactMultiChildUpdateTypes; -},{"fbjs/lib/keyMirror":232}],153:[function(require,module,exports){ +},{"fbjs/lib/keyMirror":232}],152:[function(require,module,exports){ (function (process){ /** * Copyright 2014-present, Facebook, Inc. @@ -19373,7 +19444,45 @@ var ReactNativeComponent = { module.exports = ReactNativeComponent; }).call(this,require('_process')) -},{"_process":33,"fbjs/lib/invariant":229,"object-assign":32}],154:[function(require,module,exports){ +},{"_process":33,"fbjs/lib/invariant":229,"object-assign":32}],153:[function(require,module,exports){ +/** + * Copyright 2016-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. + * + * @providesModule ReactNativeOperationHistoryDevtool + */ + +'use strict'; + +var history = []; + +var ReactNativeOperationHistoryDevtool = { + onNativeOperation: function (debugID, type, payload) { + history.push({ + instanceID: debugID, + type: type, + payload: payload + }); + }, + clearHistory: function () { + if (ReactNativeOperationHistoryDevtool._preventClearing) { + // Should only be used for tests. + return; + } + + history = []; + }, + getHistory: function () { + return history; + } +}; + +module.exports = ReactNativeOperationHistoryDevtool; +},{}],154:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -19414,7 +19523,7 @@ var ReactNodeTypes = { module.exports = ReactNodeTypes; }).call(this,require('_process')) -},{"./ReactElement":137,"_process":33,"fbjs/lib/invariant":229}],155:[function(require,module,exports){ +},{"./ReactElement":136,"_process":33,"fbjs/lib/invariant":229}],155:[function(require,module,exports){ (function (process){ /** * Copyright 2015-present, Facebook, Inc. @@ -19611,106 +19720,6 @@ module.exports = ReactOwner; },{"_process":33,"fbjs/lib/invariant":229}],157:[function(require,module,exports){ (function (process){ -/** - * Copyright 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. - * - * @providesModule ReactPerf - */ - -'use strict'; - -/** - * ReactPerf is a general AOP system designed to measure performance. This - * module only has the hooks: see ReactDefaultPerf for the analysis tool. - */ - -var ReactPerf = { - /** - * Boolean to enable/disable measurement. Set to false by default to prevent - * accidental logging and perf loss. - */ - enableMeasure: false, - - /** - * Holds onto the measure function in use. By default, don't measure - * anything, but we'll override this if we inject a measure function. - */ - storedMeasure: _noMeasure, - - /** - * @param {object} object - * @param {string} objectName - * @param {object} methodNames - */ - measureMethods: function (object, objectName, methodNames) { - if (process.env.NODE_ENV !== 'production') { - for (var key in methodNames) { - if (!methodNames.hasOwnProperty(key)) { - continue; - } - object[key] = ReactPerf.measure(objectName, methodNames[key], object[key]); - } - } - }, - - /** - * Use this to wrap methods you want to measure. Zero overhead in production. - * - * @param {string} objName - * @param {string} fnName - * @param {function} func - * @return {function} - */ - measure: function (objName, fnName, func) { - if (process.env.NODE_ENV !== 'production') { - var measuredFunc = null; - var wrapper = function () { - if (ReactPerf.enableMeasure) { - if (!measuredFunc) { - measuredFunc = ReactPerf.storedMeasure(objName, fnName, func); - } - return measuredFunc.apply(this, arguments); - } - return func.apply(this, arguments); - }; - wrapper.displayName = objName + '_' + fnName; - return wrapper; - } - return func; - }, - - injection: { - /** - * @param {function} measure - */ - injectMeasure: function (measure) { - ReactPerf.storedMeasure = measure; - } - } -}; - -/** - * Simply passes through the measured function, without measuring it. - * - * @param {string} objName - * @param {string} fnName - * @param {function} func - * @return {function} - */ -function _noMeasure(objName, fnName, func) { - return func; -} - -module.exports = ReactPerf; -}).call(this,require('_process')) - -},{"_process":33}],158:[function(require,module,exports){ -(function (process){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -19737,7 +19746,7 @@ if (process.env.NODE_ENV !== 'production') { module.exports = ReactPropTypeLocationNames; }).call(this,require('_process')) -},{"_process":33}],159:[function(require,module,exports){ +},{"_process":33}],158:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -19760,7 +19769,7 @@ var ReactPropTypeLocations = keyMirror({ }); module.exports = ReactPropTypeLocations; -},{"fbjs/lib/keyMirror":232}],160:[function(require,module,exports){ +},{"fbjs/lib/keyMirror":232}],159:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -20141,7 +20150,7 @@ function getClassName(propValue) { } module.exports = ReactPropTypes; -},{"./ReactElement":137,"./ReactPropTypeLocationNames":158,"./getIteratorFn":198,"fbjs/lib/emptyFunction":221}],161:[function(require,module,exports){ +},{"./ReactElement":136,"./ReactPropTypeLocationNames":157,"./getIteratorFn":198,"fbjs/lib/emptyFunction":221}],160:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -20304,7 +20313,7 @@ _assign(ReactReconcileTransaction.prototype, Transaction.Mixin, Mixin); PooledClass.addPoolingTo(ReactReconcileTransaction); module.exports = ReactReconcileTransaction; -},{"./CallbackQueue":81,"./PooledClass":101,"./ReactBrowserEventEmitter":103,"./ReactInputSelection":145,"./Transaction":183,"object-assign":32}],162:[function(require,module,exports){ +},{"./CallbackQueue":81,"./PooledClass":101,"./ReactBrowserEventEmitter":103,"./ReactInputSelection":144,"./Transaction":183,"object-assign":32}],161:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -20322,6 +20331,8 @@ module.exports = ReactReconcileTransaction; var ReactRef = require('./ReactRef'); var ReactInstrumentation = require('./ReactInstrumentation'); +var invariant = require('fbjs/lib/invariant'); + /** * Helper to call ReactRef.attachRefs with this composite component, split out * to avoid allocations in the transaction mount-ready queue. @@ -20344,12 +20355,20 @@ var ReactReconciler = { * @internal */ mountComponent: function (internalInstance, transaction, nativeParent, nativeContainerInfo, context) { + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginReconcilerTimer(internalInstance._debugID, 'mountComponent'); + } + } var markup = internalInstance.mountComponent(transaction, nativeParent, nativeContainerInfo, context); if (internalInstance._currentElement && internalInstance._currentElement.ref != null) { transaction.getReactMountReady().enqueue(attachRefs, internalInstance); } if (process.env.NODE_ENV !== 'production') { - ReactInstrumentation.debugTool.onMountComponent(internalInstance); + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onEndReconcilerTimer(internalInstance._debugID, 'mountComponent'); + ReactInstrumentation.debugTool.onMountComponent(internalInstance._debugID); + } } return markup; }, @@ -20369,10 +20388,18 @@ var ReactReconciler = { * @internal */ unmountComponent: function (internalInstance, safely) { + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginReconcilerTimer(internalInstance._debugID, 'unmountComponent'); + } + } ReactRef.detachRefs(internalInstance, internalInstance._currentElement); internalInstance.unmountComponent(safely); if (process.env.NODE_ENV !== 'production') { - ReactInstrumentation.debugTool.onUnmountComponent(internalInstance); + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onEndReconcilerTimer(internalInstance._debugID, 'unmountComponent'); + ReactInstrumentation.debugTool.onUnmountComponent(internalInstance._debugID); + } } }, @@ -20402,6 +20429,12 @@ var ReactReconciler = { return; } + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginReconcilerTimer(internalInstance._debugID, 'receiveComponent'); + } + } + var refsChanged = ReactRef.shouldUpdateRefs(prevElement, nextElement); if (refsChanged) { @@ -20415,7 +20448,10 @@ var ReactReconciler = { } if (process.env.NODE_ENV !== 'production') { - ReactInstrumentation.debugTool.onUpdateComponent(internalInstance); + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onEndReconcilerTimer(internalInstance._debugID, 'receiveComponent'); + ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID); + } } }, @@ -20426,10 +20462,24 @@ var ReactReconciler = { * @param {ReactReconcileTransaction} transaction * @internal */ - performUpdateIfNecessary: function (internalInstance, transaction) { + performUpdateIfNecessary: function (internalInstance, transaction, updateBatchNumber) { + if (internalInstance._updateBatchNumber !== updateBatchNumber) { + // The component's enqueued batch number should always be the current + // batch or the following one. + !(internalInstance._updateBatchNumber == null || internalInstance._updateBatchNumber === updateBatchNumber + 1) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'performUpdateIfNecessary: Unexpected batch number (current %s, ' + 'pending %s)', updateBatchNumber, internalInstance._updateBatchNumber) : invariant(false) : void 0; + return; + } + if (process.env.NODE_ENV !== 'production') { + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onBeginReconcilerTimer(internalInstance._debugID, 'performUpdateIfNecessary'); + } + } internalInstance.performUpdateIfNecessary(transaction); if (process.env.NODE_ENV !== 'production') { - ReactInstrumentation.debugTool.onUpdateComponent(internalInstance); + if (internalInstance._debugID !== 0) { + ReactInstrumentation.debugTool.onEndReconcilerTimer(internalInstance._debugID, 'performUpdateIfNecessary'); + ReactInstrumentation.debugTool.onUpdateComponent(internalInstance._debugID); + } } } @@ -20438,7 +20488,7 @@ var ReactReconciler = { module.exports = ReactReconciler; }).call(this,require('_process')) -},{"./ReactInstrumentation":147,"./ReactRef":163,"_process":33}],163:[function(require,module,exports){ +},{"./ReactInstrumentation":146,"./ReactRef":162,"_process":33,"fbjs/lib/invariant":229}],162:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -20517,7 +20567,81 @@ ReactRef.detachRefs = function (instance, element) { }; module.exports = ReactRef; -},{"./ReactOwner":156}],164:[function(require,module,exports){ +},{"./ReactOwner":156}],163:[function(require,module,exports){ +/** + * Copyright 2014-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. + * + * @providesModule ReactServerRenderingTransaction + */ + +'use strict'; + +var _assign = require('object-assign'); + +var PooledClass = require('./PooledClass'); +var Transaction = require('./Transaction'); + +/** + * Executed within the scope of the `Transaction` instance. Consider these as + * being member methods, but with an implied ordering while being isolated from + * each other. + */ +var TRANSACTION_WRAPPERS = []; + +var noopCallbackQueue = { + enqueue: function () {} +}; + +/** + * @class ReactServerRenderingTransaction + * @param {boolean} renderToStaticMarkup + */ +function ReactServerRenderingTransaction(renderToStaticMarkup) { + this.reinitializeTransaction(); + this.renderToStaticMarkup = renderToStaticMarkup; + this.useCreateElement = false; +} + +var Mixin = { + /** + * @see Transaction + * @abstract + * @final + * @return {array} Empty list of operation wrap procedures. + */ + getTransactionWrappers: function () { + return TRANSACTION_WRAPPERS; + }, + + /** + * @return {object} The queue to collect `onDOMReady` callbacks with. + */ + getReactMountReady: function () { + return noopCallbackQueue; + }, + + /** + * `PooledClass` looks for this, and will invoke this before allowing this + * instance to be reused. + */ + destructor: function () {}, + + checkpoint: function () {}, + + rollback: function () {} +}; + +_assign(ReactServerRenderingTransaction.prototype, Transaction.Mixin, Mixin); + +PooledClass.addPoolingTo(ReactServerRenderingTransaction); + +module.exports = ReactServerRenderingTransaction; +},{"./PooledClass":101,"./Transaction":183,"object-assign":32}],164:[function(require,module,exports){ (function (process){ /** * Copyright 2015-present, Facebook, Inc. @@ -20736,7 +20860,7 @@ var ReactUpdateQueue = { module.exports = ReactUpdateQueue; }).call(this,require('_process')) -},{"./ReactCurrentOwner":111,"./ReactInstanceMap":146,"./ReactUpdates":165,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],165:[function(require,module,exports){ +},{"./ReactCurrentOwner":112,"./ReactInstanceMap":145,"./ReactUpdates":165,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],165:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -20756,13 +20880,14 @@ var _assign = require('object-assign'); var CallbackQueue = require('./CallbackQueue'); var PooledClass = require('./PooledClass'); var ReactFeatureFlags = require('./ReactFeatureFlags'); -var ReactPerf = require('./ReactPerf'); +var ReactInstrumentation = require('./ReactInstrumentation'); var ReactReconciler = require('./ReactReconciler'); var Transaction = require('./Transaction'); var invariant = require('fbjs/lib/invariant'); var dirtyComponents = []; +var updateBatchNumber = 0; var asapCallbackQueue = CallbackQueue.getPooled(); var asapEnqueued = false; @@ -20857,6 +20982,13 @@ function runBatchedUpdates(transaction) { // them before their children by sorting the array. dirtyComponents.sort(mountOrderComparator); + // Any updates enqueued while reconciling must be performed after this entire + // batch. Otherwise, if dirtyComponents is [A, B] where A has children B and + // C, B could update twice in a single batch if C's render enqueues an update + // to B (since B would have already updated, we should skip it, and the only + // way we can know to do so is by checking the batch counter). + updateBatchNumber++; + for (var i = 0; i < len; i++) { // If a component is unmounted before pending changes apply, it will still // be here, but we assume that it has cleared its _pendingCallbacks and @@ -20880,7 +21012,7 @@ function runBatchedUpdates(transaction) { console.time(markerName); } - ReactReconciler.performUpdateIfNecessary(component, transaction.reconcileTransaction); + ReactReconciler.performUpdateIfNecessary(component, transaction.reconcileTransaction, updateBatchNumber); if (markerName) { console.timeEnd(markerName); @@ -20895,6 +21027,10 @@ function runBatchedUpdates(transaction) { } var flushBatchedUpdates = function () { + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onBeginFlush(); + } + // ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents // array and perform any updates enqueued by mount-ready handlers (i.e., // componentDidUpdate) but we need to check here too in order to catch @@ -20914,8 +21050,11 @@ var flushBatchedUpdates = function () { CallbackQueue.release(queue); } } + + if (process.env.NODE_ENV !== 'production') { + ReactInstrumentation.debugTool.onEndFlush(); + } }; -flushBatchedUpdates = ReactPerf.measure('ReactUpdates', 'flushBatchedUpdates', flushBatchedUpdates); /** * Mark a component as needing a rerender, adding an optional callback to a @@ -20936,6 +21075,9 @@ function enqueueUpdate(component) { } dirtyComponents.push(component); + if (component._updateBatchNumber == null) { + component._updateBatchNumber = updateBatchNumber + 1; + } } /** @@ -20981,7 +21123,7 @@ var ReactUpdates = { module.exports = ReactUpdates; }).call(this,require('_process')) -},{"./CallbackQueue":81,"./PooledClass":101,"./ReactFeatureFlags":143,"./ReactPerf":157,"./ReactReconciler":162,"./Transaction":183,"_process":33,"fbjs/lib/invariant":229,"object-assign":32}],166:[function(require,module,exports){ +},{"./CallbackQueue":81,"./PooledClass":101,"./ReactFeatureFlags":142,"./ReactInstrumentation":146,"./ReactReconciler":161,"./Transaction":183,"_process":33,"fbjs/lib/invariant":229,"object-assign":32}],166:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -20995,7 +21137,7 @@ module.exports = ReactUpdates; 'use strict'; -module.exports = '15.0.2'; +module.exports = '15.1.0'; },{}],167:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. @@ -21494,7 +21636,7 @@ var SelectEventPlugin = { }; module.exports = SelectEventPlugin; -},{"./EventConstants":92,"./EventPropagators":96,"./ReactDOMComponentTree":116,"./ReactInputSelection":145,"./SyntheticEvent":174,"./isTextInputElement":205,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/getActiveElement":224,"fbjs/lib/keyOf":233,"fbjs/lib/shallowEqual":238}],169:[function(require,module,exports){ +},{"./EventConstants":92,"./EventPropagators":96,"./ReactDOMComponentTree":117,"./ReactInputSelection":144,"./SyntheticEvent":174,"./isTextInputElement":205,"fbjs/lib/ExecutionEnvironment":215,"fbjs/lib/getActiveElement":224,"fbjs/lib/keyOf":233,"fbjs/lib/shallowEqual":238}],169:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -22125,7 +22267,7 @@ var SimpleEventPlugin = { module.exports = SimpleEventPlugin; }).call(this,require('_process')) -},{"./EventConstants":92,"./EventPropagators":96,"./ReactDOMComponentTree":116,"./SyntheticAnimationEvent":170,"./SyntheticClipboardEvent":171,"./SyntheticDragEvent":173,"./SyntheticEvent":174,"./SyntheticFocusEvent":175,"./SyntheticKeyboardEvent":177,"./SyntheticMouseEvent":178,"./SyntheticTouchEvent":179,"./SyntheticTransitionEvent":180,"./SyntheticUIEvent":181,"./SyntheticWheelEvent":182,"./getEventCharCode":194,"_process":33,"fbjs/lib/EventListener":214,"fbjs/lib/emptyFunction":221,"fbjs/lib/invariant":229,"fbjs/lib/keyOf":233}],170:[function(require,module,exports){ +},{"./EventConstants":92,"./EventPropagators":96,"./ReactDOMComponentTree":117,"./SyntheticAnimationEvent":170,"./SyntheticClipboardEvent":171,"./SyntheticDragEvent":173,"./SyntheticEvent":174,"./SyntheticFocusEvent":175,"./SyntheticKeyboardEvent":177,"./SyntheticMouseEvent":178,"./SyntheticTouchEvent":179,"./SyntheticTransitionEvent":180,"./SyntheticUIEvent":181,"./SyntheticWheelEvent":182,"./getEventCharCode":194,"_process":33,"fbjs/lib/EventListener":214,"fbjs/lib/emptyFunction":221,"fbjs/lib/invariant":229,"fbjs/lib/keyOf":233}],170:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -23554,6 +23696,8 @@ var warning = require('fbjs/lib/warning'); /** * Returns the DOM node rendered by this element. * + * See https://facebook.github.io/react/docs/top-level-api.html#reactdom.finddomnode + * * @param {ReactComponent|DOMElement} componentOrElement * @return {?DOMElement} The root node of this element. */ @@ -23588,7 +23732,7 @@ function findDOMNode(componentOrElement) { module.exports = findDOMNode; }).call(this,require('_process')) -},{"./ReactCurrentOwner":111,"./ReactDOMComponentTree":116,"./ReactInstanceMap":146,"./getNativeComponentFromComposite":199,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],192:[function(require,module,exports){ +},{"./ReactCurrentOwner":112,"./ReactDOMComponentTree":117,"./ReactInstanceMap":145,"./getNativeComponentFromComposite":199,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],192:[function(require,module,exports){ (function (process){ /** * Copyright 2013-present, Facebook, Inc. @@ -24209,6 +24353,7 @@ var _assign = require('object-assign'); var ReactCompositeComponent = require('./ReactCompositeComponent'); var ReactEmptyComponent = require('./ReactEmptyComponent'); var ReactNativeComponent = require('./ReactNativeComponent'); +var ReactInstrumentation = require('./ReactInstrumentation'); var invariant = require('fbjs/lib/invariant'); var warning = require('fbjs/lib/warning'); @@ -24231,6 +24376,21 @@ function getDeclarationErrorAddendum(owner) { return ''; } +function getDisplayName(instance) { + var element = instance._currentElement; + if (element == null) { + return '#empty'; + } else if (typeof element === 'string' || typeof element === 'number') { + return '#text'; + } else if (typeof element.type === 'string') { + return element.type; + } else if (instance.getName) { + return instance.getName() || 'Unknown'; + } else { + return element.type.displayName || element.type.name || 'Unknown'; + } +} + /** * Check if the type reference is a known internal type. I.e. not a user * provided composite type. @@ -24242,6 +24402,8 @@ function isInternalComponentType(type) { return typeof type === 'function' && typeof type.prototype !== 'undefined' && typeof type.prototype.mountComponent === 'function' && typeof type.prototype.receiveComponent === 'function'; } +var nextDebugID = 1; + /** * Given a ReactNode, create an instance that will actually be mounted. * @@ -24252,7 +24414,8 @@ function isInternalComponentType(type) { function instantiateReactComponent(node) { var instance; - if (node === null || node === false) { + var isEmpty = node === null || node === false; + if (isEmpty) { instance = ReactEmptyComponent.create(instantiateReactComponent); } else if (typeof node === 'object') { var element = node; @@ -24290,6 +24453,20 @@ function instantiateReactComponent(node) { instance._warnedAboutRefsInRender = false; } + if (process.env.NODE_ENV !== 'production') { + var debugID = isEmpty ? 0 : nextDebugID++; + instance._debugID = debugID; + + if (debugID !== 0) { + var displayName = getDisplayName(instance); + ReactInstrumentation.debugTool.onSetDisplayName(debugID, displayName); + var owner = node && node._owner; + if (owner) { + ReactInstrumentation.debugTool.onSetOwner(debugID, owner._debugID); + } + } + } + // Internal instances should fully constructed at this point, so they should // not get any new fields added to them at this point. if (process.env.NODE_ENV !== 'production') { @@ -24304,7 +24481,7 @@ function instantiateReactComponent(node) { module.exports = instantiateReactComponent; }).call(this,require('_process')) -},{"./ReactCompositeComponent":110,"./ReactEmptyComponent":139,"./ReactNativeComponent":153,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239,"object-assign":32}],204:[function(require,module,exports){ +},{"./ReactCompositeComponent":111,"./ReactEmptyComponent":138,"./ReactInstrumentation":146,"./ReactNativeComponent":152,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239,"object-assign":32}],204:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -24427,10 +24604,13 @@ var invariant = require('fbjs/lib/invariant'); /** * Returns the first child in a collection of children and verifies that there - * is only one child in the collection. The current implementation of this - * function assumes that a single child gets passed without a wrapper, but the - * purpose of this helper function is to abstract away the particular structure - * of children. + * is only one child in the collection. + * + * See https://facebook.github.io/react/docs/top-level-api.html#react.children.only + * + * The current implementation of this function assumes that a single child gets + * passed without a wrapper, but the purpose of this helper function is to + * abstract away the particular structure of children. * * @param {?object} children Child collection structure. * @return {ReactElement} The first and only `ReactElement` contained in the @@ -24444,7 +24624,7 @@ function onlyChild(children) { module.exports = onlyChild; }).call(this,require('_process')) -},{"./ReactElement":137,"_process":33,"fbjs/lib/invariant":229}],207:[function(require,module,exports){ +},{"./ReactElement":136,"_process":33,"fbjs/lib/invariant":229}],207:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -24488,7 +24668,7 @@ module.exports = quoteAttributeValueForBrowser; var ReactMount = require('./ReactMount'); module.exports = ReactMount.renderSubtreeIntoContainer; -},{"./ReactMount":150}],209:[function(require,module,exports){ +},{"./ReactMount":149}],209:[function(require,module,exports){ /** * Copyright 2013-present, Facebook, Inc. * All rights reserved. @@ -24817,7 +24997,7 @@ function traverseAllChildren(children, callback, traverseContext) { module.exports = traverseAllChildren; }).call(this,require('_process')) -},{"./KeyEscapeUtils":99,"./ReactCurrentOwner":111,"./ReactElement":137,"./getIteratorFn":198,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],213:[function(require,module,exports){ +},{"./KeyEscapeUtils":99,"./ReactCurrentOwner":112,"./ReactElement":136,"./getIteratorFn":198,"_process":33,"fbjs/lib/invariant":229,"fbjs/lib/warning":239}],213:[function(require,module,exports){ (function (process){ /** * Copyright 2015-present, Facebook, Inc. @@ -25227,18 +25407,18 @@ var EventListener = { * @param {function} callback Callback function. * @return {object} Object with a `remove` method. */ - listen: function (target, eventType, callback) { + listen: function listen(target, eventType, callback) { if (target.addEventListener) { target.addEventListener(eventType, callback, false); return { - remove: function () { + remove: function remove() { target.removeEventListener(eventType, callback, false); } }; } else if (target.attachEvent) { target.attachEvent('on' + eventType, callback); return { - remove: function () { + remove: function remove() { target.detachEvent('on' + eventType, callback); } }; @@ -25253,11 +25433,11 @@ var EventListener = { * @param {function} callback Callback function. * @return {object} Object with a `remove` method. */ - capture: function (target, eventType, callback) { + capture: function capture(target, eventType, callback) { if (target.addEventListener) { target.addEventListener(eventType, callback, true); return { - remove: function () { + remove: function remove() { target.removeEventListener(eventType, callback, true); } }; @@ -25271,7 +25451,7 @@ var EventListener = { } }, - registerDefault: function () {} + registerDefault: function registerDefault() {} }; module.exports = EventListener; @@ -25396,7 +25576,7 @@ module.exports = camelizeStyleName; * 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. * - * @typechecks + * */ var isTextNode = require('./isTextNode'); @@ -25405,10 +25585,6 @@ var isTextNode = require('./isTextNode'); /** * Checks if a given DOM node contains or is another DOM node. - * - * @param {?DOMNode} outerNode Outer DOM node. - * @param {?DOMNode} innerNode Inner DOM node. - * @return {boolean} True if `outerNode` contains or is `innerNode`. */ function containsNode(outerNode, innerNode) { if (!outerNode || !innerNode) { @@ -25419,7 +25595,7 @@ function containsNode(outerNode, innerNode) { return false; } else if (isTextNode(innerNode)) { return containsNode(outerNode, innerNode.parentNode); - } else if (outerNode.contains) { + } else if ('contains' in outerNode) { return outerNode.contains(innerNode); } else if (outerNode.compareDocumentPosition) { return !!(outerNode.compareDocumentPosition(innerNode) & 16); @@ -25657,6 +25833,7 @@ module.exports = createNodesFromMarkup; * 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. * + * */ function makeEmptyFunction(arg) { @@ -25670,7 +25847,7 @@ function makeEmptyFunction(arg) { * primarily useful idiomatically for overridable function endpoints which * always need to be callable, since JS lacks a null-call idiom ala Cocoa. */ -function emptyFunction() {} +var emptyFunction = function emptyFunction() {}; emptyFunction.thatReturns = makeEmptyFunction; emptyFunction.thatReturnsFalse = makeEmptyFunction(false); @@ -26114,7 +26291,7 @@ var invariant = require('./invariant'); * @param {object} obj * @return {object} */ -var keyMirror = function (obj) { +var keyMirror = function keyMirror(obj) { var ret = {}; var key; !(obj instanceof Object && !Array.isArray(obj)) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'keyMirror(...): Argument must be an object.') : invariant(false) : void 0; @@ -26153,7 +26330,7 @@ module.exports = keyMirror; * 'xa12' in that case. Resolve keys you want to use once at startup time, then * reuse those resolutions. */ -var keyOf = function (oneKeyObj) { +var keyOf = function keyOf(oneKeyObj) { var key; for (key in oneKeyObj) { if (!oneKeyObj.hasOwnProperty(key)) { @@ -26225,6 +26402,7 @@ module.exports = mapObject; * 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. * + * * @typechecks static-only */ @@ -26232,9 +26410,6 @@ module.exports = mapObject; /** * Memoizes the return value of a function that accepts one string argument. - * - * @param {function} callback - * @return {function} */ function memoizeStringOnly(callback) { @@ -26295,11 +26470,11 @@ var performanceNow; * because of Facebook's testing infrastructure. */ if (performance.now) { - performanceNow = function () { + performanceNow = function performanceNow() { return performance.now(); }; } else { - performanceNow = function () { + performanceNow = function performanceNow() { return Date.now(); }; } @@ -26398,7 +26573,7 @@ var emptyFunction = require('./emptyFunction'); var warning = emptyFunction; if (process.env.NODE_ENV !== 'production') { - warning = function (condition, format) { + warning = function warning(condition, format) { for (var _len = arguments.length, args = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { args[_key - 2] = arguments[_key]; } @@ -53172,7 +53347,7 @@ return jQuery; module.exports = require('react/lib/ReactDOM'); -},{"react/lib/ReactDOM":112}],"react-redux":[function(require,module,exports){ +},{"react/lib/ReactDOM":113}],"react-redux":[function(require,module,exports){ 'use strict'; exports.__esModule = true; diff --git a/web/src/js/components/flowtable-columns.js b/web/src/js/components/flowtable-columns.js index dbbe8847b..1eae64098 100644 --- a/web/src/js/components/flowtable-columns.js +++ b/web/src/js/components/flowtable-columns.js @@ -1,190 +1,121 @@ -import React from "react"; -import {RequestUtils, ResponseUtils} from "../flow/utils.js"; -import {formatSize, formatTimeDelta} from "../utils.js"; +import React from "react" +import {RequestUtils, ResponseUtils} from "../flow/utils.js" +import {formatSize, formatTimeDelta} from "../utils.js" -var TLSColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return ; - } - }), - sortKeyFun: function(flow){ - return flow.request.scheme; - } - }, - render: function () { - var flow = this.props.flow; - var ssl = (flow.request.scheme === "https"); - var classes; - if (ssl) { - classes = "col-tls col-tls-https"; - } else { - classes = "col-tls col-tls-http"; - } - return ; + +function TLSColumn({flow}) { + let ssl = (flow.request.scheme === "https") + let classes + if (ssl) { + classes = "col-tls col-tls-https" + } else { + classes = "col-tls col-tls-http" } -}); + return +} +TLSColumn.Title = ({className = "", ...props}) => +TLSColumn.sortKeyFun = flow => flow.request.scheme -var IconColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return ; - } - }) - }, - render: function () { - var flow = this.props.flow; +function IconColumn({flow}) { + let icon + if (flow.response) { + var contentType = ResponseUtils.getContentType(flow.response) - var icon; - if (flow.response) { - var contentType = ResponseUtils.getContentType(flow.response); - - //TODO: We should assign a type to the flow somewhere else. - if (flow.response.status_code === 304) { - icon = "resource-icon-not-modified"; - } else if (300 <= flow.response.status_code && flow.response.status_code < 400) { - icon = "resource-icon-redirect"; - } else if (contentType && contentType.indexOf("image") >= 0) { - icon = "resource-icon-image"; - } else if (contentType && contentType.indexOf("javascript") >= 0) { - icon = "resource-icon-js"; - } else if (contentType && contentType.indexOf("css") >= 0) { - icon = "resource-icon-css"; - } else if (contentType && contentType.indexOf("html") >= 0) { - icon = "resource-icon-document"; - } + //TODO: We should assign a type to the flow somewhere else. + if (flow.response.status_code === 304) { + icon = "resource-icon-not-modified" + } else if (300 <= flow.response.status_code && flow.response.status_code < 400) { + icon = "resource-icon-redirect" + } else if (contentType && contentType.indexOf("image") >= 0) { + icon = "resource-icon-image" + } else if (contentType && contentType.indexOf("javascript") >= 0) { + icon = "resource-icon-js" + } else if (contentType && contentType.indexOf("css") >= 0) { + icon = "resource-icon-css" + } else if (contentType && contentType.indexOf("html") >= 0) { + icon = "resource-icon-document" } - if (!icon) { - icon = "resource-icon-plain"; - } - - - icon += " resource-icon"; - return -
- ; } -}); - -var PathColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return Path; - } - }), - sortKeyFun: function(flow){ - return RequestUtils.pretty_url(flow.request); - } - }, - render: function () { - var flow = this.props.flow; - return - {flow.request.is_replay ? : null} - {flow.intercepted ? : null} - { RequestUtils.pretty_url(flow.request) } - ; + if (!icon) { + icon = "resource-icon-plain" } -}); + + icon += " resource-icon" + return +
+ +} +IconColumn.Title = ({className = "", ...props}) => -var MethodColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return Method; - } - }), - sortKeyFun: function(flow){ - return flow.request.method; - } - }, - render: function () { - var flow = this.props.flow; - return {flow.request.method}; +function PathColumn({flow}) { + return + {flow.request.is_replay ? : null} + {flow.intercepted ? : null} + { RequestUtils.pretty_url(flow.request) } + +} +PathColumn.Title = ({className = "", ...props}) => + Path +PathColumn.sortKeyFun = flow => RequestUtils.pretty_url(flow.request) + + +function MethodColumn({flow}) { + return {flow.request.method} +} +MethodColumn.Title = ({className = "", ...props}) => + Method +MethodColumn.sortKeyFun = flow => flow.request.method + + +function StatusColumn({flow}) { + let status + if (flow.response) { + status = flow.response.status_code + } else { + status = null } -}); + return {status} + +} +StatusColumn.Title = ({className = "", ...props}) => + Status +StatusColumn.sortKeyFun = flow => flow.response ? flow.response.status_code : undefined -var StatusColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return Status; - } - }), - sortKeyFun: function(flow){ - return flow.response ? flow.response.status_code : undefined; - } - }, - render: function () { - var flow = this.props.flow; - var status; - if (flow.response) { - status = flow.response.status_code; - } else { - status = null; - } - return {status}; +function SizeColumn({flow}) { + let total = flow.request.contentLength + if (flow.response) { + total += flow.response.contentLength || 0 } -}); + let size = formatSize(total) + return {size} - -var SizeColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return Size; - } - }), - sortKeyFun: function(flow){ - var total = flow.request.contentLength; - if (flow.response) { - total += flow.response.contentLength || 0; - } - return total; - } - }, - render: function () { - var flow = this.props.flow; - - var total = flow.request.contentLength; - if (flow.response) { - total += flow.response.contentLength || 0; - } - var size = formatSize(total); - return {size}; +} +SizeColumn.Title = ({className = "", ...props}) => + Size +SizeColumn.sortKeyFun = flow => { + let total = flow.request.contentLength + if (flow.response) { + total += flow.response.contentLength || 0 } -}); + return total +} -var TimeColumn = React.createClass({ - statics: { - Title: React.createClass({ - render: function(){ - return Time; - } - }), - sortKeyFun: function(flow){ - if(flow.response) { - return flow.response.timestamp_end - flow.request.timestamp_start; - } - } - }, - render: function () { - var flow = this.props.flow; - var time; - if (flow.response) { - time = formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start)); - } else { - time = "..."; - } - return {time}; +function TimeColumn({flow}) { + let time + if (flow.response) { + time = formatTimeDelta(1000 * (flow.response.timestamp_end - flow.request.timestamp_start)) + } else { + time = "..." } -}); + return {time} +} +TimeColumn.Title = ({className = "", ...props}) => + Time +TimeColumn.sortKeyFun = flow => flow.response.timestamp_end - flow.request.timestamp_start var all_columns = [ @@ -195,6 +126,6 @@ var all_columns = [ StatusColumn, SizeColumn, TimeColumn -]; +] -export default all_columns; +export default all_columns diff --git a/web/src/js/components/flowtable.js b/web/src/js/components/flowtable.js index 0241cd78b..d621387cc 100644 --- a/web/src/js/components/flowtable.js +++ b/web/src/js/components/flowtable.js @@ -19,21 +19,20 @@ FlowRow.propTypes = { selected: React.PropTypes.bool, }; -function FlowRow(props) { - const flow = props.flow; +function FlowRow({flow, selected, highlight, columns, selectFlow}) { const className = classNames({ - "selected": props.selected, - "highlighted": props.highlight && parseFilter(props.highlight)(flow), + "selected": selected, + "highlighted": highlight && parseFilter(highlight)(flow), "intercepted": flow.intercepted, "has-request": flow.request, "has-response": flow.response, }); return ( - props.selectFlow(flow)}> - {props.columns.map(Column => ( - + selectFlow(flow)}> + {columns.map(Column => ( + ))} ); @@ -44,11 +43,8 @@ const FlowRowContainer = connect( flow: state.flows.all.byId[ownProps.flowId], highlight: state.flows.highlight, selected: state.flows.selected.indexOf(ownProps.flowId) >= 0 - }), - (dispatch, ownProps) => ({ - }) -)(FlowRow); +)(FlowRow) class FlowTableHead extends React.Component { @@ -59,7 +55,7 @@ class FlowTableHead extends React.Component { constructor(props, context) { super(props, context); - this.state = { sortColumn: undefined, sortDesc: false }; + this.state = {sortColumn: undefined, sortDesc: false}; } onClick(Column) { @@ -69,20 +65,20 @@ class FlowTableHead extends React.Component { if (Column === this.state.sortColumn) { sortDesc = !sortDesc; - this.setState({ sortDesc }); + this.setState({sortDesc}); } else { - this.setState({ sortColumn: hasSort && Column, sortDesc: false }); + this.setState({sortColumn: hasSort && Column, sortDesc: false}); } let sortKeyFun = Column.sortKeyFun; if (sortDesc) { - sortKeyFun = hasSort && function() { - const k = Column.sortKeyFun.apply(this, arguments); - if (_.isString(k)) { - return reverseString("" + k); - } - return -k; - }; + sortKeyFun = hasSort && function () { + const k = Column.sortKeyFun.apply(this, arguments); + if (_.isString(k)) { + return reverseString("" + k); + } + return -k; + }; } this.props.setSortKeyFun(sortKeyFun); @@ -95,9 +91,9 @@ class FlowTableHead extends React.Component { {this.props.columns.map(Column => ( this.onClick(Column)} - className={sortColumn === Column && sortType} + className={sortColumn === Column ? sortType : undefined} /> ))} @@ -118,7 +114,7 @@ class FlowTable extends React.Component { constructor(props, context) { super(props, context); - this.state = { vScroll: calcVScroll() }; + this.state = {vScroll: calcVScroll()}; this.onViewportUpdate = this.onViewportUpdate.bind(this); } @@ -132,7 +128,7 @@ class FlowTable extends React.Component { } componentWillReceiveProps(nextProps) { - if(nextProps.selected && nextProps.selected !== this.props.selected){ + if (nextProps.selected && nextProps.selected !== this.props.selected) { window.setTimeout(() => this.scrollIntoView(nextProps.selected), 1) } } @@ -154,7 +150,7 @@ class FlowTable extends React.Component { if (!shallowEqual(this.state.vScroll, vScroll) || this.state.viewportTop !== viewportTop) { - this.setState({ vScroll, viewportTop }); + this.setState({vScroll, viewportTop}); } } @@ -190,22 +186,22 @@ class FlowTable extends React.Component {
- + - - {flows.map(flow => ( - - ))} - + + {flows.map(flow => ( + + ))} +
@@ -221,8 +217,6 @@ const parseFilter = _.memoize(Filt.parse) const FlowTableContainer = connect( state => ({ flows: state.flows.view, - }), - dispatch => ({ }) )(FlowTable)