aboutsummaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2015-03-27 21:58:04 +0100
committerMaximilian Hils <git@maximilianhils.com>2015-03-27 21:58:04 +0100
commit1913975fa60c76bfb7e79a908b18e7e93793f71f (patch)
tree54a4ea1605e2d8219d2983d2181ce4b27168ed49 /web
parentf39e6c5c18890de902d061226ba413254114c8ad (diff)
downloadmitmproxy-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.js55
-rw-r--r--web/src/js/components/eventlog.js43
-rw-r--r--web/src/js/components/flowtable.js42
-rw-r--r--web/src/js/components/flowview/index.js2
-rw-r--r--web/src/js/components/footer.js6
-rw-r--r--web/src/js/components/header.js10
-rw-r--r--web/src/js/components/mainview.js63
-rw-r--r--web/src/js/components/proxyapp.js44
-rw-r--r--web/src/js/store/view.js1
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;