aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkborchers <kris.borchers@gmail.com>2011-12-15 12:56:12 -0600
committerkborchers <kris.borchers@gmail.com>2011-12-15 12:57:11 -0600
commita53916b45427d1afa3507acbebb6f92a03bbcd84 (patch)
treefac2d548af11865cecdca70c20a9d419ba9a7ace
parentc00b685cb824fe940226be041067b0b9c44ba983 (diff)
parenta8d0e4c8043b42257c51a1d65cd07d1042538062 (diff)
downloadjquery-ui-a53916b45427d1afa3507acbebb6f92a03bbcd84.tar.gz
jquery-ui-a53916b45427d1afa3507acbebb6f92a03bbcd84.zip
Merge branch 'master' into selectmenu
-rw-r--r--demos/menubar/default.html55
-rw-r--r--tests/unit/menu/menu_defaults.js2
-rw-r--r--tests/unit/menu/menu_events.js7
-rw-r--r--tests/visual/menu/menu.html4
-rw-r--r--themes/base/jquery.ui.menu.css2
-rw-r--r--themes/base/jquery.ui.menubar.css2
-rw-r--r--ui/jquery.ui.menu.js76
-rw-r--r--ui/jquery.ui.menubar.js101
8 files changed, 149 insertions, 100 deletions
diff --git a/demos/menubar/default.html b/demos/menubar/default.html
index 72c124423..ef39a7121 100644
--- a/demos/menubar/default.html
+++ b/demos/menubar/default.html
@@ -35,6 +35,15 @@
},
select: select
});
+
+ $("#bar3").menubar({
+ position: {
+ within: $("#demo-frame").add(window).first()
+ },
+ select: select,
+ items: ".menubarItem",
+ menuElement: ".menuElement"
+ });
});
</script>
<style>
@@ -136,6 +145,52 @@
</li>
</ul>
+<div id="bar3" class="menubar">
+ <div class="menubarItem">
+ <a href="#File">File</a>
+ <div class="menuElement">
+ <div><a href="#Open...">Open...</a></div>
+ <div class="ui-state-disabled">Open recent...</div>
+ <div><a href="#Save">Save</a></div>
+ <div><a href="#Save as...">Save as...</a></div>
+ <div><a href="#Close">Close</a></div>
+ <div><a href="#Quit">Quit</a></div>
+ </div>
+ </div>
+ <div class="menubarItem">
+ <a href="#Edit">Edit</a>
+ <div class="menuElement">
+ <div><a href="#Copy">Copy</a></div>
+ <div><a href="#Cut">Cut</a></div>
+ <div class="ui-state-disabled">Paste</div>
+ </div>
+ </div>
+ <div class="menubarItem">
+ <a href="#View">View</a>
+ <div class="menuElement">
+ <div><a href="#Fullscreen">Fullscreen</a></div>
+ <div><a href="#Fit into view">Fit into view</a></div>
+ <div>
+ <a href="#Encoding">Encoding</a>
+ <div class="menuElement">
+ <div class="ui-state-disabled">Auto-detect</div>
+ <div><a href="#UTF-8">UTF-8</a></div>
+ <div>
+ <a href="#UTF-16">UTF-16</a>
+ <div class="menuElement">
+ <div><a href="#Option 1">Option 1</a></div>
+ <div><a href="#Option 2">Option 2</a></div>
+ <div class="ui-state-disabled">Option 3</div>
+ <div><a href="#Option 4">Option 4</a></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div><a href="#Customize...">Customize...</a></div>
+ </div>
+ </div>
+</div>
+
<div class="ui-widget" style="margin-top:2em; font-family:Arial">
Log:
<div id="log" style="height: 100px; width: 300px; overflow: auto;" class="ui-widget-content"></div>
diff --git a/tests/unit/menu/menu_defaults.js b/tests/unit/menu/menu_defaults.js
index a559a3d8d..3d7ec297f 100644
--- a/tests/unit/menu/menu_defaults.js
+++ b/tests/unit/menu/menu_defaults.js
@@ -5,7 +5,7 @@ commonWidgetTests( "menu", {
my: "left top",
at: "right top"
},
- items: "ul",
+ menus: "ul",
trigger: null,
// callbacks
diff --git a/tests/unit/menu/menu_events.js b/tests/unit/menu/menu_events.js
index 55ec1e2ff..79b98163b 100644
--- a/tests/unit/menu/menu_events.js
+++ b/tests/unit/menu/menu_events.js
@@ -27,7 +27,7 @@ test("handle click on custom item menu", function() {
select: function(event, ui) {
menu_log();
},
- items: "div"
+ menus: "div"
});
menu_log("click",true);
menu_click($('#menu5'),"1");
@@ -38,6 +38,8 @@ test("handle click on custom item menu", function() {
equals( $("#log").html(), "1,3,2,afterclick,1,click,", "Click order not valid.");
});
+/* Commenting out these tests until a way to handle the extra focus and blur events
+ fired by IE is found
test( "handle blur: click", function() {
expect( 4 );
var $menu = $( "#menu1" ).menu({
@@ -78,6 +80,7 @@ test( "handle blur on custom item menu: click", function() {
$("#remove").remove();
});
+*/
asyncTest( "handle submenu auto collapse: mouseleave", function() {
expect( 4 );
@@ -100,7 +103,7 @@ asyncTest( "handle submenu auto collapse: mouseleave", function() {
asyncTest( "handle custom menu item submenu auto collapse: mouseleave", function() {
expect( 5 );
- var $menu = $( "#menu5" ).menu( { items: "div" } );
+ var $menu = $( "#menu5" ).menu( { menus: "div" } );
$menu.children( ":nth-child(7)" ).trigger( "mouseover" );
setTimeout(function() {
diff --git a/tests/visual/menu/menu.html b/tests/visual/menu/menu.html
index 50837f43e..0715ac7f7 100644
--- a/tests/visual/menu/menu.html
+++ b/tests/visual/menu/menu.html
@@ -28,14 +28,14 @@
select: function(event, ui) {
$("<div/>").text("Selected: " + ui.item.text()).appendTo("#log");
},
- items: "div"
+ menus: "div"
});
$("#menu6").menu({
select: function(event, ui) {
$("<div/>").text("Selected: " + ui.item.text()).appendTo("#log");
},
- items: ".menuElement"
+ menus: ".menuElement"
});
}
diff --git a/themes/base/jquery.ui.menu.css b/themes/base/jquery.ui.menu.css
index c616cf2c5..33a9498fb 100644
--- a/themes/base/jquery.ui.menu.css
+++ b/themes/base/jquery.ui.menu.css
@@ -14,7 +14,7 @@
.ui-menu .ui-menu-item a.ui-state-focus,
.ui-menu .ui-menu-item a.ui-state-active { font-weight: normal; margin: -1px; }
-.ui-menu li.ui-state-disabled { font-weight: normal; padding: .0em .4em; margin: .4em 0 .2em; line-height: 1.5; }
+.ui-menu .ui-state-disabled { font-weight: normal; padding: .0em .4em; margin: .4em 0 .2em; line-height: 1.5; }
/* icon support */
.ui-menu-icons { position: relative; }
diff --git a/themes/base/jquery.ui.menubar.css b/themes/base/jquery.ui.menubar.css
index 95c42ae9e..8b175f28a 100644
--- a/themes/base/jquery.ui.menubar.css
+++ b/themes/base/jquery.ui.menubar.css
@@ -12,4 +12,4 @@
.ui-menubar .ui-button { float: left; font-weight: normal; border-top-width: 0 !important; border-bottom-width: 0 !important; margin: 0; outline: none; }
.ui-menubar .ui-menubar-link { border-right: 1px dashed transparent; border-left: 1px dashed transparent; }
-.ui-menubar .ui-menu { width: 200px; position: absolute; z-index: 9999; }
+.ui-menubar .ui-menu { width: 200px; position: absolute; z-index: 9999; font-weight: normal; }
diff --git a/ui/jquery.ui.menu.js b/ui/jquery.ui.menu.js
index 0263cff65..6e534b1ba 100644
--- a/ui/jquery.ui.menu.js
+++ b/ui/jquery.ui.menu.js
@@ -54,14 +54,13 @@ $.widget( "ui.menu", {
},
"click .ui-menu-item:has(a)": function( event ) {
event.stopImmediatePropagation();
- var target = $( event.currentTarget );
- // it's possible to click an item without hovering it (#7085)
- if ( !this.active || ( this.active[ 0 ] !== target[ 0 ] ) ) {
- this.focus( event, target );
- }
this.select( event );
- // Redirect focus to the menu.
- this.element.focus();
+ // Redirect focus to the menu with a delay for firefox
+ this._delay( function() {
+ if ( !this.element.is(":focus") ) {
+ this.element.focus();
+ }
+ }, 20);
},
"mouseover .ui-menu-item": function( event ) {
event.stopImmediatePropagation();
@@ -72,9 +71,21 @@ $.widget( "ui.menu", {
},
"mouseleave": "collapseAll",
"mouseleave .ui-menu": "collapseAll",
- "mouseout .ui-menu-item": "blur",
"focus": function( event ) {
- this.focus( event, $( event.target ).children( ".ui-menu-item:first" ) );
+ var firstItem = this.element.children( ".ui-menu-item" ).eq( 0 );
+ if ( this._hasScroll() && !this.active ) {
+ var menu = this.element;
+ menu.children().each( function() {
+ var currentItem = $( this );
+ if ( currentItem.offset().top - menu.offset().top >= 0 ) {
+ firstItem = currentItem;
+ return false;
+ }
+ });
+ } else if ( this.active ) {
+ firstItem = this.active;
+ }
+ this.focus( event, firstItem );
},
blur: function( event ) {
this._delay( function() {
@@ -283,21 +294,6 @@ $.widget( "ui.menu", {
focus: function( event, item ) {
this.blur( event );
- if ( this._hasScroll() ) {
- var borderTop = parseFloat( $.curCSS( this.activeMenu[0], "borderTopWidth", true ) ) || 0,
- paddingTop = parseFloat( $.curCSS( this.activeMenu[0], "paddingTop", true ) ) || 0,
- offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop,
- scroll = this.activeMenu.scrollTop(),
- elementHeight = this.activeMenu.height(),
- itemHeight = item.height();
-
- if ( offset < 0 ) {
- this.activeMenu.scrollTop( scroll + offset );
- } else if ( offset + itemHeight > elementHeight ) {
- this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
- }
- }
-
this.active = item.first()
.children( "a" )
.addClass( "ui-state-focus" )
@@ -463,15 +459,14 @@ $.widget( "ui.menu", {
},
nextPage: function( event ) {
+ if ( !this.active ) {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
+ return;
+ }
+ if ( this.last() ) {
+ return;
+ }
if ( this._hasScroll() ) {
- if ( !this.active ) {
- this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
- return;
- }
- if ( this.last() ) {
- return;
- }
-
var base = this.active.offset().top,
height = this.element.height(),
result;
@@ -488,15 +483,14 @@ $.widget( "ui.menu", {
},
previousPage: function( event ) {
+ if ( !this.active ) {
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
+ return;
+ }
+ if ( this.first() ) {
+ return;
+ }
if ( this._hasScroll() ) {
- if ( !this.active ) {
- this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
- return;
- }
- if ( this.first() ) {
- return;
- }
-
var base = this.active.offset().top,
height = this.element.height(),
result;
@@ -512,7 +506,7 @@ $.widget( "ui.menu", {
},
_hasScroll: function() {
- return this.element.height() < this.element.prop( "scrollHeight" );
+ return this.element.outerHeight() < this.element.prop( "scrollHeight" );
},
select: function( event ) {
diff --git a/ui/jquery.ui.menubar.js b/ui/jquery.ui.menubar.js
index 673493366..6bc03ba4d 100644
--- a/ui/jquery.ui.menubar.js
+++ b/ui/jquery.ui.menubar.js
@@ -22,6 +22,8 @@ $.widget( "ui.menubar", {
options: {
autoExpand: false,
buttons: false,
+ items: "li",
+ menuElement: "ul",
menuIcon: false,
position: {
my: "left top",
@@ -30,19 +32,21 @@ $.widget( "ui.menubar", {
},
_create: function() {
var that = this;
- var items = this.items = this.element.children( "li" )
+ this.menuItems = this.element.children( this.options.items );
+ this.items = this.menuItems.children( "button, a" );
+
+ this.menuItems
.addClass( "ui-menubar-item" )
- .attr( "role", "presentation" )
- .children( "button, a" );
+ .attr( "role", "presentation" );
// let only the first item receive focus
- items.slice(1).attr( "tabIndex", -1 );
+ this.items.slice(1).attr( "tabIndex", -1 );
this.element
.addClass( "ui-menubar ui-widget-header ui-helper-clearfix" )
.attr( "role", "menubar" );
- this._focusable( items );
- this._hoverable( items );
- items.next( "ul" )
+ this._focusable( this.items );
+ this._hoverable( this.items );
+ this.items.siblings( this.options.menuElement )
.menu({
position: {
within: this.options.position.within
@@ -53,7 +57,8 @@ $.widget( "ui.menubar", {
// TODO what is this targetting? there's probably a better way to access it
$(event.target).prev().focus();
that._trigger( "select", event, ui );
- }
+ },
+ menus: that.options.menuElement
})
.hide()
.attr({
@@ -66,19 +71,19 @@ $.widget( "ui.menubar", {
return;
switch ( event.keyCode ) {
case $.ui.keyCode.LEFT:
- that._left( event );
+ that.previous( event );
event.preventDefault();
break;
case $.ui.keyCode.RIGHT:
- that._right( event );
+ that.next( event );
event.preventDefault();
break;
};
});
- items.each(function() {
+ this.items.each(function() {
var input = $(this),
// TODO menu var is only used on two places, doesn't quite justify the .each
- menu = input.next( "ul" );
+ menu = input.next( that.options.menuElement );
input.bind( "click.menubar focus.menubar mouseenter.menubar", function( event ) {
// ignore triggered focus event
@@ -109,11 +114,11 @@ $.widget( "ui.menubar", {
event.preventDefault();
break;
case $.ui.keyCode.LEFT:
- that._prev( event, $( this ) );
+ that.previous( event );
event.preventDefault();
break;
case $.ui.keyCode.RIGHT:
- that._next( event, $( this ) );
+ that.next( event );
event.preventDefault();
break;
}
@@ -166,17 +171,16 @@ $.widget( "ui.menubar", {
},
_destroy : function() {
- var items = this.element.children( "li" )
+ this.menuItems
.removeClass( "ui-menubar-item" )
- .removeAttr( "role" )
- .children( "button, a" );
+ .removeAttr( "role" );
this.element
.removeClass( "ui-menubar ui-widget-header ui-helper-clearfix" )
.removeAttr( "role" )
.unbind( ".menubar" );
- items
+ this.items
.unbind( ".menubar" )
.removeClass( "ui-button ui-widget ui-button-text-only ui-menubar-link ui-state-default" )
.removeAttr( "role" )
@@ -243,55 +247,48 @@ $.widget( "ui.menubar", {
}, this.options.position ) )
.removeAttr( "aria-hidden" )
.attr( "aria-expanded", "true" )
- .menu("focus", event, menu.children( "li" ).first() )
+ .menu("focus", event, menu.children( ".ui-menu-item" ).first() )
// TODO need a comment here why both events are triggered
.focus()
.focusin();
this.open = true;
},
- // TODO refactor this and the next three methods
- _prev: function( event, button ) {
- button.attr( "tabIndex", -1 );
- var prev = button.parent().prevAll( "li" ).children( ".ui-button" ).eq( 0 );
- if ( prev.length ) {
- prev.removeAttr( "tabIndex" )[0].focus();
- } else {
- var lastItem = this.element.children( "li:last" ).children( ".ui-button:last" );
- lastItem.removeAttr( "tabIndex" )[0].focus();
- }
+ next: function( event ) {
+ this._move( "next", "first", event );
},
- _next: function( event, button ) {
- button.attr( "tabIndex", -1 );
- var next = button.parent().nextAll( "li" ).children( ".ui-button" ).eq( 0 );
- if ( next.length ) {
- next.removeAttr( "tabIndex")[0].focus();
- } else {
- var firstItem = this.element.children( "li:first" ).children( ".ui-button:first" );
- firstItem.removeAttr( "tabIndex" )[0].focus();
- }
+ previous: function( event ) {
+ this._move( "prev", "last", event );
},
- // TODO rename to parent
- _left: function( event ) {
- var prev = this.active.parent().prevAll( "li:eq(0)" ).children( ".ui-menu" ).eq( 0 );
- if ( prev.length ) {
- this._open( event, prev );
+ _move: function( direction, filter, event ) {
+ var next,
+ wrapItem;
+ if ( this.open ) {
+ next = this.active.closest( ".ui-menubar-item" )[ direction + "All" ]( this.options.items ).first().children( ".ui-menu" ).eq( 0 );
+ wrapItem = this.menuItems[ filter ]().children( ".ui-menu" ).eq( 0 );
} else {
- var lastItem = this.element.children( "li:last" ).children( ".ui-menu:first" );
- this._open( event, lastItem );
+ if ( event ) {
+ next = $( event.target ).closest( ".ui-menubar-item" )[ direction + "All" ]( this.options.items ).children( ".ui-menubar-link" ).eq( 0 );
+ wrapItem = this.menuItems[ filter ]().children( ".ui-menubar-link" ).eq( 0 );
+ } else {
+ next = wrapItem = this.menuItems.children( "a" ).eq( 0 );
+ }
}
- },
- // TODO rename to child (or something like that)
- _right: function( event ) {
- var next = this.active.parent().nextAll( "li:eq(0)" ).children( ".ui-menu" ).eq( 0 );
if ( next.length ) {
- this._open( event, next );
+ if ( this.open ) {
+ this._open( event, next );
+ } else {
+ next.removeAttr( "tabIndex")[0].focus();
+ }
} else {
- var firstItem = this.element.children( "li:first" ).children( ".ui-menu:first" );
- this._open( event, firstItem );
+ if ( this.open ) {
+ this._open( event, wrapItem );
+ } else {
+ wrapItem.removeAttr( "tabIndex")[0].focus();
+ }
}
}
});