aboutsummaryrefslogtreecommitdiffstats
path: root/web/src/js/components/ProxyApp.js
blob: 71a7bf9b43315fea7d597dedb167809f8c3e1dc8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
import React, { Component, PropTypes } from "react"
import ReactDOM from "react-dom"
import _ from "lodash"
import { connect } from 'react-redux'

import { Splitter } from "./common.js"
import { Header, MainMenu } from "./header.js"
import EventLog from "./eventlog.js"
import Footer from "./footer.js"
import { SettingsStore } from "../store/store.js"
import { Key } from "../utils.js"

class ProxyAppMain extends Component {

    static childContextTypes = {
        returnFocus: PropTypes.func.isRequired,
        location: PropTypes.object.isRequired,
    }

    static contextTypes = {
        router: PropTypes.object.isRequired,
    }

    constructor(props, context) {
        super(props, context)

        this.settingsStore = new SettingsStore()

        // Default Settings before fetch
        _.extend(this.settingsStore.dict, {})

        this.state = { settings: this.settingsStore.dict }

        this.onKeyDown = this.onKeyDown.bind(this)
        this.updateLocation = this.updateLocation.bind(this)
        this.onSettingsChange = this.onSettingsChange.bind(this)
    }

    /**
     * @todo move to actions
     */
    updateLocation(pathname, queryUpdate) {
        if (pathname === undefined) {
            pathname = this.props.location.pathname
        }
        const query = this.props.location.query
        for (const key of Object.keys(queryUpdate || {})) {
            query[i] = queryUpdate[i] || undefined
        }
        this.context.router.replace({ pathname, query })
    }

    /**
     * @todo pass in with props
     */
    getQuery() {
        // 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.props.location.query)
    }

    /**
     * @todo remove settings store
     * @todo connect websocket here
     * @todo listen to window's key events
     */
    componentDidMount() {
        this.focus()
        this.settingsStore.addListener("recalculate", this.onSettingsChange)
    }

    /**
     * @todo remove settings store
     * @todo disconnect websocket here
     * @todo stop listening to window's key events
     */
    componentWillUnmount() {
        this.settingsStore.removeListener("recalculate", this.onSettingsChange)
    }

    /**
     * @todo move to actions
     */
    onSettingsChange() {
        this.setState({ settings: this.settingsStore.dict })
    }

    /**
     * @todo use props
     */
    getChildContext() {
        return {
            returnFocus: this.focus,
            location: this.props.location
        }
    }

    /**
     * @todo remove it
     */
    focus() {
        document.activeElement.blur()
        window.getSelection().removeAllRanges()
        ReactDOM.findDOMNode(this).focus()
    }

    /**
     * @todo move to actions
     */
    onKeyDown(e) {
        let name = null

        switch (e.keyCode) {
            case Key.I:
                name = "intercept"
                break
            case Key.L:
                name = "search"
                break
            case Key.H:
                name = "highlight"
                break
            default:
                let main = this.refs.view
                if (this.refs.view.getWrappedInstance) {
                    main = this.refs.view.getWrappedInstance()
                }
                if (main.onMainKeyDown) {
                    main.onMainKeyDown(e)
                }
                return // don't prevent default then
        }

        if (name) {
            const headerComponent = this.refs.header
            headerComponent.setState({active: MainMenu}, function () {
                headerComponent.refs.active.refs[name].select()
            })
        }

        e.preventDefault()
    }

    render() {
        const { showEventLog, location, children } = this.props
        const { settings } = this.state
        const query = this.getQuery()
        return (
            <div id="container" tabIndex="0" onKeyDown={this.onKeyDown}>
                <Header ref="header" settings={settings} updateLocation={this.updateLocation} query={query} />
                {React.cloneElement(
                    children,
                    { ref: "view", location, query, updateLocation: this.updateLocation }
                )}
                {showEventLog && [
                    <Splitter key="splitter" axis="y"/>,
                    <EventLog key="eventlog"/>
                ]}
                <Footer settings={settings}/>
            </div>
        )
    }
}

export default connect(
    state => ({
        showEventLog: state.eventLog.visible
    })
)(ProxyAppMain)