aboutsummaryrefslogtreecommitdiffstats
path: root/ui/widgets/menu.js
diff options
context:
space:
mode:
authorFelix Nagel <info@felixnagel.com>2017-08-26 13:08:14 +0200
committerFelix Nagel <info@felixnagel.com>2017-08-26 13:08:14 +0200
commit1b885ff76899fb70cce28371968d314ea74b7d7a (patch)
tree1a3a19be9d874f9daffd1238950c073ec086ffc2 /ui/widgets/menu.js
parent2b611bad90fa6f19e3bf02912c6cd5c08903c993 (diff)
parent74f8a0ac952f6f45f773312292baef1c26d81300 (diff)
downloadjquery-ui-datepicker.tar.gz
jquery-ui-datepicker.zip
Merge branch 'master' into datepickerdatepicker
# Conflicts: # ui/i18n/datepicker-pt.js
Diffstat (limited to 'ui/widgets/menu.js')
-rw-r--r--ui/widgets/menu.js96
1 files changed, 60 insertions, 36 deletions
diff --git a/ui/widgets/menu.js b/ui/widgets/menu.js
index 49da26865..302d202ae 100644
--- a/ui/widgets/menu.js
+++ b/ui/widgets/menu.js
@@ -64,6 +64,7 @@ return $.widget( "ui.menu", {
// Flag used to prevent firing of the click handler
// as the event bubbles up through nested menus
this.mouseHandled = false;
+ this.lastMousePosition = { x: null, y: null };
this.element
.uniqueId()
.attr( {
@@ -78,6 +79,8 @@ return $.widget( "ui.menu", {
// them (focus should always stay on UL during navigation).
"mousedown .ui-menu-item": function( event ) {
event.preventDefault();
+
+ this._activateItem( event );
},
"click .ui-menu-item": function( event ) {
var target = $( event.target );
@@ -107,36 +110,15 @@ return $.widget( "ui.menu", {
}
}
},
- "mouseenter .ui-menu-item": function( event ) {
-
- // Ignore mouse events while typeahead is active, see #10458.
- // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
- // is over an item in the menu
- if ( this.previousFilter ) {
- return;
- }
-
- var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
- target = $( event.currentTarget );
-
- // Ignore bubbled events on parent items, see #11641
- if ( actualTarget[ 0 ] !== target[ 0 ] ) {
- return;
- }
-
- // Remove ui-state-active class from siblings of the newly focused menu item
- // to avoid a jump caused by adjacent elements both having a class with a border
- this._removeClass( target.siblings().children( ".ui-state-active" ),
- null, "ui-state-active" );
- this.focus( event, target );
- },
+ "mouseenter .ui-menu-item": "_activateItem",
+ "mousemove .ui-menu-item": "_activateItem",
mouseleave: "collapseAll",
"mouseleave .ui-menu": "collapseAll",
focus: function( event, keepActiveItem ) {
// If there's already an active item, keep it active
// If not, activate the first item
- var item = this.active || this.element.find( this.options.items ).eq( 0 );
+ var item = this.active || this._menuItems().first();
if ( !keepActiveItem ) {
this.focus( event, item );
@@ -162,7 +144,7 @@ return $.widget( "ui.menu", {
this._on( this.document, {
click: function( event ) {
if ( this._closeOnDocumentClick( event ) ) {
- this.collapseAll( event );
+ this.collapseAll( event, true );
}
// Reset the mouseHandled flag
@@ -171,6 +153,46 @@ return $.widget( "ui.menu", {
} );
},
+ _activateItem: function( event ) {
+
+ // Ignore mouse events while typeahead is active, see #10458.
+ // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
+ // is over an item in the menu
+ if ( this.previousFilter ) {
+ return;
+ }
+
+ // If the mouse didn't actually move, but the page was scrolled, ignore the event (#9356)
+ if ( event.clientX === this.lastMousePosition.x &&
+ event.clientY === this.lastMousePosition.y ) {
+ return;
+ }
+
+ this.lastMousePosition = {
+ x: event.clientX,
+ y: event.clientY
+ };
+
+ var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
+ target = $( event.currentTarget );
+
+ // Ignore bubbled events on parent items, see #11641
+ if ( actualTarget[ 0 ] !== target[ 0 ] ) {
+ return;
+ }
+
+ // If the item is already active, there's nothing to do
+ if ( target.is( ".ui-state-active" ) ) {
+ return;
+ }
+
+ // Remove ui-state-active class from siblings of the newly focused menu item
+ // to avoid a jump caused by adjacent elements both having a class with a border
+ this._removeClass( target.siblings().children( ".ui-state-active" ),
+ null, "ui-state-active" );
+ this.focus( event, target );
+ },
+
_destroy: function() {
var items = this.element.find( ".ui-menu-item" )
.removeAttr( "role aria-disabled" ),
@@ -502,7 +524,7 @@ return $.widget( "ui.menu", {
this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
this.activeMenu = currentMenu;
- }, this.delay );
+ }, all ? 0 : this.delay );
},
// With no arguments, closes the currently active menu - if nothing is active
@@ -538,11 +560,7 @@ return $.widget( "ui.menu", {
},
expand: function( event ) {
- var newItem = this.active &&
- this.active
- .children( ".ui-menu " )
- .find( this.options.items )
- .first();
+ var newItem = this.active && this._menuItems( this.active.children( ".ui-menu" ) ).first();
if ( newItem && newItem.length ) {
this._open( newItem.parent() );
@@ -570,21 +588,27 @@ return $.widget( "ui.menu", {
return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
},
+ _menuItems: function( menu ) {
+ return ( menu || this.element )
+ .find( this.options.items )
+ .filter( ".ui-menu-item" );
+ },
+
_move: function( direction, filter, event ) {
var next;
if ( this.active ) {
if ( direction === "first" || direction === "last" ) {
next = this.active
[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
- .eq( -1 );
+ .last();
} else {
next = this.active
[ direction + "All" ]( ".ui-menu-item" )
- .eq( 0 );
+ .first();
}
}
if ( !next || !next.length || !this.active ) {
- next = this.activeMenu.find( this.options.items )[ filter ]();
+ next = this._menuItems( this.activeMenu )[ filter ]();
}
this.focus( event, next );
@@ -610,7 +634,7 @@ return $.widget( "ui.menu", {
this.focus( event, item );
} else {
- this.focus( event, this.activeMenu.find( this.options.items )
+ this.focus( event, this._menuItems( this.activeMenu )
[ !this.active ? "first" : "last" ]() );
}
},
@@ -634,7 +658,7 @@ return $.widget( "ui.menu", {
this.focus( event, item );
} else {
- this.focus( event, this.activeMenu.find( this.options.items ).first() );
+ this.focus( event, this._menuItems( this.activeMenu ).first() );
}
},