mirror of
https://github.com/fastmail/Squire.git
synced 2025-03-13 08:01:37 -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;
|
node = parent;
|
||||||
parent = node.parentNode;
|
parent = node.parentNode;
|
||||||
}
|
}
|
||||||
// If focussed in empty inline element
|
// If focused in empty inline element
|
||||||
if ( node !== parent ) {
|
if ( node !== parent ) {
|
||||||
// Move focus to just before empty inline(s)
|
// Move focus to just before empty inline(s)
|
||||||
range.setStart( parent,
|
range.setStart( parent,
|
||||||
|
@ -2310,6 +2310,7 @@ function Squire ( root, config ) {
|
||||||
|
|
||||||
this._events = {};
|
this._events = {};
|
||||||
|
|
||||||
|
this._isFocused = false;
|
||||||
this._lastSelection = null;
|
this._lastSelection = null;
|
||||||
|
|
||||||
// IE loses selection state of iframe on blur, so make sure we
|
// IE loses selection state of iframe on blur, so make sure we
|
||||||
|
@ -2502,8 +2503,26 @@ var customEvents = {
|
||||||
};
|
};
|
||||||
|
|
||||||
proto.fireEvent = function ( type, event ) {
|
proto.fireEvent = function ( type, event ) {
|
||||||
var handlers = this._events[ type ],
|
var handlers = this._events[ type ];
|
||||||
l, obj;
|
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 ( handlers ) {
|
||||||
if ( !event ) {
|
if ( !event ) {
|
||||||
event = {};
|
event = {};
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -42,6 +42,7 @@ function Squire ( root, config ) {
|
||||||
|
|
||||||
this._events = {};
|
this._events = {};
|
||||||
|
|
||||||
|
this._isFocused = false;
|
||||||
this._lastSelection = null;
|
this._lastSelection = null;
|
||||||
|
|
||||||
// IE loses selection state of iframe on blur, so make sure we
|
// IE loses selection state of iframe on blur, so make sure we
|
||||||
|
@ -234,8 +235,26 @@ var customEvents = {
|
||||||
};
|
};
|
||||||
|
|
||||||
proto.fireEvent = function ( type, event ) {
|
proto.fireEvent = function ( type, event ) {
|
||||||
var handlers = this._events[ type ],
|
var handlers = this._events[ type ];
|
||||||
l, obj;
|
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 ( handlers ) {
|
||||||
if ( !event ) {
|
if ( !event ) {
|
||||||
event = {};
|
event = {};
|
||||||
|
|
|
@ -110,7 +110,7 @@ var afterDelete = function ( self, range ) {
|
||||||
node = parent;
|
node = parent;
|
||||||
parent = node.parentNode;
|
parent = node.parentNode;
|
||||||
}
|
}
|
||||||
// If focussed in empty inline element
|
// If focused in empty inline element
|
||||||
if ( node !== parent ) {
|
if ( node !== parent ) {
|
||||||
// Move focus to just before empty inline(s)
|
// Move focus to just before empty inline(s)
|
||||||
range.setStart( parent,
|
range.setStart( parent,
|
||||||
|
|
Loading…
Add table
Reference in a new issue