-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Token Input: Fix Firefox blur problems #6162
Changes from 3 commits
b1da1b5
cc524a7
d3a03a7
03496d8
59db858
3b94338
0b1f0ef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -95,11 +95,6 @@ var TokenField = React.createClass( { | |
} | ||
}, | ||
|
||
componentWillUnmount: function() { | ||
debug( 'componentWillUnmount' ); | ||
this._clearBlurTimeout(); | ||
}, | ||
|
||
render: function() { | ||
var classes = classNames( 'token-field', { | ||
'is-active': this.state.isActive, | ||
|
@@ -116,7 +111,6 @@ var TokenField = React.createClass( { | |
tokenFieldProps = Object.assign( {}, tokenFieldProps, { | ||
onKeyDown: this._onKeyDown, | ||
onKeyPress: this._onKeyPress, | ||
onBlur: this._onBlur, | ||
onFocus: this._onFocus | ||
} ); | ||
} | ||
|
@@ -125,7 +119,6 @@ var TokenField = React.createClass( { | |
<div { ...tokenFieldProps } > | ||
<div ref="tokensAndInput" | ||
className="token-field__input-container" | ||
onClick={ ! this.props.disabled && this._onClick } | ||
tabIndex="-1" | ||
> | ||
{ this._renderTokensAndInput() } | ||
|
@@ -178,7 +171,8 @@ var TokenField = React.createClass( { | |
ref: 'input', | ||
key: 'input', | ||
disabled: this.props.disabled, | ||
value: this.state.incompleteTokenValue | ||
value: this.state.incompleteTokenValue, | ||
onBlur: this._onBlur, | ||
}; | ||
|
||
if ( ! ( maxLength && value.length >= maxLength ) ) { | ||
|
@@ -193,78 +187,22 @@ var TokenField = React.createClass( { | |
}, | ||
|
||
_onFocus: function( event ) { | ||
if ( this._blurTimeoutID ) { | ||
this._clearBlurTimeout(); | ||
return; | ||
} else if ( this.state.isActive ) { | ||
return; // already active | ||
} | ||
|
||
this.setState( { isActive: true } ); | ||
if ( 'function' === typeof this.props.onFocus ) { | ||
this.props.onFocus( event ); | ||
} | ||
}, | ||
|
||
_onBlur: function( event ) { | ||
var blurSource = event.relatedTarget || | ||
event.nativeEvent.explicitOriginalTarget || // FF | ||
document.activeElement; // IE11 | ||
|
||
var stillActive = this.refs.main.contains( blurSource ); | ||
|
||
if ( stillActive ) { | ||
debug( '_onBlur but component still active; not doing anything' ); | ||
return; // we didn't leave the component, so don't do anything | ||
} | ||
|
||
debug( '_onBlur before timeout setting component inactive' ); | ||
this.setState( { | ||
isActive: false | ||
} ); | ||
/* When the component blurs, we need to add the current text, or | ||
* the selected suggestion (if any). | ||
* | ||
* Two reasons to set a timeout rather than do this immediately: | ||
* - Some other user action (like tapping on a suggestion) may | ||
* have caused this blur. If there is another user-triggered | ||
* event, we need to give it a chance to complete first. | ||
* - At one point, using the right arrow key to move the text | ||
* input was causing a blur to outside the component?! (left | ||
* arrow key does not do this). So, we delay the resetting of | ||
* the state and cancel it if we get focus back quick enough. | ||
*/ | ||
debug( '_onBlur waiting to add current token' ); | ||
this._blurTimeoutID = window.setTimeout( function() { | ||
// Add the current token, UNLESS the text input is empty and | ||
// there is a suggested token selected. In that case, we don't | ||
// want to add it, because it's easy to inadvertently hover | ||
// over a suggestion. | ||
if ( this._inputHasValidValue() ) { | ||
debug( '_onBlur after timeout adding current token' ); | ||
this._addCurrentToken(); | ||
} else { | ||
debug( '_onBlur after timeout not adding current token' ); | ||
} | ||
debug( '_onBlur resetting component state' ); | ||
this.setState( this.getInitialState() ); | ||
this._clearBlurTimeout(); | ||
}.bind( this ), 0 ); | ||
}, | ||
|
||
_clearBlurTimeout: function() { | ||
if ( this._blurTimeoutID ) { | ||
debug( '_blurTimeoutID cleared' ); | ||
window.clearTimeout( this._blurTimeoutID ); | ||
this._blurTimeoutID = null; | ||
} | ||
}, | ||
|
||
_onClick: function() { | ||
if ( this.refs.input && ! this.refs.input.hasFocus() ) { | ||
debug( '_onClick focusing input' ); | ||
this.refs.input.focus(); | ||
debug( '_onBlur setting component inactive' ); | ||
if ( this._inputHasValidValue() ) { | ||
debug( '_onBlur adding current token' ); | ||
this._addCurrentToken(); | ||
} else { | ||
debug( '_onBlur not adding current token' ); | ||
} | ||
debug( '_onBlur resetting component state' ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ...and we can remove this one as well. |
||
this.setState( this.getInitialState() ); | ||
}, | ||
|
||
_onTokenClickRemove: function( event ) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,6 +94,7 @@ var SuggestionsList = React.createClass( { | |
<li | ||
className={ classes } | ||
key={ suggestion } | ||
onMouseDown={ this._handleMouseDown } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've tested this on the iPhone and mouseDown seems to do the job. |
||
onClick={ this._handleClick( suggestion ) } | ||
onMouseEnter={ this._handleHover( suggestion ) }> | ||
{ match ? | ||
|
@@ -124,6 +125,11 @@ var SuggestionsList = React.createClass( { | |
return function() { | ||
this.props.onSelect( suggestion ); | ||
}.bind( this ); | ||
}, | ||
|
||
_handleMouseDown: function( e ) { | ||
// By preventing default here, we will not lose focus of <input> when clicking a suggestion | ||
e.preventDefault(); | ||
} | ||
} ); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the new
_onBlur
code is very simple we can remove this debug statement...