mirror of
https://github.com/Kong/insomnia.git
synced 2026-05-19 14:23:03 -04:00
Fixed some editor bugs (#97)
* Fixed some editor bugs * Some fixes * Update index.js
This commit is contained in:
23
app/ui/components/base/Lazy.js
Normal file
23
app/ui/components/base/Lazy.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
|
||||
class Lazy extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = {show: false};
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
const delay = this.props.delay || 0;
|
||||
setTimeout(() => this.setState({show: true}), delay);
|
||||
}
|
||||
|
||||
render () {
|
||||
return this.state.show ? this.props.children : null;
|
||||
}
|
||||
}
|
||||
|
||||
Lazy.propTypes = {
|
||||
delay: PropTypes.number,
|
||||
};
|
||||
|
||||
export default Lazy;
|
||||
@@ -132,7 +132,11 @@ class Editor extends PureComponent {
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasFocus () {
|
||||
return this.codeMirror.hasFocus();
|
||||
if (this.codeMirror) {
|
||||
return this.codeMirror.hasFocus();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,7 +166,6 @@ class Editor extends PureComponent {
|
||||
}
|
||||
|
||||
const {value, debounceMillis: ms} = this.props;
|
||||
|
||||
this.codeMirror = CodeMirror.fromTextArea(textarea, BASE_CODEMIRROR_OPTIONS);
|
||||
|
||||
// Set default listeners
|
||||
@@ -183,11 +186,11 @@ class Editor extends PureComponent {
|
||||
});
|
||||
}
|
||||
|
||||
// Do this a bit later so we don't block the render process
|
||||
window.requestAnimationFrame(() => {
|
||||
// Set editor options
|
||||
this._codemirrorSetOptions();
|
||||
// Set editor options
|
||||
this._codemirrorSetOptions();
|
||||
|
||||
// Do this a bit later so we don't block the render process
|
||||
setTimeout(() => {
|
||||
// Actually set the value
|
||||
this._codemirrorSetValue(value || '');
|
||||
|
||||
@@ -198,15 +201,9 @@ class Editor extends PureComponent {
|
||||
|
||||
// Unset default cursor of [0, 0];
|
||||
this.codeMirror.setCursor({line: -1, ch: -1});
|
||||
});
|
||||
}, 10);
|
||||
};
|
||||
|
||||
_debounce (fn) {
|
||||
const {debounceMillis} = this.props;
|
||||
const ms = typeof debounceMillis === 'number' ? debounceMillis : DEBOUNCE_MILLIS;
|
||||
return misc.debounce(fn, ms);
|
||||
}
|
||||
|
||||
_isJSON (mode) {
|
||||
if (!mode) {
|
||||
return false;
|
||||
@@ -568,10 +565,12 @@ class Editor extends PureComponent {
|
||||
return (
|
||||
<div className={classes}>
|
||||
<div className="editor__container input" style={{fontSize: `${fontSize || 12}px`}}>
|
||||
<textarea ref={this._handleInitTextarea}
|
||||
defaultValue=" "
|
||||
readOnly={readOnly}
|
||||
autoComplete="off"/>
|
||||
<textarea
|
||||
ref={this._handleInitTextarea}
|
||||
style={{display: 'none'}}
|
||||
defaultValue=" "
|
||||
readOnly={readOnly}
|
||||
autoComplete="off"/>
|
||||
</div>
|
||||
{toolbar}
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,23 @@ class OneLineEditor extends PureComponent {
|
||||
this.props.onChange && this.props.onChange(value);
|
||||
};
|
||||
|
||||
_handleKeyDown = e => {
|
||||
// submit form if needed
|
||||
if (e.keyCode === 13) {
|
||||
let node = e.target;
|
||||
for (let i = 0; i < 20 && node; i++) {
|
||||
if (node.tagName === 'FORM') {
|
||||
node.dispatchEvent(new Event('submit'));
|
||||
break;
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
// Also call the original if there was one
|
||||
this.props.onKeyDown && this.props.onKeyDown(e);
|
||||
};
|
||||
|
||||
_setRef = n => this.editor = n;
|
||||
|
||||
render () {
|
||||
@@ -33,6 +50,7 @@ class OneLineEditor extends PureComponent {
|
||||
noMatchBrackets
|
||||
singleLine
|
||||
tabIndex={0}
|
||||
onKeyDown={this._handleKeyDown}
|
||||
onChange={this._handleChange}
|
||||
className="editor--single-line"
|
||||
value={defaultValue}
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, {PureComponent, PropTypes} from 'react';
|
||||
|
||||
import KeyValueEditor from '../keyvalueeditor/Editor';
|
||||
import Editor from '../codemirror/Editor';
|
||||
import Lazy from '../base/Lazy';
|
||||
import {trackEvent} from '../../../analytics/index';
|
||||
|
||||
class RequestHeadersEditor extends PureComponent {
|
||||
@@ -65,29 +66,31 @@ class RequestHeadersEditor extends PureComponent {
|
||||
const {bulk, headers, onChange, handleRender} = this.props;
|
||||
|
||||
return bulk ? (
|
||||
<div className="tall">
|
||||
<Editor
|
||||
onChange={this._handleBulkUpdate}
|
||||
value={this._getHeadersString()}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="pad-bottom scrollable-container">
|
||||
<div className="scrollable">
|
||||
<KeyValueEditor
|
||||
namePlaceholder="My-Header"
|
||||
valuePlaceholder="Value"
|
||||
pairs={headers}
|
||||
sortable={true}
|
||||
handleRender={handleRender}
|
||||
onToggleDisable={this._handleTrackToggle}
|
||||
onCreate={this._handleTrackCreate}
|
||||
onDelete={this._handleTrackDelete}
|
||||
onChange={onChange}
|
||||
<div className="tall">
|
||||
<Editor
|
||||
onChange={this._handleBulkUpdate}
|
||||
value={this._getHeadersString()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
) : (
|
||||
<div className="pad-bottom scrollable-container">
|
||||
<div className="scrollable">
|
||||
<Lazy>
|
||||
<KeyValueEditor
|
||||
namePlaceholder="My-Header"
|
||||
valuePlaceholder="Value"
|
||||
pairs={headers}
|
||||
sortable={true}
|
||||
handleRender={handleRender}
|
||||
onToggleDisable={this._handleTrackToggle}
|
||||
onCreate={this._handleTrackCreate}
|
||||
onDelete={this._handleTrackDelete}
|
||||
onChange={onChange}
|
||||
/>
|
||||
</Lazy>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import classnames from 'classnames';
|
||||
import {DEBOUNCE_MILLIS} from '../../../common/constants';
|
||||
import KeyValueEditorRow from './Row';
|
||||
import {generateId, nullFn} from '../../../common/misc';
|
||||
import * as misc from '../../../common/misc';
|
||||
|
||||
const NAME = 'name';
|
||||
const VALUE = 'value';
|
||||
@@ -17,7 +18,7 @@ class KeyValueEditor extends PureComponent {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
|
||||
this._focusedPair = null;
|
||||
this._focusedPairId = null;
|
||||
this._focusedField = NAME;
|
||||
this._rows = [];
|
||||
|
||||
@@ -70,12 +71,12 @@ class KeyValueEditor extends PureComponent {
|
||||
};
|
||||
|
||||
_handleFocusName = pair => {
|
||||
this._focusedPair = pair;
|
||||
this._setFocusedPair(pair);
|
||||
this._focusedField = NAME;
|
||||
};
|
||||
|
||||
_handleFocusValue = pair => {
|
||||
this._focusedPair = pair;
|
||||
this._setFocusedPair(pair);
|
||||
this._focusedField = VALUE;
|
||||
};
|
||||
|
||||
@@ -144,21 +145,27 @@ class KeyValueEditor extends PureComponent {
|
||||
...this.state.pairs.slice(position)
|
||||
];
|
||||
|
||||
this._focusedPair = pair;
|
||||
this._setFocusedPair(pair);
|
||||
this._onChange(pairs);
|
||||
|
||||
this.props.onCreate && this.props.onCreate();
|
||||
}
|
||||
|
||||
_deletePair (position, breakFocus = false) {
|
||||
if (this._focusedPair >= position) {
|
||||
this._focusedPair = breakFocus ? -1 : this._focusedPair - 1;
|
||||
const focusedPosition = this._getFocusedPairIndex();
|
||||
|
||||
if (focusedPosition >= position) {
|
||||
const newPosition = breakFocus ? -1 : focusedPosition - 1;
|
||||
this._setFocusedPair(this.state.pairs[newPosition]);
|
||||
}
|
||||
|
||||
const pair = this.state.pairs[position];
|
||||
this.props.onDelete && this.props.onDelete(pair);
|
||||
|
||||
const pairs = this.state.pairs.filter((_, i) => i !== position);
|
||||
const pairs = [
|
||||
...this.state.pairs.slice(0, position),
|
||||
...this.state.pairs.slice(position + 1),
|
||||
];
|
||||
|
||||
this._onChange(pairs);
|
||||
};
|
||||
@@ -170,8 +177,7 @@ class KeyValueEditor extends PureComponent {
|
||||
} else if (this._focusedField === VALUE) {
|
||||
this._focusedField = NAME;
|
||||
if (addIfValue) {
|
||||
const i = this._getPairIndex(this._focusedPair);
|
||||
this._addPair(i + 1);
|
||||
this._addPair(this._getFocusedPairIndex() + 1);
|
||||
} else {
|
||||
this._focusNextPair();
|
||||
}
|
||||
@@ -183,10 +189,10 @@ class KeyValueEditor extends PureComponent {
|
||||
this._focusedField = NAME;
|
||||
this._updateFocus();
|
||||
} else if (this._focusedField === NAME) {
|
||||
const p = this._focusedPair;
|
||||
const p = this._getFocusedPair();
|
||||
if (!p.name && !p.value && !p.fileName && deleteIfEmpty) {
|
||||
this._focusedField = VALUE;
|
||||
this._deletePair(this._focusedPair);
|
||||
this._deletePair(this._getFocusedPairIndex());
|
||||
} else if (!p.name) {
|
||||
this._focusedField = VALUE;
|
||||
this._focusPreviousPair();
|
||||
@@ -195,25 +201,32 @@ class KeyValueEditor extends PureComponent {
|
||||
}
|
||||
|
||||
_focusNextPair () {
|
||||
const i = this._getPairIndex(this._focusedPair);
|
||||
const i = this._getFocusedPairIndex();
|
||||
|
||||
if (i === -1) {
|
||||
// No focused pair currently
|
||||
return;
|
||||
}
|
||||
|
||||
if (i >= this.state.pairs.length - 1) {
|
||||
// Focused on last one, so add another
|
||||
this._addPair();
|
||||
} else {
|
||||
this._focusedPair = this.state.pairs[i + 1];
|
||||
this._setFocusedPair(this.state.pairs[i + 1]);
|
||||
this._updateFocus();
|
||||
}
|
||||
}
|
||||
|
||||
_focusPreviousPair () {
|
||||
const i = this._getPairIndex(this._focusedPair);
|
||||
const i = this._getFocusedPairIndex();
|
||||
if (i > 0) {
|
||||
this._focusedPair = this.state.pairs[i - 1];
|
||||
this._setFocusedPair(this.state.pairs[i - 1]);
|
||||
this._updateFocus();
|
||||
}
|
||||
}
|
||||
|
||||
_updateFocus () {
|
||||
const row = this._focusedPair && this._rows[this._focusedPair.id];
|
||||
const row = this._getFocusedPair() && this._rows[this._focusedPairId];
|
||||
|
||||
if (!row) {
|
||||
return;
|
||||
@@ -227,7 +240,27 @@ class KeyValueEditor extends PureComponent {
|
||||
}
|
||||
|
||||
_getPairIndex (pair) {
|
||||
return this.props.pairs.findIndex(p => p.id === pair.id);
|
||||
if (pair) {
|
||||
return this.props.pairs.findIndex(p => p.id === pair.id);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
_getFocusedPairIndex () {
|
||||
return this._getPairIndex(this._getFocusedPair());
|
||||
}
|
||||
|
||||
_getFocusedPair () {
|
||||
return this.props.pairs.find(p => p.id === this._focusedPairId) || null;
|
||||
}
|
||||
|
||||
_setFocusedPair (pair) {
|
||||
if (pair) {
|
||||
this._focusedPairId = pair.id;
|
||||
} else {
|
||||
this._focusedPairId = null;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
|
||||
@@ -97,7 +97,7 @@ class KeyValueEditorRow extends PureComponent {
|
||||
) : null
|
||||
}
|
||||
|
||||
<div className="key-value-editor__row" onMouseDown={preventDefault/* Don't trigger drag*/}>
|
||||
<div className="key-value-editor__row">
|
||||
<div className="form-control form-control--underlined form-control--wide">
|
||||
<OneLineEditor
|
||||
ref={this._setNameInputRef}
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import React, {PureComponent, PropTypes} from 'react';
|
||||
import {debounce} from '../../../common/misc';
|
||||
|
||||
class ResponseRaw extends PureComponent {
|
||||
_update (value) {
|
||||
// Use a timeout so it doesn't block the UI
|
||||
window.requestAnimationFrame(() => this._setTextAreaValue(value))
|
||||
}
|
||||
// Use a timeout so it doesn't block the UI
|
||||
_update = debounce(value => this._setTextAreaValue(value));
|
||||
|
||||
_setTextAreaValue (value) {
|
||||
// Bail if we're not mounted
|
||||
|
||||
@@ -13,18 +13,18 @@ class ResponseViewer extends PureComponent {
|
||||
blockingBecauseTooLarge: false
|
||||
};
|
||||
|
||||
_handleOpenLink (link) {
|
||||
_handleOpenLink = link => {
|
||||
shell.openExternal(link);
|
||||
}
|
||||
};
|
||||
|
||||
_handleDismissBlocker () {
|
||||
_handleDismissBlocker = () => {
|
||||
this.setState({blockingBecauseTooLarge: false});
|
||||
}
|
||||
};
|
||||
|
||||
_handleDisableBlocker () {
|
||||
_handleDisableBlocker = () => {
|
||||
alwaysShowLargeResponses = true;
|
||||
this._handleDismissBlocker();
|
||||
}
|
||||
};
|
||||
|
||||
_checkResponseBlocker (props) {
|
||||
if (alwaysShowLargeResponses) {
|
||||
@@ -101,13 +101,13 @@ class ResponseViewer extends PureComponent {
|
||||
slowdowns on some computers
|
||||
</p>
|
||||
<p>
|
||||
<button onClick={e => this._handleDismissBlocker()}
|
||||
<button onClick={this._handleDismissBlocker}
|
||||
className="inline-block btn btn--clicky">
|
||||
Show Response
|
||||
</button>
|
||||
{" "}
|
||||
<button className="faint inline-block btn btn--super-compact"
|
||||
onClick={e => this._handleDisableBlocker()}>
|
||||
onClick={this._handleDisableBlocker}>
|
||||
Always Show
|
||||
</button>
|
||||
</p>
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
padding-left: @padding-md;
|
||||
margin-top: @padding-xs;
|
||||
margin-bottom: @padding-xs;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.key-value-editor__row-wrapper--disabled .input,
|
||||
@@ -43,6 +45,11 @@
|
||||
top: 100%;
|
||||
}
|
||||
|
||||
&.key-value-editor__row-wrapper--dragging-above::before {
|
||||
// So the line appears on the next row
|
||||
bottom: 100%;
|
||||
}
|
||||
|
||||
// Style last row the same no matter if focused or not.
|
||||
&.key-value-editor__row-wrapper--clicker .CodeMirror {
|
||||
border-color: var(--hl-sm) !important;
|
||||
@@ -70,6 +77,10 @@
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.input {
|
||||
background-color: transparent;
|
||||
height: @line-height-sm;
|
||||
|
||||
Reference in New Issue
Block a user