import React, {PureComponent, PropTypes} from 'react'; 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/MethodDropdown'; import PromptModal from './modals/PromptModal'; import PromptButton from './base/PromptButton'; import OneLineEditor from './codemirror/OneLineEditor'; class RequestUrlBar extends PureComponent { state = { currentInterval: null, currentTimeout: null, downloadPath: null }; _urlChangeDebounceTimeout = null; _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 () => { // If no pasted text in the queue, just fire the regular change handler if (!pastedText) { this.props.onUrlChange(url); } // Reset pasted text cache const pastedText = this._lastPastedText; 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(importedRequest.url); } else { 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.select(); } }; _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(); } }; _handleSendAfterDelay = async () => { 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); }; _handleSendOnInterval = async () => { 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'); } }; _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); } 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} = this.props; return (
{method}
{this.renderSendButton()}
); } } RequestUrlBar.propTypes = { handleSend: PropTypes.func.isRequired, handleSendAndDownload: PropTypes.func.isRequired, handleRender: PropTypes.func.isRequired, handleImport: PropTypes.func.isRequired, onUrlChange: PropTypes.func.isRequired, onMethodChange: PropTypes.func.isRequired, handleGenerateCode: PropTypes.func.isRequired, url: PropTypes.string.isRequired, method: PropTypes.string.isRequired }; export default RequestUrlBar;