diff options
author | Maximilian Hils <git@maximilianhils.com> | 2015-03-27 21:58:04 +0100 |
---|---|---|
committer | Maximilian Hils <git@maximilianhils.com> | 2015-03-27 21:58:04 +0100 |
commit | 1913975fa60c76bfb7e79a908b18e7e93793f71f (patch) | |
tree | 54a4ea1605e2d8219d2983d2181ce4b27168ed49 /web | |
parent | f39e6c5c18890de902d061226ba413254114c8ad (diff) | |
download | mitmproxy-1913975fa60c76bfb7e79a908b18e7e93793f71f.tar.gz mitmproxy-1913975fa60c76bfb7e79a908b18e7e93793f71f.tar.bz2 mitmproxy-1913975fa60c76bfb7e79a908b18e7e93793f71f.zip |
web: use contexts to pass down stores.
Using contexts frees us from the contracts we have
using props - namely, we can assume them to be constant
for the lifetime of the object.
Diffstat (limited to 'web')
-rw-r--r-- | web/src/js/components/common.js | 55 | ||||
-rw-r--r-- | web/src/js/components/eventlog.js | 43 | ||||
-rw-r--r-- | web/src/js/components/flowtable.js | 42 | ||||
-rw-r--r-- | web/src/js/components/flowview/index.js | 2 | ||||
-rw-r--r-- | web/src/js/components/footer.js | 6 | ||||
-rw-r--r-- | web/src/js/components/header.js | 10 | ||||
-rw-r--r-- | web/src/js/components/mainview.js | 63 | ||||
-rw-r--r-- | web/src/js/components/proxyapp.js | 44 | ||||
-rw-r--r-- | web/src/js/store/view.js | 1 |
9 files changed, 130 insertions, 136 deletions
diff --git a/web/src/js/components/common.js b/web/src/js/components/common.js index 433e4f10..b0aa0977 100644 --- a/web/src/js/components/common.js +++ b/web/src/js/components/common.js @@ -7,8 +7,8 @@ var AutoScrollMixin = { componentWillUpdate: function () { var node = this.getDOMNode(); this._shouldScrollBottom = ( - node.scrollTop !== 0 && - node.scrollTop + node.clientHeight === node.scrollHeight + node.scrollTop !== 0 && + node.scrollTop + node.clientHeight === node.scrollHeight ); }, componentDidUpdate: function () { @@ -29,32 +29,54 @@ var StickyHeadMixin = { } }; +var SettingsState = { + contextTypes: { + settingsStore: React.PropTypes.object.isRequired + }, + getInitialState: function () { + return { + settings: this.context.settingsStore.dict + }; + }, + componentDidMount: function () { + this.context.settingsStore.addListener("recalculate", this.onSettingsChange); + }, + componentWillUnmount: function () { + this.context.settingsStore.removeListener("recalculate", this.onSettingsChange); + }, + onSettingsChange: function () { + this.setState({ + settings: this.context.settingsStore.dict + }); + }, +}; + var ChildFocus = { - contextTypes: { - returnFocus: React.PropTypes.func - } + contextTypes: { + returnFocus: React.PropTypes.func + } }; var Navigation = _.extend({}, ReactRouter.Navigation, { setQuery: function (dict) { var q = this.context.router.getCurrentQuery(); - for(var i in dict){ - if(dict.hasOwnProperty(i)){ + for (var i in dict) { + if (dict.hasOwnProperty(i)) { q[i] = dict[i] || undefined; //falsey values shall be removed. } } this.replaceWith(this.context.router.getCurrentPath(), this.context.router.getCurrentParams(), q); }, - replaceWith: function(routeNameOrPath, params, query) { - if(routeNameOrPath === undefined){ + replaceWith: function (routeNameOrPath, params, query) { + if (routeNameOrPath === undefined) { routeNameOrPath = this.context.router.getCurrentPath(); } - if(params === undefined){ + if (params === undefined) { params = this.context.router.getCurrentParams(); } - if(query === undefined) { + if (query === undefined) { query = this.context.router.getCurrentQuery(); } @@ -65,13 +87,13 @@ var Navigation = _.extend({}, ReactRouter.Navigation, { // react-router is fairly good at changing its API regularly. // We keep the old method for now - if it should turn out that their changes are permanent, // we may remove this mixin and access react-router directly again. -var State = _.extend({}, ReactRouter.State, { - getQuery: function(){ +var RouterState = _.extend({}, ReactRouter.State, { + getQuery: function () { // For whatever reason, react-router always returns the same object, which makes comparing // the current props with nextProps impossible. As a workaround, we just clone the query object. return _.clone(this.context.router.getCurrentQuery()); }, - getParams: function(){ + getParams: function () { return _.clone(this.context.router.getCurrentParams()); } }); @@ -183,9 +205,10 @@ var Splitter = React.createClass({ module.exports = { ChildFocus: ChildFocus, - State: State, + RouterState: RouterState, Navigation: Navigation, StickyHeadMixin: StickyHeadMixin, AutoScrollMixin: AutoScrollMixin, - Splitter: Splitter + Splitter: Splitter, + SettingsState: SettingsState };
\ No newline at end of file diff --git a/web/src/js/components/eventlog.js b/web/src/js/components/eventlog.js index de69462b..65024712 100644 --- a/web/src/js/components/eventlog.js +++ b/web/src/js/components/eventlog.js @@ -31,46 +31,37 @@ var LogMessage = React.createClass({ }); var EventLogContents = React.createClass({ + contextTypes: { + eventStore: React.PropTypes.object.isRequired + }, mixins: [common.AutoScrollMixin, VirtualScrollMixin], getInitialState: function () { - return { - log: [] - }; - }, - componentWillMount: function () { - this.openView(this.props.eventStore); - }, - componentWillUnmount: function () { - this.closeView(); - }, - openView: function (store) { - var view = new views.StoreView(store, function (entry) { + var filterFn = function (entry) { return this.props.filter[entry.level]; - }.bind(this)); - this.setState({ - view: view - }); - + }; + var view = new views.StoreView(this.context.eventStore, filterFn.bind(this)); view.addListener("add", this.onEventLogChange); view.addListener("recalculate", this.onEventLogChange); + + return { + log: view.list, + view: view + }; }, - closeView: function () { + componentWillUnmount: function () { this.state.view.close(); }, + filter: function (entry) { + return this.props.filter[entry.level]; + }, onEventLogChange: function () { - this.setState({ - log: this.state.view.list - }); + this.forceUpdate(); }, componentWillReceiveProps: function (nextProps) { if (nextProps.filter !== this.props.filter) { this.props.filter = nextProps.filter; // Dirty: Make sure that view filter sees the update. this.state.view.recalculate(); } - if (nextProps.eventStore !== this.props.eventStore) { - this.closeView(); - this.openView(nextProps.eventStore); - } }, getDefaultProps: function () { return { @@ -149,7 +140,7 @@ var EventLog = React.createClass({ </div> </div> - <EventLogContents filter={this.state.filter} eventStore={this.props.eventStore}/> + <EventLogContents filter={this.state.filter}/> </div> ); } diff --git a/web/src/js/components/flowtable.js b/web/src/js/components/flowtable.js index 4217786a..609034f6 100644 --- a/web/src/js/components/flowtable.js +++ b/web/src/js/components/flowtable.js @@ -108,33 +108,25 @@ var ROW_HEIGHT = 32; var FlowTable = React.createClass({ mixins: [common.StickyHeadMixin, common.AutoScrollMixin, VirtualScrollMixin], + contextTypes: { + view: React.PropTypes.object.isRequired + }, getInitialState: function () { return { columns: flowtable_columns }; }, - _listen: function(view){ - if(!view){ - return; - } - view.addListener("add", this.onChange); - view.addListener("update", this.onChange); - view.addListener("remove", this.onChange); - view.addListener("recalculate", this.onChange); - }, componentWillMount: function () { - this._listen(this.props.view); + this.context.view.addListener("add", this.onChange); + this.context.view.addListener("update", this.onChange); + this.context.view.addListener("remove", this.onChange); + this.context.view.addListener("recalculate", this.onChange); }, - componentWillReceiveProps: function (nextProps) { - if (nextProps.view !== this.props.view) { - if (this.props.view) { - this.props.view.removeListener("add"); - this.props.view.removeListener("update"); - this.props.view.removeListener("remove"); - this.props.view.removeListener("recalculate"); - } - this._listen(nextProps.view); - } + componentWillUnmount: function(){ + this.context.view.removeListener("add", this.onChange); + this.context.view.removeListener("update", this.onChange); + this.context.view.removeListener("remove", this.onChange); + this.context.view.removeListener("recalculate", this.onChange); }, getDefaultProps: function () { return { @@ -150,7 +142,7 @@ var FlowTable = React.createClass({ }, scrollIntoView: function (flow) { this.scrollRowIntoView( - this.props.view.index(flow), + this.context.view.index(flow), this.refs.body.getDOMNode().offsetTop ); }, @@ -158,8 +150,8 @@ var FlowTable = React.createClass({ var selected = (flow === this.props.selected); var highlighted = ( - this.props.view._highlight && - this.props.view._highlight[flow.id] + this.context.view._highlight && + this.context.view._highlight[flow.id] ); return <FlowRow key={flow.id} @@ -172,9 +164,7 @@ var FlowTable = React.createClass({ />; }, render: function () { - //console.log("render flowtable", this.state.start, this.state.stop, this.props.selected); - var flows = this.props.view ? this.props.view.list : []; - + var flows = this.context.view.list; var rows = this.renderRows(flows); return ( diff --git a/web/src/js/components/flowview/index.js b/web/src/js/components/flowview/index.js index 0c31aca5..4214714e 100644 --- a/web/src/js/components/flowview/index.js +++ b/web/src/js/components/flowview/index.js @@ -14,7 +14,7 @@ var allTabs = { }; var FlowView = React.createClass({ - mixins: [common.StickyHeadMixin, common.Navigation, common.State], + mixins: [common.StickyHeadMixin, common.Navigation, common.RouterState], getTabs: function (flow) { var tabs = []; ["request", "response", "error"].forEach(function (e) { diff --git a/web/src/js/components/footer.js b/web/src/js/components/footer.js index d04fb615..52d6d0ad 100644 --- a/web/src/js/components/footer.js +++ b/web/src/js/components/footer.js @@ -1,9 +1,11 @@ var React = require("react"); +var common = require("./common.js"); var Footer = React.createClass({ + mixins: [common.SettingsState], render: function () { - var mode = this.props.settings.mode; - var intercept = this.props.settings.intercept; + var mode = this.state.settings.mode; + var intercept = this.state.settings.intercept; return ( <footer> {mode != "regular" ? <span className="label label-success">{mode} mode</span> : null} diff --git a/web/src/js/components/header.js b/web/src/js/components/header.js index dcfdd2ae..b2934df6 100644 --- a/web/src/js/components/header.js +++ b/web/src/js/components/header.js @@ -157,7 +157,7 @@ var FilterInput = React.createClass({ }); var MainMenu = React.createClass({ - mixins: [common.Navigation, common.State], + mixins: [common.Navigation, common.RouterState, common.SettingsState], statics: { title: "Start", route: "flows" @@ -178,7 +178,7 @@ var MainMenu = React.createClass({ render: function () { var filter = this.getQuery()[Query.FILTER] || ""; var highlight = this.getQuery()[Query.HIGHLIGHT] || ""; - var intercept = this.props.settings.intercept || ""; + var intercept = this.state.settings.intercept || ""; return ( <div> @@ -214,7 +214,7 @@ var ViewMenu = React.createClass({ title: "View", route: "flows" }, - mixins: [common.Navigation, common.State], + mixins: [common.Navigation, common.RouterState], toggleEventLog: function () { var d = {}; @@ -379,7 +379,7 @@ var Header = React.createClass({ {header} </nav> <div className="menu"> - <this.state.active settings={this.props.settings}/> + <this.state.active/> </div> </header> ); @@ -389,4 +389,4 @@ var Header = React.createClass({ module.exports = { Header: Header -}
\ No newline at end of file +};
\ No newline at end of file diff --git a/web/src/js/components/mainview.js b/web/src/js/components/mainview.js index 9790a69e..54687373 100644 --- a/web/src/js/components/mainview.js +++ b/web/src/js/components/mainview.js @@ -10,22 +10,40 @@ FlowTable = require("./flowtable.js"); var FlowView = require("./flowview/index.js"); var MainView = React.createClass({ - mixins: [common.Navigation, common.State], + mixins: [common.Navigation, common.RouterState], + contextTypes: { + flowStore: React.PropTypes.object.isRequired, + }, childContextTypes: { - returnFocus: React.PropTypes.func.isRequired + returnFocus: React.PropTypes.func.isRequired, + view: React.PropTypes.object.isRequired, }, - getChildContext: function() { - return { returnFocus: this.returnFocus }; + getChildContext: function () { + return { + returnFocus: this.returnFocus, + view: this.state.view + }; }, - returnFocus: function(){ + returnFocus: function () { this.getDOMNode().focus(); }, getInitialState: function () { + var sortKeyFun = false; + var view = new views.StoreView(this.context.flowStore, this.getViewFilt(), sortKeyFun); + view.addListener("recalculate", this.onRecalculate); + view.addListener("add", this.onUpdate); + view.addListener("update", this.onUpdate); + view.addListener("remove", this.onUpdate); + view.addListener("remove", this.onRemove); + return { - flows: [], - sortKeyFun: false + view: view, + sortKeyFun: sortKeyFun }; }, + componentWillUnmount: function () { + this.state.view.close(); + }, getViewFilt: function () { try { var filt = Filt.parse(this.getQuery()[Query.FILTER] || ""); @@ -44,29 +62,12 @@ var MainView = React.createClass({ }; }, componentWillReceiveProps: function (nextProps) { - if (nextProps.flowStore !== this.props.flowStore) { - this.closeView(); - this.openView(nextProps.flowStore); - } - var filterChanged = (this.props.query[Query.FILTER] !== nextProps.query[Query.FILTER]); var highlightChanged = (this.props.query[Query.HIGHLIGHT] !== nextProps.query[Query.HIGHLIGHT]); if (filterChanged || highlightChanged) { this.state.view.recalculate(this.getViewFilt(), this.state.sortKeyFun); } }, - openView: function (store) { - var view = new views.StoreView(store, this.getViewFilt(), this.state.sortKeyFun); - this.setState({ - view: view - }); - - view.addListener("recalculate", this.onRecalculate); - view.addListener("add", this.onUpdate); - view.addListener("update", this.onUpdate); - view.addListener("remove", this.onUpdate); - view.addListener("remove", this.onRemove); - }, onRecalculate: function () { this.forceUpdate(); var selected = this.getSelected(); @@ -85,16 +86,7 @@ var MainView = React.createClass({ this.selectFlow(flow_to_select); } }, - closeView: function () { - this.state.view.close(); - }, - componentWillMount: function () { - this.openView(this.props.flowStore); - }, - componentWillUnmount: function () { - this.closeView(); - }, - setSortKeyFun: function(sortKeyFun){ + setSortKeyFun: function (sortKeyFun) { this.setState({ sortKeyFun: sortKeyFun }); @@ -221,7 +213,7 @@ var MainView = React.createClass({ e.preventDefault(); }, getSelected: function () { - return this.props.flowStore.get(this.getParams().flowId); + return this.context.flowStore.get(this.getParams().flowId); }, render: function () { var selected = this.getSelected(); @@ -239,7 +231,6 @@ var MainView = React.createClass({ return ( <div className="main-view" onKeyDown={this.onKeyDown} tabIndex="0"> <FlowTable ref="flowTable" - view={this.state.view} selectFlow={this.selectFlow} setSortKeyFun={this.setSortKeyFun} selected={selected} /> diff --git a/web/src/js/components/proxyapp.js b/web/src/js/components/proxyapp.js index 863a9f53..411e1be8 100644 --- a/web/src/js/components/proxyapp.js +++ b/web/src/js/components/proxyapp.js @@ -20,52 +20,48 @@ var Reports = React.createClass({ var ProxyAppMain = React.createClass({ - mixins: [common.State], + mixins: [common.RouterState], + childContextTypes: { + settingsStore: React.PropTypes.object.isRequired, + flowStore: React.PropTypes.object.isRequired, + eventStore: React.PropTypes.object.isRequired + }, + getChildContext: function () { + return { + settingsStore: this.state.settingsStore, + flowStore: this.state.flowStore, + eventStore: this.state.eventStore + }; + }, getInitialState: function () { var eventStore = new store.EventLogStore(); var flowStore = new store.FlowStore(); - var settings = new store.SettingsStore(); + var settingsStore = new store.SettingsStore(); // Default Settings before fetch - _.extend(settings.dict,{ - }); + _.extend(settingsStore.dict, {}); return { - settings: settings, + settingsStore: settingsStore, flowStore: flowStore, eventStore: eventStore }; }, - componentDidMount: function () { - this.state.settings.addListener("recalculate", this.onSettingsChange); - window.app = this; - }, - componentWillUnmount: function () { - this.state.settings.removeListener("recalculate", this.onSettingsChange); - }, - onSettingsChange: function(){ - this.setState({ - settings: this.state.settings - }); - }, render: function () { var eventlog; if (this.getQuery()[Query.SHOW_EVENTLOG]) { eventlog = [ <common.Splitter key="splitter" axis="y"/>, - <EventLog key="eventlog" eventStore={this.state.eventStore}/> + <EventLog key="eventlog"/> ]; } else { eventlog = null; } return ( <div id="container"> - <header.Header settings={this.state.settings.dict}/> - <RouteHandler - settings={this.state.settings.dict} - flowStore={this.state.flowStore} - query={this.getQuery()}/> + <header.Header/> + <RouteHandler query={this.getQuery()}/> {eventlog} - <Footer settings={this.state.settings.dict}/> + <Footer/> </div> ); } diff --git a/web/src/js/store/view.js b/web/src/js/store/view.js index d13822d5..d628d46b 100644 --- a/web/src/js/store/view.js +++ b/web/src/js/store/view.js @@ -35,6 +35,7 @@ _.extend(StoreView.prototype, EventEmitter.prototype, { this.store.removeListener("update", this.update); this.store.removeListener("remove", this.remove); this.store.removeListener("recalculate", this.recalculate); + this.removeAllListeners(); }, recalculate: function (filt, sortfun) { filt = filt || this.filt || default_filt; |