mirror of
https://github.com/fastmail/Squire.git
synced 2024-12-22 07:13:08 -05:00
Enforce sane focus/blur events.
Because focus/blur events are fired synchonously, browsers can get confused if UI code starts focusing other elements while inside a focus/blur handler, and end up firing events in the wrong order which can cause infinite loops. This change ensures we only get a focus/blur event when they really are happening, and you always get one then the other.
This commit is contained in:
parent
84ae8a05f5
commit
f593d8ac04
4 changed files with 46 additions and 8 deletions
|
@ -1300,7 +1300,7 @@ var afterDelete = function ( self, range ) {
|
|||
node = parent;
|
||||
parent = node.parentNode;
|
||||
}
|
||||
// If focussed in empty inline element
|
||||
// If focused in empty inline element
|
||||
if ( node !== parent ) {
|
||||
// Move focus to just before empty inline(s)
|
||||
range.setStart( parent,
|
||||
|
@ -2310,6 +2310,7 @@ function Squire ( root, config ) {
|
|||
|
||||
this._events = {};
|
||||
|
||||
this._isFocused = false;
|
||||
this._lastSelection = null;
|
||||
|
||||
// IE loses selection state of iframe on blur, so make sure we
|
||||
|
@ -2502,8 +2503,26 @@ var customEvents = {
|
|||
};
|
||||
|
||||
proto.fireEvent = function ( type, event ) {
|
||||
var handlers = this._events[ type ],
|
||||
l, obj;
|
||||
var handlers = this._events[ type ];
|
||||
var isFocused, l, obj;
|
||||
// UI code, especially modal views, may be monitoring for focus events and
|
||||
// immediately removing focus. In certain conditions, this can cause the
|
||||
// focus event to fire after the blur event, which can cause an infinite
|
||||
// loop. So we detect whether we're actually focused/blurred before firing.
|
||||
if ( /^(?:focus|blur)/.test( type ) ) {
|
||||
isFocused = isOrContains( this._root, this._doc.activeElement );
|
||||
if ( type === 'focus' ) {
|
||||
if ( !isFocused || this._isFocused ) {
|
||||
return this;
|
||||
}
|
||||
this._isFocused = true;
|
||||
} else {
|
||||
if ( isFocused || !this._isFocused ) {
|
||||
return this;
|
||||
}
|
||||
this._isFocused = false;
|
||||
}
|
||||
}
|
||||
if ( handlers ) {
|
||||
if ( !event ) {
|
||||
event = {};
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -42,6 +42,7 @@ function Squire ( root, config ) {
|
|||
|
||||
this._events = {};
|
||||
|
||||
this._isFocused = false;
|
||||
this._lastSelection = null;
|
||||
|
||||
// IE loses selection state of iframe on blur, so make sure we
|
||||
|
@ -234,8 +235,26 @@ var customEvents = {
|
|||
};
|
||||
|
||||
proto.fireEvent = function ( type, event ) {
|
||||
var handlers = this._events[ type ],
|
||||
l, obj;
|
||||
var handlers = this._events[ type ];
|
||||
var isFocused, l, obj;
|
||||
// UI code, especially modal views, may be monitoring for focus events and
|
||||
// immediately removing focus. In certain conditions, this can cause the
|
||||
// focus event to fire after the blur event, which can cause an infinite
|
||||
// loop. So we detect whether we're actually focused/blurred before firing.
|
||||
if ( /^(?:focus|blur)/.test( type ) ) {
|
||||
isFocused = isOrContains( this._root, this._doc.activeElement );
|
||||
if ( type === 'focus' ) {
|
||||
if ( !isFocused || this._isFocused ) {
|
||||
return this;
|
||||
}
|
||||
this._isFocused = true;
|
||||
} else {
|
||||
if ( isFocused || !this._isFocused ) {
|
||||
return this;
|
||||
}
|
||||
this._isFocused = false;
|
||||
}
|
||||
}
|
||||
if ( handlers ) {
|
||||
if ( !event ) {
|
||||
event = {};
|
||||
|
|
|
@ -110,7 +110,7 @@ var afterDelete = function ( self, range ) {
|
|||
node = parent;
|
||||
parent = node.parentNode;
|
||||
}
|
||||
// If focussed in empty inline element
|
||||
// If focused in empty inline element
|
||||
if ( node !== parent ) {
|
||||
// Move focus to just before empty inline(s)
|
||||
range.setStart( parent,
|
||||
|
|
Loading…
Reference in a new issue