Permalink
Browse files

Popup: Added _closeTry and _closeVet methods. Fixes closing the popup…

… unexpectedly by race conditions.

- A focusout followed by a focusin sometimes trigger events in reverse order,
  but should not close the popup nevertheless. Or a click-in-the-popup followed
  by a focusout should also avoid closing it unexpectedly;
- _closeTry and _closeVet work together to close the popup, but making sure no
  other event vets it;
  • Loading branch information...
1 parent 28fdac8 commit c6cce9cada38e480c49b4dd4bd84956dbb426332 @rxaviers committed May 26, 2012
Showing with 35 additions and 13 deletions.
  1. +35 −13 ui/jquery.ui.popup.js
View
@@ -89,7 +89,7 @@ $.widget( "ui.popup", {
case $.ui.keyCode.UP:
// prevent scrolling
event.preventDefault();
- clearTimeout( this.closeTimer );
+ this._closeVet();
this._delay(function() {
this.open( event );
this.focusPopup( event );
@@ -114,7 +114,7 @@ $.widget( "ui.popup", {
return;
}
this.open( event );
- clearTimeout( this.closeTimer );
+ this._closeVet();
this._delay( function() {
if ( !noFocus ) {
this.focusPopup();
@@ -164,17 +164,10 @@ $.widget( "ui.popup", {
this._bind({
focusout: function( event ) {
- // use a timer to allow click to clear it and letting that
- // handle the closing instead of opening again
- this.closeTimer = this._delay( function() {
- this.close( event );
- }, 150);
+ this._closeTry( event );
},
focusin: function( event ) {
- clearTimeout( this.closeTimer );
- },
- mouseup: function( event ) {
- clearTimeout( this.closeTimer );
+ this._closeVet();
}
});
@@ -189,13 +182,42 @@ $.widget( "ui.popup", {
this._bind( this.document, {
click: function( event ) {
- if ( this.isOpen && !$( event.target ).closest( this.element.add( this.options.trigger ) ).length ) {
- this.close( event );
+ if ( this.isOpen ) {
+ if ( $( event.target ).closest( this.element.add( this.options.trigger ) ).length ) {
+ this._closeVet();
+ }
+ else {
+ this._closeTry( event );
+ }
}
}
});
},
+ // Unless vetted, close. Use a timer to allow veto in a timed window.
+ // Note that a focusout followed by a focusin sometimes trigger events in reverse order, but should not close the popup nevertheless. Or a click-in-the-popup followed by a focusout should also avoid closing it unexpectedly.
+ _closeTry: function( event ) {
+ if ( this.closeVeto || this.closeTimer ) {
+ return;
+ }
+ this.closeTimer = this._delay( function() {
+ this.close( event );
+ this.closeTimer = null;
+ }, 150 );
+ },
+
+ // Vets any close attempt in a timed window.
+ _closeVet: function() {
+ this.closeVeto = true;
+ this._delay( function() {
+ this.closeVeto = false;
+ }, 150 );
+ if ( this.closeTimer ) {
+ clearTimeout( this.closeTimer );
+ this.closeTimer = null;
+ }
+ },
+
_destroy: function() {
this.element
.show()

0 comments on commit c6cce9c

Please sign in to comment.