From 18b619e164ced91cf0ac8d3fd3c18be1f07df1cc Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Thu, 18 Feb 2016 12:29:35 +0100 Subject: move mitmproxy/web to root --- web/src/js/components/header.js | 399 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 399 insertions(+) create mode 100644 web/src/js/components/header.js (limited to 'web/src/js/components/header.js') diff --git a/web/src/js/components/header.js b/web/src/js/components/header.js new file mode 100644 index 00000000..998a41df --- /dev/null +++ b/web/src/js/components/header.js @@ -0,0 +1,399 @@ +var React = require("react"); +var $ = require("jquery"); + +var Filt = require("../filt/filt.js"); +var utils = require("../utils.js"); +var common = require("./common.js"); +var actions = require("../actions.js"); +var Query = require("../actions.js").Query; + +var FilterDocs = React.createClass({ + statics: { + xhr: false, + doc: false + }, + componentWillMount: function () { + if (!FilterDocs.doc) { + FilterDocs.xhr = $.getJSON("/filter-help").done(function (doc) { + FilterDocs.doc = doc; + FilterDocs.xhr = false; + }); + } + if (FilterDocs.xhr) { + FilterDocs.xhr.done(function () { + this.forceUpdate(); + }.bind(this)); + } + }, + render: function () { + if (!FilterDocs.doc) { + return ; + } else { + var commands = FilterDocs.doc.commands.map(function (c) { + return + {c[0].replace(" ", '\u00a0')} + {c[1]} + ; + }); + commands.push( + + + +   mitmproxy docs + + ); + return + {commands} +
; + } + } +}); +var FilterInput = React.createClass({ + mixins: [common.ChildFocus], + getInitialState: function () { + // Consider both focus and mouseover for showing/hiding the tooltip, + // because onBlur of the input is triggered before the click on the tooltip + // finalized, hiding the tooltip just as the user clicks on it. + return { + value: this.props.value, + focus: false, + mousefocus: false + }; + }, + componentWillReceiveProps: function (nextProps) { + this.setState({value: nextProps.value}); + }, + onChange: function (e) { + var nextValue = e.target.value; + this.setState({ + value: nextValue + }); + // Only propagate valid filters upwards. + if (this.isValid(nextValue)) { + this.props.onChange(nextValue); + } + }, + isValid: function (filt) { + try { + Filt.parse(filt || this.state.value); + return true; + } catch (e) { + return false; + } + }, + getDesc: function () { + var desc; + try { + desc = Filt.parse(this.state.value).desc; + } catch (e) { + desc = "" + e; + } + if (desc !== "true") { + return desc; + } else { + return ( + + ); + } + }, + onFocus: function () { + this.setState({focus: true}); + }, + onBlur: function () { + this.setState({focus: false}); + }, + onMouseEnter: function () { + this.setState({mousefocus: true}); + }, + onMouseLeave: function () { + this.setState({mousefocus: false}); + }, + onKeyDown: function (e) { + if (e.keyCode === utils.Key.ESC || e.keyCode === utils.Key.ENTER) { + this.blur(); + // If closed using ESC/ENTER, hide the tooltip. + this.setState({mousefocus: false}); + } + e.stopPropagation(); + }, + blur: function () { + this.refs.input.getDOMNode().blur(); + this.returnFocus(); + }, + select: function () { + this.refs.input.getDOMNode().select(); + }, + render: function () { + var isValid = this.isValid(); + var icon = "fa fa-fw fa-" + this.props.type; + var groupClassName = "filter-input input-group" + (isValid ? "" : " has-error"); + + var popover; + if (this.state.focus || this.state.mousefocus) { + popover = ( +
+
+
+ {this.getDesc()} +
+
+ ); + } + + return ( +
+ + + + + {popover} +
+ ); + } +}); + +var MainMenu = React.createClass({ + mixins: [common.Navigation, common.RouterState, common.SettingsState], + statics: { + title: "Start", + route: "flows" + }, + onSearchChange: function (val) { + var d = {}; + d[Query.SEARCH] = val; + this.setQuery(d); + }, + onHighlightChange: function (val) { + var d = {}; + d[Query.HIGHLIGHT] = val; + this.setQuery(d); + }, + onInterceptChange: function (val) { + actions.SettingsActions.update({intercept: val}); + }, + render: function () { + var search = this.getQuery()[Query.SEARCH] || ""; + var highlight = this.getQuery()[Query.HIGHLIGHT] || ""; + var intercept = this.state.settings.intercept || ""; + + return ( +
+
+ + + +
+
+
+ ); + } +}); + + +var ViewMenu = React.createClass({ + statics: { + title: "View", + route: "flows" + }, + mixins: [common.Navigation, common.RouterState], + toggleEventLog: function () { + var d = {}; + + if (this.getQuery()[Query.SHOW_EVENTLOG]) { + d[Query.SHOW_EVENTLOG] = undefined; + } else { + d[Query.SHOW_EVENTLOG] = "t"; // any non-false value will do it, keep it short + } + + this.setQuery(d); + }, + render: function () { + var showEventLog = this.getQuery()[Query.SHOW_EVENTLOG]; + return ( +
+ + +
+ ); + } +}); + + +var ReportsMenu = React.createClass({ + statics: { + title: "Visualization", + route: "reports" + }, + render: function () { + return
Reports Menu
; + } +}); + +var FileMenu = React.createClass({ + getInitialState: function () { + return { + showFileMenu: false + }; + }, + handleFileClick: function (e) { + e.preventDefault(); + if (!this.state.showFileMenu) { + var close = function () { + this.setState({showFileMenu: false}); + document.removeEventListener("click", close); + }.bind(this); + document.addEventListener("click", close); + + this.setState({ + showFileMenu: true + }); + } + }, + handleNewClick: function (e) { + e.preventDefault(); + if (confirm("Delete all flows?")) { + actions.FlowActions.clear(); + } + }, + handleOpenClick: function (e) { + e.preventDefault(); + console.error("unimplemented: handleOpenClick"); + }, + handleSaveClick: function (e) { + e.preventDefault(); + console.error("unimplemented: handleSaveClick"); + }, + handleShutdownClick: function (e) { + e.preventDefault(); + console.error("unimplemented: handleShutdownClick"); + }, + render: function () { + var fileMenuClass = "dropdown pull-left" + (this.state.showFileMenu ? " open" : ""); + + return ( +
+ mitmproxy + +
+ ); + } +}); + + +var header_entries = [MainMenu, ViewMenu /*, ReportsMenu */]; + + +var Header = React.createClass({ + mixins: [common.Navigation], + getInitialState: function () { + return { + active: header_entries[0] + }; + }, + handleClick: function (active, e) { + e.preventDefault(); + this.replaceWith(active.route); + this.setState({active: active}); + }, + render: function () { + var header = header_entries.map(function (entry, i) { + var className; + if (entry === this.state.active) { + className = "active"; + } else { + className = ""; + } + return ( + + { entry.title} + + ); + }.bind(this)); + + return ( +
+ +
+ +
+
+ ); + } +}); + + +module.exports = { + Header: Header, + MainMenu: MainMenu +}; \ No newline at end of file -- cgit v1.2.3