import React, {PureComponent, PropTypes} from 'react'; import autobind from 'autobind-decorator'; import {remote} from 'electron'; import {DEBOUNCE_MILLIS, isMac} from '../../common/constants'; import {Dropdown, DropdownButton, DropdownItem, DropdownDivider, DropdownHint} from './base/dropdown'; import {trackEvent} from '../../analytics'; import {showModal} from './modals/index'; import MethodDropdown from './dropdowns/method-dropdown'; import PromptModal from './modals/prompt-modal'; import PromptButton from './base/prompt-button'; import OneLineEditor from './codemirror/one-line-editor'; @autobind class RequestUrlBar extends PureComponent { constructor (props) { super(props); this.state = { currentInterval: null, currentTimeout: null, downloadPath: null }; this._urlChangeDebounceTimeout = null; this._lastPastedText = null; } _setDropdownRef (n) { this._dropdown = n; } _setInputRef (n) { this._input = n; } _handleMetaClickSend (e) { e.preventDefault(); this._dropdown.show(); } _handleFormSubmit (e) { e.preventDefault(); e.stopPropagation(); this._handleSend(); } _handleMethodChange (method) { this.props.onMethodChange(method); trackEvent('Request', 'Method Change', method); } _handleUrlChange (url) { clearTimeout(this._urlChangeDebounceTimeout); this._urlChangeDebounceTimeout = setTimeout(async () => { const pastedText = this._lastPastedText; // If no pasted text in the queue, just fire the regular change handler if (!pastedText) { this.props.onUrlChange(url); return; } // Reset pasted text cache this._lastPastedText = null; // Attempt to import the pasted text const importedRequest = await this.props.handleImport(pastedText); // Update depending on whether something was imported if (!importedRequest) { this.props.onUrlChange(url); } }, DEBOUNCE_MILLIS); } _handleUrlPaste (e) { // NOTE: We're not actually doing the import here to avoid races with onChange this._lastPastedText = e.clipboardData.getData('text/plain'); } _handleGenerateCode () { this.props.handleGenerateCode(); trackEvent('Request', 'Generate Code', 'Send Action'); } _handleSetDownloadLocation () { const options = { title: 'Select Download Location', buttonLabel: 'Select', properties: ['openDirectory'] }; remote.dialog.showOpenDialog(options, paths => { if (!paths || paths.length === 0) { trackEvent('Response', 'Download Select Cancel'); return; } this.setState({downloadPath: paths[0]}); }); } _handleClearDownloadLocation () { this.setState({downloadPath: null}); } _handleKeyDown (e) { if (!this._input) { return; } // meta+l const metaPressed = isMac() ? e.metaKey : e.ctrlKey; if (metaPressed && e.keyCode === 76) { e.preventDefault(); this._input.focus(); this._input.selectAll(); } } _handleSend () { // Don't stop interval because duh, it needs to keep going! // XXX this._handleStopInterval(); XXX this._handleStopTimeout(); const {downloadPath} = this.state; if (downloadPath) { this.props.handleSendAndDownload(downloadPath); } else { this.props.handleSend(); } } async _handleSendAfterDelay () { const seconds = await showModal(PromptModal, { inputType: 'decimal', headerName: 'Send After Delay', label: 'Delay in seconds', defaultValue: 3, submitName: 'Start' }); this._handleStopTimeout(); this._sendTimeout = setTimeout(this._handleSend, seconds * 1000); this.setState({currentTimeout: seconds}); trackEvent('Request', 'Send on Delay', 'Send Action', seconds); } async _handleSendOnInterval () { const seconds = await showModal(PromptModal, { inputType: 'decimal', headerName: 'Send on Interval', label: 'Interval in seconds', defaultValue: 3, submitName: 'Start' }); this._handleStopInterval(); this._sendInterval = setInterval(this._handleSend, seconds * 1000); this.setState({currentInterval: seconds}); trackEvent('Request', 'Send on Interval', 'Send Action', seconds); } _handleStopInterval () { clearTimeout(this._sendInterval); if (this.state.currentInterval) { this.setState({currentInterval: null}); trackEvent('Request', 'Stop Send Interval'); } } _handleStopTimeout () { clearTimeout(this._sendTimeout); if (this.state.currentTimeout) { this.setState({currentTimeout: null}); trackEvent('Request', 'Stop Send Timeout'); } } _handleResetTimeouts () { this._handleStopTimeout(); this._handleStopInterval(); } _handleClickSend (e) { const metaPressed = isMac() ? e.metaKey : e.ctrlKey; // If we're pressing a meta key, let the dropdown open if (metaPressed) { e.preventDefault(); // Don't submit the form return; } // If we're not pressing a meta key, cancel dropdown and send the request e.stopPropagation(); // Don't trigger the dropdown this._handleFormSubmit(e); } componentDidMount () { document.body.addEventListener('keydown', this._handleKeyDown); } componentWillUnmount () { document.body.removeEventListener('keydown', this._handleKeyDown); } componentWillReceiveProps (nextProps) { if (nextProps.requestId !== this.props.requestId) { this._handleResetTimeouts(); } } renderSendButton () { const {currentInterval, currentTimeout, downloadPath} = this.state; let cancelButton = null; if (currentInterval) { cancelButton = ( ); } else if (currentTimeout) { cancelButton = ( ); } let sendButton; if (!cancelButton) { sendButton = ( {downloadPath ? 'Download' : 'Send'} Basic Send Now Generate Client Code Advanced Send After Delay Repeat on Interval {downloadPath ? ( Stop Auto-Download ) : ( Download After Send )} ); } return [ cancelButton, sendButton ]; } render () { const { url, method, handleRender, handleGetRenderContext, handleAutocompleteUrls, uniquenessKey } = this.props; return (
{method}
{this.renderSendButton()}
); } } RequestUrlBar.propTypes = { handleSend: PropTypes.func.isRequired, handleSendAndDownload: PropTypes.func.isRequired, handleRender: PropTypes.func.isRequired, handleGetRenderContext: PropTypes.func.isRequired, handleImport: PropTypes.func.isRequired, handleAutocompleteUrls: PropTypes.func.isRequired, onUrlChange: PropTypes.func.isRequired, onMethodChange: PropTypes.func.isRequired, handleGenerateCode: PropTypes.func.isRequired, url: PropTypes.string.isRequired, method: PropTypes.string.isRequired, requestId: PropTypes.string.isRequired, uniquenessKey: PropTypes.string.isRequired }; export default RequestUrlBar;