aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js/components/flowview
diff options
context:
space:
mode:
authorMaximilian Hils <git@maximilianhils.com>2015-03-30 03:49:50 +0200
committerMaximilian Hils <git@maximilianhils.com>2015-03-30 03:49:50 +0200
commit6d29f93e9eaaabe20c0d46887048f2367bfbb3cf (patch)
tree0b3be8ff99d7b986596ca69e67b3e7fe885d4764 /web/src/js/components/flowview
parent737002921e9aed701afb49fda8777e8c9286bf09 (diff)
downloadmitmproxy-6d29f93e9eaaabe20c0d46887048f2367bfbb3cf.tar.gz
mitmproxy-6d29f93e9eaaabe20c0d46887048f2367bfbb3cf.tar.bz2
mitmproxy-6d29f93e9eaaabe20c0d46887048f2367bfbb3cf.zip
web: add prompt for keyboard navigation
Diffstat (limited to 'web/src/js/components/flowview')
-rw-r--r--web/src/js/components/flowview/index.js59
-rw-r--r--web/src/js/components/flowview/messages.js74
2 files changed, 115 insertions, 18 deletions
diff --git a/web/src/js/components/flowview/index.js b/web/src/js/components/flowview/index.js
index 4214714e..739a46dc 100644
--- a/web/src/js/components/flowview/index.js
+++ b/web/src/js/components/flowview/index.js
@@ -5,6 +5,8 @@ var common = require("../common.js");
var Nav = require("./nav.js");
var Messages = require("./messages.js");
var Details = require("./details.js");
+var Prompt = require("../prompt.js");
+
var allTabs = {
request: Messages.Request,
@@ -15,6 +17,11 @@ var allTabs = {
var FlowView = React.createClass({
mixins: [common.StickyHeadMixin, common.Navigation, common.RouterState],
+ getInitialState: function () {
+ return {
+ prompt: false
+ };
+ },
getTabs: function (flow) {
var tabs = [];
["request", "response", "error"].forEach(function (e) {
@@ -27,7 +34,7 @@ var FlowView = React.createClass({
},
nextTab: function (i) {
var tabs = this.getTabs(this.props.flow);
- var currentIndex = tabs.indexOf(this.getParams().detailTab);
+ var currentIndex = tabs.indexOf(this.getActive());
// JS modulo operator doesn't correct negative numbers, make sure that we are positive.
var nextIndex = (currentIndex + i + tabs.length) % tabs.length;
this.selectTab(tabs[nextIndex]);
@@ -41,10 +48,50 @@ var FlowView = React.createClass({
}
);
},
+ getActive: function(){
+ return this.getParams().detailTab;
+ },
+ promptEdit: function () {
+ var options;
+ switch(this.getActive()){
+ case "request":
+ options = [
+ "method",
+ "url",
+ {text:"http version", key:"v"},
+ "header"
+ /*, "content"*/];
+ break;
+ case "response":
+ options = [
+ {text:"http version", key:"v"},
+ "code",
+ "message",
+ "header"
+ /*, "content"*/];
+ break;
+ case "details":
+ return;
+ default:
+ throw "Unknown tab for edit: " + this.getActive();
+ }
+
+ this.setState({
+ prompt: {
+ done: function (k) {
+ this.setState({prompt: false});
+ if(k){
+ this.refs.tab.edit(k);
+ }
+ }.bind(this),
+ options: options
+ }
+ });
+ },
render: function () {
var flow = this.props.flow;
var tabs = this.getTabs(flow);
- var active = this.getParams().detailTab;
+ var active = this.getActive();
if (!_.contains(tabs, active)) {
if (active === "response" && flow.error) {
@@ -57,6 +104,11 @@ var FlowView = React.createClass({
this.selectTab(active);
}
+ var prompt = null;
+ if (this.state.prompt) {
+ prompt = <Prompt {...this.state.prompt}/>;
+ }
+
var Tab = allTabs[active];
return (
<div className="flow-detail" onScroll={this.adjustHead}>
@@ -65,7 +117,8 @@ var FlowView = React.createClass({
tabs={tabs}
active={active}
selectTab={this.selectTab}/>
- <Tab flow={flow}/>
+ <Tab ref="tab" flow={flow}/>
+ {prompt}
</div>
);
}
diff --git a/web/src/js/components/flowview/messages.js b/web/src/js/components/flowview/messages.js
index 7feaa634..cb166026 100644
--- a/web/src/js/components/flowview/messages.js
+++ b/web/src/js/components/flowview/messages.js
@@ -23,13 +23,16 @@ var Headers = React.createClass({
} else {
nextHeaders.splice(row, 1);
// manually move selection target if this has been the last row.
- if(row === nextHeaders.length){
- this._nextSel = (row-1)+"-value";
+ if (row === nextHeaders.length) {
+ this._nextSel = (row - 1) + "-value";
}
}
}
this.props.onChange(nextHeaders);
},
+ edit: function () {
+ this.refs["0-key"].focus();
+ },
onTab: function (row, col, e) {
var headers = this.props.message.headers;
if (row === headers.length - 1 && col === 1) {
@@ -138,9 +141,11 @@ var InlineInput = React.createClass({
},
blur: function () {
this.getDOMNode().blur();
+ window.getSelection().removeAllRanges();
this.context.returnFocus && this.context.returnFocus();
},
- selectContents: function () {
+ focus: function () {
+ React.findDOMNode(this).focus();
var range = document.createRange();
range.selectNodeContents(this.getDOMNode());
var sel = window.getSelection();
@@ -148,7 +153,7 @@ var InlineInput = React.createClass({
sel.addRange(range);
},
onFocus: function () {
- this.setState({editable: true}, this.selectContents);
+ this.setState({editable: true}, this.focus);
},
onBlur: function (e) {
this.setState({editable: false});
@@ -182,7 +187,7 @@ var HeaderInlineInput = React.createClass({
}
break;
case utils.Key.TAB:
- if(!e.shiftKey){
+ if (!e.shiftKey) {
this.props.onTab(e);
}
break;
@@ -202,6 +207,9 @@ var ValidateInlineInput = React.createClass({
originalContent: this.props.content
};
},
+ focus: function () {
+ this.getDOMNode().focus();
+ },
onChange: function (val) {
this.setState({
content: val
@@ -253,11 +261,11 @@ var RequestLine = React.createClass({
var httpver = "HTTP/" + flow.request.httpversion.join(".");
return <div className="first-line request-line">
- <InlineInput content={flow.request.method} onChange={this.onMethodChange}/>
+ <InlineInput ref="method" content={flow.request.method} onChange={this.onMethodChange}/>
&nbsp;
- <ValidateInlineInput content={url} onChange={this.onUrlChange} isValid={this.isValidUrl} />
+ <ValidateInlineInput ref="url" content={url} onChange={this.onUrlChange} isValid={this.isValidUrl} />
&nbsp;
- <ValidateInlineInput immediate content={httpver} onChange={this.onHttpVersionChange} isValid={flowutils.isValidHttpVersion} />
+ <ValidateInlineInput ref="httpVersion" immediate content={httpver} onChange={this.onHttpVersionChange} isValid={flowutils.isValidHttpVersion} />
</div>
},
isValidUrl: function (url) {
@@ -292,11 +300,11 @@ var ResponseLine = React.createClass({
var flow = this.props.flow;
var httpver = "HTTP/" + flow.response.httpversion.join(".");
return <div className="first-line response-line">
- <ValidateInlineInput immediate content={httpver} onChange={this.onHttpVersionChange} isValid={flowutils.isValidHttpVersion} />
+ <ValidateInlineInput ref="httpVersion" immediate content={httpver} onChange={this.onHttpVersionChange} isValid={flowutils.isValidHttpVersion} />
&nbsp;
- <ValidateInlineInput immediate content={flow.response.code + ""} onChange={this.onCodeChange} isValid={this.isValidCode} />
+ <ValidateInlineInput ref="code" immediate content={flow.response.code + ""} onChange={this.onCodeChange} isValid={this.isValidCode} />
&nbsp;
- <InlineInput content={flow.response.msg} onChange={this.onMsgChange}/>
+ <InlineInput ref="msg" content={flow.response.msg} onChange={this.onMsgChange}/>
</div>;
},
@@ -330,14 +338,32 @@ var Request = React.createClass({
var flow = this.props.flow;
return (
<section className="request">
- <RequestLine flow={flow}/>
+ <RequestLine ref="requestLine" flow={flow}/>
{/*<ResponseLine flow={flow}/>*/}
- <Headers message={flow.request} onChange={this.onHeaderChange}/>
+ <Headers ref="headers" message={flow.request} onChange={this.onHeaderChange}/>
<hr/>
<ContentView flow={flow} message={flow.request}/>
</section>
);
},
+ edit: function (k) {
+ switch (k) {
+ case "m":
+ this.refs.requestLine.refs.method.focus();
+ break;
+ case "u":
+ this.refs.requestLine.refs.url.focus();
+ break;
+ case "v":
+ this.refs.requestLine.refs.httpVersion.focus();
+ break;
+ case "h":
+ this.refs.headers.edit();
+ break;
+ default:
+ throw "Unimplemented: "+ k;
+ }
+ },
onHeaderChange: function (nextHeaders) {
actions.FlowActions.update(this.props.flow, {
request: {
@@ -353,13 +379,31 @@ var Response = React.createClass({
return (
<section className="response">
{/*<RequestLine flow={flow}/>*/}
- <ResponseLine flow={flow}/>
- <Headers message={flow.response} onChange={this.onHeaderChange}/>
+ <ResponseLine ref="responseLine" flow={flow}/>
+ <Headers ref="headers" message={flow.response} onChange={this.onHeaderChange}/>
<hr/>
<ContentView flow={flow} message={flow.response}/>
</section>
);
},
+ edit: function (k) {
+ switch (k) {
+ case "c":
+ this.refs.responseLine.refs.code.focus();
+ break;
+ case "m":
+ this.refs.responseLine.refs.msg.focus();
+ break;
+ case "v":
+ this.refs.responseLine.refs.httpVersion.focus();
+ break;
+ case "h":
+ this.refs.headers.edit();
+ break;
+ default:
+ throw "Unimplemented: "+ k;
+ }
+ },
onHeaderChange: function (nextHeaders) {
actions.FlowActions.update(this.props.flow, {
response: {