diff options
author | jzaefferer <joern.zaefferer@gmail.com> | 2010-12-22 18:31:27 +0100 |
---|---|---|
committer | jzaefferer <joern.zaefferer@gmail.com> | 2010-12-22 18:31:27 +0100 |
commit | 3552947c19b8ea1b779dc9809783c6ac6a218d68 (patch) | |
tree | 61b23078b9ff83f65bd5258bc4dd9efed5ac5f7a | |
parent | 8d39171fa285519203688084f3cf66c1e2ae0ada (diff) | |
parent | 70e8e9f294729f120f7b52fb9803fddfd37e464e (diff) | |
download | jquery-ui-3552947c19b8ea1b779dc9809783c6ac6a218d68.tar.gz jquery-ui-3552947c19b8ea1b779dc9809783c6ac6a218d68.zip |
Merge remote branch 'origin/menu'
Conflicts:
demos/autocomplete/categories.html
demos/autocomplete/combobox.html
demos/autocomplete/custom-data.html
demos/autocomplete/default.html
demos/autocomplete/folding.html
demos/autocomplete/multiple-remote.html
demos/autocomplete/multiple.html
demos/autocomplete/remote-jsonp.html
demos/autocomplete/remote-with-cache.html
demos/autocomplete/remote.html
demos/autocomplete/xml.html
demos/button/splitbutton.html
demos/index.html
tests/visual/menu/nested.html
themes/base/jquery.ui.autocomplete.css
ui/jquery.ui.autocomplete.js
40 files changed, 848 insertions, 325 deletions
diff --git a/demos/autocomplete/categories.html b/demos/autocomplete/categories.html index 494445b25..163c969dd 100644 --- a/demos/autocomplete/categories.html +++ b/demos/autocomplete/categories.html @@ -8,6 +8,7 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <style> diff --git a/demos/autocomplete/combobox.html b/demos/autocomplete/combobox.html index 37bb0c179..f74f0f106 100644 --- a/demos/autocomplete/combobox.html +++ b/demos/autocomplete/combobox.html @@ -9,6 +9,7 @@ <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.button.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <style> diff --git a/demos/autocomplete/custom-data.html b/demos/autocomplete/custom-data.html index 9b6a2e6d4..8a3a0b235 100644 --- a/demos/autocomplete/custom-data.html +++ b/demos/autocomplete/custom-data.html @@ -8,6 +8,7 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <style> diff --git a/demos/autocomplete/default.html b/demos/autocomplete/default.html index 2f1495925..9de61467f 100644 --- a/demos/autocomplete/default.html +++ b/demos/autocomplete/default.html @@ -8,6 +8,7 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <script> diff --git a/demos/autocomplete/folding.html b/demos/autocomplete/folding.html index 5a06faa23..cea358a8d 100644 --- a/demos/autocomplete/folding.html +++ b/demos/autocomplete/folding.html @@ -8,6 +8,7 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <script> diff --git a/demos/autocomplete/multiple-remote.html b/demos/autocomplete/multiple-remote.html index 9494da98a..f0ea7aafd 100644 --- a/demos/autocomplete/multiple-remote.html +++ b/demos/autocomplete/multiple-remote.html @@ -1,6 +1,7 @@ <!DOCTYPE html> <html lang="en"> <head> +<<<<<<< HEAD <meta charset="utf-8"> <title>jQuery UI Autocomplete - Multiple, remote</title> <link rel="stylesheet" href="../../themes/base/jquery.ui.all.css"> @@ -8,6 +9,7 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <style> diff --git a/demos/autocomplete/multiple.html b/demos/autocomplete/multiple.html index 44e6971e5..0b8e14478 100644 --- a/demos/autocomplete/multiple.html +++ b/demos/autocomplete/multiple.html @@ -8,6 +8,7 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <script> diff --git a/demos/autocomplete/remote-jsonp.html b/demos/autocomplete/remote-jsonp.html index ab14bcd14..986e9f0f0 100644 --- a/demos/autocomplete/remote-jsonp.html +++ b/demos/autocomplete/remote-jsonp.html @@ -8,6 +8,7 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <style> diff --git a/demos/autocomplete/remote-with-cache.html b/demos/autocomplete/remote-with-cache.html index 1f4cce74b..a6b02f255 100644 --- a/demos/autocomplete/remote-with-cache.html +++ b/demos/autocomplete/remote-with-cache.html @@ -8,6 +8,7 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <style> diff --git a/demos/autocomplete/remote.html b/demos/autocomplete/remote.html index de8062100..c8ee849fe 100644 --- a/demos/autocomplete/remote.html +++ b/demos/autocomplete/remote.html @@ -8,6 +8,7 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <style> diff --git a/demos/autocomplete/xml.html b/demos/autocomplete/xml.html index ca338716b..fff432e58 100644 --- a/demos/autocomplete/xml.html +++ b/demos/autocomplete/xml.html @@ -8,6 +8,7 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <script src="../../ui/jquery.ui.autocomplete.js"></script> <link rel="stylesheet" href="../demos.css"> <style> diff --git a/demos/button/splitbutton.html b/demos/button/splitbutton.html index 580c49cc5..8baf12f00 100644 --- a/demos/button/splitbutton.html +++ b/demos/button/splitbutton.html @@ -8,6 +8,8 @@ <script src="../../ui/jquery.ui.core.js"></script> <script src="../../ui/jquery.ui.widget.js"></script> <script src="../../ui/jquery.ui.button.js"></script> + <script src="../../ui/jquery.ui.position.js"></script> + <script src="../../ui/jquery.ui.menu.js"></script> <link rel="stylesheet" href="../demos.css"> <script> $(function() { @@ -16,39 +18,60 @@ .click(function() { alert( "Running the last action" ); }) - .next() - .button( { - text: false, - icons: { - primary: "ui-icon-triangle-1-s" - } - }) - .click(function() { - alert( "Could display a menu to select an action" ); - }) - .parent() - .buttonset(); + .next() + .button( { + text: false, + icons: { + primary: "ui-icon-triangle-1-s" + } + }) + .click( function() { + var menu = $(this).parent().next().show().position({ + my: "left top", + at: "left bottom", + of: this + }); + $(document).one("click", function() { + menu.hide(); + }); + return false; + }) + .parent() + .buttonset() + .next() + .hide() + .menu(); }); </script> <style> - + .ui-menu { position: absolute; width: 100px; } </style> </head> <body> <div class="demo"> -<div> - <button id="rerun">Run last action</button> - <button id="select">Select an action</button> -</div> + <div> + <div> + <button id="rerun">Run last action</button> + <button id="select">Select an action</button> + </div> + <ul> + <li><a href="#">Open...</a></li> + <li><a href="#">Save</a></li> + <li><a href="#">Delete</a></li> + </ul> + </div> </div><!-- End demo --> <div class="demo-description"> -<p>An example of a split button built with two buttons: A plan button with just text, one with only a primary icon and no text. Both are grouped together in a set.</p> + +<p>An example of a split button built with two buttons: A plain button with just text, one with only a primary icon +and no text. Both are grouped together in a set.</p> + </div><!-- End demo-description --> </body> diff --git a/demos/index.html b/demos/index.html index fed42a23c..298803d2f 100644 --- a/demos/index.html +++ b/demos/index.html @@ -19,6 +19,7 @@ <script src="../ui/jquery.ui.dialog.js"></script> <script src="../ui/jquery.ui.draggable.js"></script> <script src="../ui/jquery.ui.droppable.js"></script> + <script src="../ui/jquery.ui.menu.js"></script> <script src="../ui/jquery.ui.position.js"></script> <script src="../ui/jquery.ui.progressbar.js"></script> <script src="../ui/jquery.ui.resizable.js"></script> @@ -270,6 +271,7 @@ <dd><a href="button/index.html">Button</a></dd> <dd><a href="datepicker/index.html">Datepicker</a></dd> <dd><a href="dialog/index.html">Dialog</a></dd> + <dd><a href="menu/index.html">Menu</a></dd> <dd><a href="progressbar/index.html">Progressbar</a></dd> <dd><a href="slider/index.html">Slider</a></dd> <dd><a href="spinner/index.html">Spinner</a></dd> diff --git a/demos/menu/contextmenu.html b/demos/menu/contextmenu.html new file mode 100644 index 000000000..682d016dc --- /dev/null +++ b/demos/menu/contextmenu.html @@ -0,0 +1,82 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <title>jQuery UI Menu - Contextmenu demo</title> + <link type="text/css" href="../../themes/base/jquery.ui.all.css" rel="stylesheet" /> + <script type="text/javascript" src="../../jquery-1.4.2.js"></script> + <script type="text/javascript" src="../../ui/jquery.ui.core.js"></script> + <script type="text/javascript" src="../../ui/jquery.ui.position.js"></script> + <script type="text/javascript" src="../../ui/jquery.ui.widget.js"></script> + <script type="text/javascript" src="../../ui/jquery.ui.menu.js"></script> + <script type="text/javascript" src="../../ui/jquery.ui.button.js"></script> + <link type="text/css" href="../demos.css" rel="stylesheet" /> + <script type="text/javascript"> + $(function() { + $(".demo button").button({ + icons: { + primary: "ui-icon-home", + secondary: "ui-icon-triangle-1-s" + } + }).each(function() { + $(this).next().menu({ + select: function(event, ui) { + $(this).hide(); + $("#log").append("<div>Selected " + ui.item.text() + "</div>"); + }, + input: $(this) + }).hide(); + }).click(function(event) { + var menu = $(this).next(); + if (menu.is(":visible")) { + menu.hide(); + return false; + } + menu.menu("deactivate").show().css({top:0, left:0}).position({ + my: "left top", + at: "right top", + of: this + }); + $(document).one("click", function() { + menu.hide(); + }); + return false; + }) + }); + </script> + <style> + .ui-menu { width: 200px; position: absolute; } + </style> +</head> +<body> + +<div class="demo"> + + <button>Select a city</button> + <ul> + <li><a href="#">Amsterdam</a></li> + <li><a href="#">Anaheim</a></li> + <li><a href="#">Cologne</a></li> + <li><a href="#">Frankfurt</a></li> + <li><a href="#">Magdeburg</a></li> + <li><a href="#">Munich</a></li> + <li><a href="#">Utrecht</a></li> + <li><a href="#">Zurich</a></li> + </ul> + + <div id="log"></div> + +</div><!-- End demo --> + +<div class="demo-description"> + +<p>A simple contextmenu: Click the button, or tab to it and hit space to open the menu. Use the mouse or cursor keys to select an item, click it or hit enter to select it.</p> + +<p>The keyboard handling is part of the menu. Using the input option to menu is configured to add the key event handlers to the button, as that button gets focused when clicked.</p> + +</div><!-- End demo-description --> + + + +</body> +</html> diff --git a/demos/menu/default.html b/demos/menu/default.html new file mode 100644 index 000000000..580439acb --- /dev/null +++ b/demos/menu/default.html @@ -0,0 +1,54 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <title>jQuery UI Menu - Default demo</title> + <link type="text/css" href="../../themes/base/jquery.ui.all.css" rel="stylesheet" /> + <script type="text/javascript" src="../../jquery-1.4.2.js"></script> + <script type="text/javascript" src="../../ui/jquery.ui.core.js"></script> + <script type="text/javascript" src="../../ui/jquery.ui.widget.js"></script> + <script type="text/javascript" src="../../ui/jquery.ui.menu.js"></script> + <link type="text/css" href="../demos.css" rel="stylesheet" /> + <script type="text/javascript"> + $(function() { + $(".demo ul").menu(); + }); + </script> + <style> + + </style> +</head> +<body> + +<div class="demo"> + + <ul> + <li><a href="#">Aberdeen</a></li> + <li><a href="#">Ada</a></li> + <li><a href="#">Adamsville</a></li> + <li><a href="#">Addyston</a></li> + <li><a href="#">Adelphi</a></li> + <li><a href="#">Adena</a></li> + <li><a href="#">Adrian</a></li> + <li><a href="#">Akron</a></li> + <li><a href="#">Albany</a></li> + <li><a href="#">Alexandria</a></li> + <li><a href="#">Alger</a></li> + <li><a href="#">Alledonia</a></li> + <li><a href="#">Alliance</a></li> + <li><a href="#">Alpha</a></li> + <li><a href="#">Alvada</a></li> + </ul> + +</div><!-- End demo --> + +<div class="demo-description"> + +<p>A menu with the default configuration. A list is transformed, adding themeing, mouse and keyboard navigation support. Try to tab to the menu and use the cursor keys to navigate.</p> + +</div><!-- End demo-description --> + + + +</body> +</html> diff --git a/demos/menu/index.html b/demos/menu/index.html new file mode 100644 index 000000000..cfc12bc1d --- /dev/null +++ b/demos/menu/index.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <title>jQuery UI Menu Demos</title> + <link type="text/css" href="../demos.css" rel="stylesheet" /> +</head> +<body> + <div class="demos-nav"> + <h4>Examples</h4> + <ul> + <li class="demo-config-on"><a href="default.html">Default functionality</a></li> + <li><a href="contextmenu.html">Contextmenu</a></li> + </ul> + </div> +</body> +</html> diff --git a/tests/static/index.html b/tests/static/index.html index 80048bf42..3145ad219 100644 --- a/tests/static/index.html +++ b/tests/static/index.html @@ -32,6 +32,8 @@ <li><a href="button/default.html">Button</a></li> <li><a href="datepicker/default.html">Datepicker</a></li> <li><a href="dialog/default.html">Dialog</a></li> + <li><a href="menu/default.html">Menu</a></li> + <li><a href="menu/all-menus-icons.html">Menu with icons</a></li> <li><a href="progressbar/default.html">Progressbar</a></li> <li><a href="slider/default.html">Slider</a></li> <li><a href="tabs/default.html">Tabs</a></li> diff --git a/tests/unit/index.html b/tests/unit/index.html index 33de9e765..1566cfc38 100644 --- a/tests/unit/index.html +++ b/tests/unit/index.html @@ -24,6 +24,7 @@ <script type="text/javascript" src="../../ui/jquery.ui.widget.js"></script> <script type="text/javascript" src="../../ui/jquery.ui.mouse.js"></script> <script type="text/javascript" src="../../ui/jquery.ui.accordion.js"></script> + <script type="text/javascript" src="../../ui/jquery.ui.menu.js"></script> <script type="text/javascript" src="../../ui/jquery.ui.autocomplete.js"></script> <script type="text/javascript" src="../../ui/jquery.ui.button.js"></script> <script type="text/javascript" src="../../ui/jquery.ui.datepicker.js"></script> diff --git a/tests/unit/menu/menu.html b/tests/unit/menu/menu.html new file mode 100644 index 000000000..b47728641 --- /dev/null +++ b/tests/unit/menu/menu.html @@ -0,0 +1,74 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <title>jQuery UI Menu Test Suite</title> + + <link rel="stylesheet" href="../../../themes/base/jquery.ui.all.css" type="text/css" title="ui-theme" /> + + <script type="text/javascript" src="../../../jquery-1.4.2.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.core.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script> + + <link rel="stylesheet" href="../../../external/qunit.css" type="text/css"/> + <script type="text/javascript" src="../../../external/qunit.js"></script> + <script type="text/javascript" src="../../jquery.simulate.js"></script> + <script type="text/javascript" src="../testsuite.js"></script> + + <script type="text/javascript"> + + function log(message,clear) { + if (clear && clear === true) { + $("#log").html(""); + } + if ( message === undefined ) { + message = $("#log").data("lastItem"); + } + $("#log").prepend( message + "," ); + } + function clickMenu(menu,item) { + $("#log").data("lastItem",item); + $('li:eq(' + item + ') a',menu).trigger("click"); + } + + + </script> + <script type="text/javascript" src="menu_core.js"></script> + <script type="text/javascript" src="menu_defaults.js"></script> + <script type="text/javascript" src="menu_events.js"></script> + <script type="text/javascript" src="menu_methods.js"></script> + <script type="text/javascript" src="menu_options.js"></script> + <script type="text/javascript" src="menu_tickets.js"></script> + + + <style> + #main { font-size: 10pt; font-family: 'trebuchet ms', verdana, arial; } + #list, #list1 *, #navigation, #navigation * { margin: 0; padding: 0; font-size: 12px; } + .mainOnMoon {position: absolute; top: -10000px; left: -10000px;} + </style> +</head> +<body> + +<h1 id="qunit-header">jQuery UI Menu Test Suite</h1> +<h2 id="qunit-banner"></h2> +<h2 id="qunit-userAgent"></h2> +<ol id="qunit-tests"> +</ol> + + +<div id="main" class="mainOnMoon"> + +<ul class="foo" id="menu1"> + <li class="foo"><a class="foo" href="#">Aberdeen</a></li> + <li class="foo"><a class="foo" href="#">Ada</a></li> + <li class="foo"><a class="foo" href="#">Adamsville</a></li> + <li class="foo"><a class="foo" href="#">Addyston</a></li> + <li class="foo"><a class="foo" href="#">Adelphi</a></li> +</ul> +<div id="log"></div> + +</div> + +</body> +</html> diff --git a/tests/unit/menu/menu_core.js b/tests/unit/menu/menu_core.js new file mode 100644 index 000000000..a1cf11b7f --- /dev/null +++ b/tests/unit/menu/menu_core.js @@ -0,0 +1,32 @@ +/* + * menu_core.js + */ + + +(function($) { + +module("menu: core"); + +test("accessibility", function () { + expect(3); + var ac = $('#menu1').menu(); + var item0 = $("li:eq(0) a"); + + ok( ac.hasClass("ui-menu ui-widget ui-widget-content ui-corner-all"), "menu class"); + equals( ac.attr("role"), "listbox", "main role"); + equals( ac.attr("aria-activedescendant"), "ui-active-menuitem", "aria attribute"); +}); + +test("items class and role", function () { + var ac = $('#menu1').menu(); + expect(1 + 4 * $("li",ac).length); + ok( ($("li",ac).length > 0 ), "number of menu items"); + $("li",ac).each(function(item) { + ok( $(this).hasClass("ui-menu-item"), "menu item ("+ item + ") class for item"); + equals( $(this).attr("role"), "menuitem", "menu item ("+ item + ") role"); + ok( $("a",this).hasClass("ui-corner-all"), "a element class for menu item ("+ item + ") "); + equals( $("a",this).attr("tabindex"), "-1", "a element tabindex for menu item ("+ item + ") "); + }); +}); + +})(jQuery); diff --git a/tests/unit/menu/menu_defaults.js b/tests/unit/menu/menu_defaults.js new file mode 100644 index 000000000..c3f741d2a --- /dev/null +++ b/tests/unit/menu/menu_defaults.js @@ -0,0 +1,11 @@ +/* + * menu_defaults.js + */ + +var menu_defaults = { + disabled: false, + navigationFilter: function() {} + +}; + +commonWidgetTests('menu', { defaults: menu_defaults }); diff --git a/tests/unit/menu/menu_events.js b/tests/unit/menu/menu_events.js new file mode 100644 index 000000000..a03bec3f6 --- /dev/null +++ b/tests/unit/menu/menu_events.js @@ -0,0 +1,24 @@ +/* + * menu_events.js + */ +(function($) { + +module("menu: events"); + +test("handle click on menu", function() { + expect(1); + var ac = $('#menu1').menu({ + select: function(event, ui) { + log(); + } + }); + log("click",true); + clickMenu($('#menu1'),"1"); + log("afterclick"); + clickMenu( ac,"2"); + clickMenu($('#menu1'),"3"); + clickMenu( ac,"1"); + equals( $("#log").html(), "1,3,2,afterclick,1,click,", "Click order not valid."); +}); + +})(jQuery); diff --git a/tests/unit/menu/menu_methods.js b/tests/unit/menu/menu_methods.js new file mode 100644 index 000000000..b6ebaf215 --- /dev/null +++ b/tests/unit/menu/menu_methods.js @@ -0,0 +1,19 @@ +/* + * menu_methods.js + */ +(function($) { + +module("menu: methods"); + +test("destroy", function() { + var beforeHtml = $("#menu1").find("div").css("font-style", "normal").end().parent().html(); + var afterHtml = $("#menu1").menu().menu("destroy").parent().html(); + // Opera 9 outputs role="" instead of removing the attribute like everyone else + if ($.browser.opera) { + afterHtml = afterHtml.replace(/ role=""/g, ""); + } + equal( afterHtml, beforeHtml ); +}); + + +})(jQuery); diff --git a/tests/unit/menu/menu_options.js b/tests/unit/menu/menu_options.js new file mode 100644 index 000000000..03822fd74 --- /dev/null +++ b/tests/unit/menu/menu_options.js @@ -0,0 +1,10 @@ +/* + * menu_options.js + */ +(function($) { + +module("menu: options"); + + + +})(jQuery); diff --git a/tests/unit/menu/menu_tickets.js b/tests/unit/menu/menu_tickets.js new file mode 100644 index 000000000..760afd368 --- /dev/null +++ b/tests/unit/menu/menu_tickets.js @@ -0,0 +1,8 @@ +/* + * menu_tickets.js + */ +(function($) { + +module("menu: tickets"); + +})(jQuery); diff --git a/tests/visual/all.html b/tests/visual/all.html index 4bbd323b0..c50465a47 100644 --- a/tests/visual/all.html +++ b/tests/visual/all.html @@ -11,6 +11,7 @@ <script type="text/javascript" src="../../ui/jquery.ui.mouse.js"></script> <script type="text/javascript" src="../../ui/jquery.ui.position.js"></script> <script type="text/javascript" src="../../ui/jquery.ui.accordion.js"></script> + <script type="text/javascript" src="../../ui/jquery.ui.menu.js"></script> <script type="text/javascript" src="../../ui/jquery.ui.autocomplete.js"></script> <script type="text/javascript" src="../../ui/jquery.ui.button.js"></script> <script type="text/javascript" src="../../ui/jquery.ui.datepicker.js"></script> diff --git a/tests/visual/autocomplete/autocomplete.html b/tests/visual/autocomplete/autocomplete.html index 9b0ba66f6..199451e9c 100644 --- a/tests/visual/autocomplete/autocomplete.html +++ b/tests/visual/autocomplete/autocomplete.html @@ -9,6 +9,7 @@ <script type="text/javascript" src="../../../ui/jquery.ui.core.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.position.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.autocomplete.js"></script> <script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script> <script type="text/javascript"> diff --git a/tests/visual/compound/widgets_in_dialog.html b/tests/visual/compound/widgets_in_dialog.html index 11120ea24..dc1b551cf 100644 --- a/tests/visual/compound/widgets_in_dialog.html +++ b/tests/visual/compound/widgets_in_dialog.html @@ -13,7 +13,7 @@ <script type="text/javascript" src="../../../ui/jquery.ui.resizable.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.draggable.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.accordion.js"></script> - <script type="text/javascript" src="../../../ui/jquery.ui.autocomplete.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.button.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.datepicker.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.dialog.js"></script> diff --git a/tests/visual/index.html b/tests/visual/index.html index c7b709279..04e23fddd 100644 --- a/tests/visual/index.html +++ b/tests/visual/index.html @@ -41,6 +41,14 @@ <li><a href="button/button.html">Button</a></li> <li><a href="datepicker/datepicker.html">Datepicker</a></li> <li><a href="dialog/dialog.html">Dialog</a></li> + <li> + <a href="menu/menu.html">Menu</a> + <ul> + <li><a href="menu/contextmenu.html">Context Menu</a></li> + <li><a href="menu/nested.html">Nested Menu</a></li> + <li><a href="menu/drilldown.html">Drilldown Menu</a></li> + </ul> + </li> <li><a href="progressbar/progressbar.html">Progressbar</a></li> <li><a href="slider/slider.html">Slider</a></li> <li><a href="spinner/spinner.html">Spinner</a></li> diff --git a/tests/visual/menu/contextmenu.html b/tests/visual/menu/contextmenu.html index eb328abf0..d3fdc4e7c 100644 --- a/tests/visual/menu/contextmenu.html +++ b/tests/visual/menu/contextmenu.html @@ -8,7 +8,7 @@ <script type="text/javascript" src="../../../ui/jquery.ui.core.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.position.js"></script> - <script type="text/javascript" src="../../../ui/jquery.ui.autocomplete.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script> <script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script> <script type="text/javascript"> $(function() { @@ -18,23 +18,24 @@ top: 10 }).appendTo(document.body).themeswitcher(); - var menus = $("#menu1, #menu2").menu({ - selected: function(event, ui) { - $("#log").append("<div>Selected " + ui.item.text() + "</div>"); - } - }).hide(); - - - $("button").click(function(event) { + $("button").each(function() { + $(this).next().menu({ + selected: function(event, ui) { + $(this).hide(); + $("#log").append("<div>Selected " + ui.item.text() + "</div>"); + }, + input: $(this) + }).hide(); + }).click(function(event) { // TODO required to prevent the click handler below from handling this event event.stopPropagation(); - $("#menu" + this.id).menu("deactivate").show().position({ + var menu = $("#menu" + this.id).menu("deactivate").show().position({ my: "left top", at: "right top", of: event.pageX > 0 ? event : this }); $(document).one("click", function() { - menus.hide(); + menu.hide(); }) }).keydown(function(event) { var menu = $("#menu" + this.id).data("menu"); @@ -42,24 +43,8 @@ return; event.stopPropagation(); switch (event.keyCode) { - case $.ui.keyCode.PAGE_UP: - menu.previousPage(); - break; - case $.ui.keyCode.PAGE_DOWN: - menu.nextPage(); - break; - case $.ui.keyCode.UP: - menu.previous(); - break; - case $.ui.keyCode.DOWN: - menu.next(); - event.preventDefault(); - break; - case $.ui.keyCode.ENTER: case $.ui.keyCode.TAB: - menu.select(); menu.widget().hide(); - event.preventDefault(); break; case $.ui.keyCode.ESCAPE: menu.widget().hide(); @@ -86,7 +71,7 @@ }); } if (match.length) { - menu.activate(match); + menu.activate(event, match); if (match.length > 1) { menu.previousFilter = character; menu.filterTimer = setTimeout(function() { @@ -111,7 +96,6 @@ <body> <button id="1">Show context menu 1</button> - <ul id="menu1"> <li><a href="#">Amsterdam</a></li> <li><a href="#">Anaheim</a></li> @@ -123,6 +107,12 @@ <li><a href="#">Zurich</a></li> </ul> +<div class="ui-widget" style="margin-top:2em; font-family:Arial"> + Log: + <div id="log" style="height: 400px; width: 300px; overflow: auto;" class="ui-widget-content"></div> +</div> + +<button id="2">Show context menu 2</button> <ul id="menu2"> <li><a href="#">Aberdeen</a></li> <li><a href="#">Ada</a></li> @@ -164,12 +154,5 @@ <li><a href="#">Amesville</a></li> </ul> -<div class="ui-widget" style="margin-top:2em; font-family:Arial"> - Log: - <div id="log" style="height: 400px; width: 300px; overflow: auto;" class="ui-widget-content"></div> -</div> - -<button id="2">Show context menu 2</button> - </body> </html> diff --git a/tests/visual/menu/drilldown.html b/tests/visual/menu/drilldown.html index 7bb7b03a2..65cdf1111 100644 --- a/tests/visual/menu/drilldown.html +++ b/tests/visual/menu/drilldown.html @@ -9,9 +9,16 @@ <script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.position.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.button.js"></script> - <script type="text/javascript" src="../../../ui/jquery.ui.autocomplete.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script> + <script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script> <script type="text/javascript"> $(function() { + $.fn.themeswitcher && $('<div/>').css({ + position: "absolute", + right: 10, + top: 10 + }).appendTo(document.body).themeswitcher(); + $.widget("ui.drilldown", { _init: function() { var self = this; @@ -21,10 +28,12 @@ this.element.find("ul").hide().prev("a").prepend('<span class="ui-icon ui-icon-carat-1-e"></span>').end().filter(":first").show(); this.element.find("ul").menu({ + // disable built-in key handling + input: $(), focus: function(event, ui) { self.activeItem = ui.item; }, - selected: function(event, ui) { + select: function(event, ui) { if (this != self.active[0]) { return; } @@ -33,7 +42,7 @@ self._open(nested); } else { self.element.find("h3").text(ui.item.text()); - self.options.selected.apply(this, arguments); + self.options.select.apply(this, arguments); } } }); @@ -115,7 +124,7 @@ }); var drilldown = $("#drilldown").drilldown({ - selected: function(event, ui) { + select: function(event, ui) { $("#log").append("<div>Selected " + ui.item.text() + "</div>"); } }); diff --git a/tests/visual/menu/menu.html b/tests/visual/menu/menu.html index 3a10da2e8..ec31a0f96 100644 --- a/tests/visual/menu/menu.html +++ b/tests/visual/menu/menu.html @@ -7,8 +7,7 @@ <script type="text/javascript" src="../../../jquery-1.4.4.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.core.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script> - <script type="text/javascript" src="../../../ui/jquery.ui.autocomplete.js"></script> - <script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script> <script type="text/javascript"> $(function() { $.fn.themeswitcher && $('<div/>').css({ @@ -17,39 +16,25 @@ top: 10 }).appendTo(document.body).themeswitcher(); - var menus = $("#menu1, #menu2").menu({ - selected: function(event, ui) { - $("<div/>").text("Selected: " + ui.item.text()).appendTo("#log"); - } - }).keydown(function(event) { - var menu = $(this).data("menu"); - if (menu.widget().is(":hidden")) - return; - event.stopPropagation(); - switch (event.keyCode) { - case $.ui.keyCode.PAGE_UP: - menu.previousPage(); - event.preventDefault(); - break; - case $.ui.keyCode.PAGE_DOWN: - menu.nextPage(); - event.preventDefault(); - break; - case $.ui.keyCode.UP: - menu.previous(); - event.preventDefault(); - break; - case $.ui.keyCode.DOWN: - menu.next(); - event.preventDefault(); - break; - case $.ui.keyCode.ENTER: - menu.select(); - event.preventDefault(); - break; - } - }); + function create() { + menus.menu({ + select: function(event, ui) { + $("<div/>").text("Selected: " + ui.item.text()).appendTo("#log"); + } + }); + } + + var menus = $("#menu1, #menu2"); + create(); + $("#toggle-destroy").toggle(function() { + menus.menu("destroy"); + }, create); + $("#toggle-disable").toggle(function() { + menus.menu("disable"); + }, function() { + menus.menu("enable"); + }); }); </script> <style> @@ -60,7 +45,7 @@ </head> <body> -<ul id="menu1" tabindex="0"> +<ul id="menu1"> <li><a href="#">Aberdeen</a></li> <li><a href="#">Ada</a></li> <li><a href="#">Adamsville</a></li> @@ -68,7 +53,7 @@ <li><a href="#">Adelphi</a></li> </ul> -<ul id="menu2" tabindex="0"> +<ul id="menu2"> <li><a href="#">Aberdeen</a></li> <li><a href="#">Ada</a></li> <li><a href="#">Adamsville</a></li> @@ -114,5 +99,8 @@ <div id="log" style="height: 400px; width: 300px; overflow: auto;" class="ui-widget-content"></div> </div> +<button id="toggle-disable">Disable / Enable</button> +<button id="toggle-destroy">Destroy / Create</button> + </body> </html> diff --git a/tests/visual/menu/menubar.html b/tests/visual/menu/menubar.html new file mode 100644 index 000000000..087365c42 --- /dev/null +++ b/tests/visual/menu/menubar.html @@ -0,0 +1,94 @@ +<!doctype html> +<html> +<head> + <title>Menu Visual Test: Default</title> + <link rel="stylesheet" href="../visual.css" type="text/css" /> + <link rel="stylesheet" href="../../../themes/base/jquery.ui.all.css" type="text/css" title="ui-theme" /> + <script type="text/javascript" src="../../../jquery-1.4.2.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.core.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.position.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.button.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script> + <script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script> + <script type="text/javascript"> + $(function() { + $.fn.themeswitcher && $('<div/>').css({ + position: "absolute", + right: 10, + top: 10 + }).appendTo(document.body).themeswitcher(); + + $(".menubar").children("a") + .button() + .click(function() { + var button = $(this); + var menu = button.next(); + if (menu.is(":visible")) { + menu.hide(); + return false; + } + menu.parent().find(".ui-menu").not(menu).hide(); + menu.show().css({ left:0, top: 0 }).position({ + my: "left top", + at: "left bottom", + of: button + }); + $(document).bind("click.menubar", function(event) { + if ($(event.target).closest(".ui-menu")[0] == menu[0]) { + return; + } + $(this).unbind(".menubar"); + menu.hide(); + }); + return false; + }) + .each(function() { + $(this).next().hide().menu({ + input: $(this), + select: function(event, ui) { + $("<div/>").text("Selected: " + ui.item.text()).appendTo("#log"); + } + }); + }); + + }); + </script> + <style> + body { font-size:62.5%; } + .ui-menu { width: 200px; } + .menubar .ui-menu { position: absolute; } + </style> +</head> +<body> + +<div class="menubar ui-widget-header"> + <a href="#">File</a> + <ul> + <li><a href="#">Open...</a></li> + <li><a href="#">Save</a></li> + <li><a href="#">Save as...</a></li> + <li><a href="#">Close</a></li> + <li><a href="#">Quit</a></li> + </ul> + <a href="#">Edit</a> + <ul> + <li><a href="#">Copy</a></li> + <li><a href="#">Cut</a></li> + <li><a href="#">Paste</a></li> + </ul> + <a href="#">View</a> + <ul> + <li><a href="#">Fullscreen</a></li> + <li><a href="#">Fit into view</a></li> + <li><a href="#">Customize...</a></li> + </ul> +</div> + +<div class="ui-widget" style="margin-top:2em; font-family:Arial"> + Log: + <div id="log" style="height: 400px; width: 300px; overflow: auto;" class="ui-widget-content"></div> +</div> + +</body> +</html> diff --git a/tests/visual/menu/nested.html b/tests/visual/menu/nested.html index c7f9a0914..2508c55c4 100644 --- a/tests/visual/menu/nested.html +++ b/tests/visual/menu/nested.html @@ -8,8 +8,8 @@ <script type="text/javascript" src="../../../ui/jquery.ui.core.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.position.js"></script> - <script type="text/javascript" src="../../../ui/jquery.ui.autocomplete.js"></script> - <script type="text/javascript" src="../../../external/jquery.bgiframe-2.1.2.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script> + <script type="text/javascript" src="../../../external/jquery.bgiframe-2.1.1.js"></script> <script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script> <script type="text/javascript"> $(function() { @@ -28,7 +28,9 @@ this.element.find("ul").hide().prev("a").prepend('<span class="ui-icon ui-icon-carat-1-e"></span>'); this.element.find("ul").andSelf().menu({ - selected: this.options.selected, + // disable built-in key handling + input: $(), + select: this.options.select, focus: function(event, ui) { self.active = ui.item.parent(); self.activeItem = ui.item; @@ -75,7 +77,7 @@ }); var nestedmenu = $("#menu").nestedmenu({ - selected: function(event, ui) { + select: function(event, ui) { $("#log").append("<div>Selected " + ui.item.text() + "</div>"); } }).hide(); diff --git a/tests/visual/position/position.html b/tests/visual/position/position.html index 80452bc81..11fb48d6e 100644 --- a/tests/visual/position/position.html +++ b/tests/visual/position/position.html @@ -9,7 +9,7 @@ <script type="text/javascript" src="../../../ui/jquery.ui.core.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.widget.js"></script> <script type="text/javascript" src="../../../ui/jquery.ui.position.js"></script> - <script type="text/javascript" src="../../../ui/jquery.ui.autocomplete.js"></script> + <script type="text/javascript" src="../../../ui/jquery.ui.menu.js"></script> <script type="text/javascript" src="http://jqueryui.com/themeroller/themeswitchertool/"></script> <script type="text/javascript"> $(function() { diff --git a/themes/base/jquery.ui.autocomplete.css b/themes/base/jquery.ui.autocomplete.css index ea370d63e..aab7e8d63 100644 --- a/themes/base/jquery.ui.autocomplete.css +++ b/themes/base/jquery.ui.autocomplete.css @@ -11,43 +11,3 @@ /* workarounds */ * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ - -/* - * jQuery UI Menu @VERSION - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Menu#theming - */ -.ui-menu { - list-style:none; - padding: 2px; - margin: 0; - display:block; - float: left; -} -.ui-menu .ui-menu { - margin-top: -3px; -} -.ui-menu .ui-menu-item { - margin:0; - padding: 0; - zoom: 1; - float: left; - clear: left; - width: 100%; -} -.ui-menu .ui-menu-item a { - text-decoration:none; - display:block; - padding:.2em .4em; - line-height:1.5; - zoom:1; -} -.ui-menu .ui-menu-item a.ui-state-hover, -.ui-menu .ui-menu-item a.ui-state-active { - font-weight: normal; - margin: -1px; -} diff --git a/themes/base/jquery.ui.base.css b/themes/base/jquery.ui.base.css index 62d17c7e2..34d2c8fc6 100644 --- a/themes/base/jquery.ui.base.css +++ b/themes/base/jquery.ui.base.css @@ -14,6 +14,7 @@ @import url("jquery.ui.button.css"); @import url("jquery.ui.datepicker.css"); @import url("jquery.ui.dialog.css"); +@import url("jquery.ui.menu.css"); @import url("jquery.ui.progressbar.css"); @import url("jquery.ui.resizable.css"); @import url("jquery.ui.selectable.css"); diff --git a/themes/base/jquery.ui.menu.css b/themes/base/jquery.ui.menu.css new file mode 100644 index 000000000..667518bff --- /dev/null +++ b/themes/base/jquery.ui.menu.css @@ -0,0 +1,37 @@ +/* + * jQuery UI Menu @VERSION + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + */ +.ui-menu { + list-style:none; + padding: 2px; + margin: 0; + display:block; +} +.ui-menu .ui-menu { + margin-top: -3px; +} +.ui-menu .ui-menu-item { + margin:0; + padding: 0; + zoom: 1; + width: 100%; +} +.ui-menu .ui-menu-item a { + text-decoration:none; + display:block; + padding:.2em .4em; + line-height:1.5; + zoom:1; +} +.ui-menu .ui-menu-item a { + font-weight: normal; +} +.ui-menu .ui-menu-item a.ui-state-hover, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} diff --git a/ui/jquery.ui.autocomplete.js b/ui/jquery.ui.autocomplete.js index 73d50ee6e..f48dc032a 100644 --- a/ui/jquery.ui.autocomplete.js +++ b/ui/jquery.ui.autocomplete.js @@ -11,6 +11,7 @@ * jquery.ui.core.js * jquery.ui.widget.js * jquery.ui.position.js + * jquery.ui.menu.js */ (function( $, undefined ) { @@ -158,6 +159,8 @@ $.widget( "ui.autocomplete", { }, 13); }) .menu({ + // custom key handling for now + input: $(), focus: function( event, ui ) { var item = ui.item.data( "item.autocomplete" ); if ( false !== self._trigger( "focus", event, { item: item } ) ) { @@ -167,7 +170,7 @@ $.widget( "ui.autocomplete", { } } }, - selected: function( event, ui ) { + select: function( event, ui ) { var item = ui.item.data( "item.autocomplete" ), previous = self.previous; @@ -417,187 +420,3 @@ $.extend( $.ui.autocomplete, { }); }( jQuery )); - -/* - * jQuery UI Menu (not officially released) - * - * This widget isn't yet finished and the API is subject to change. We plan to finish - * it for the next release. You're welcome to give it a try anyway and give us feedback, - * as long as you're okay with migrating your code later on. We can help with that, too. - * - * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * http://docs.jquery.com/UI/Menu - * - * Depends: - * jquery.ui.core.js - * jquery.ui.widget.js - */ -(function($) { - -$.widget("ui.menu", { - _create: function() { - var self = this; - this.element - .addClass("ui-menu ui-widget ui-widget-content ui-corner-all") - .attr({ - role: "listbox", - "aria-activedescendant": "ui-active-menuitem" - }) - .click(function( event ) { - if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) { - return; - } - // temporary - event.preventDefault(); - self.select( event ); - }); - this.refresh(); - }, - - refresh: function() { - var self = this; - - // don't refresh list items that are already adapted - var items = this.element.children("li:not(.ui-menu-item):has(a)") - .addClass("ui-menu-item") - .attr("role", "menuitem"); - - items.children("a") - .addClass("ui-corner-all") - .attr("tabindex", -1) - // mouseenter doesn't work with event delegation - .mouseenter(function( event ) { - self.activate( event, $(this).parent() ); - }) - .mouseleave(function() { - self.deactivate(); - }); - }, - - activate: function( event, item ) { - this.deactivate(); - if (this.hasScroll()) { - var offset = item.offset().top - this.element.offset().top, - scroll = this.element.attr("scrollTop"), - elementHeight = this.element.height(); - if (offset < 0) { - this.element.attr("scrollTop", scroll + offset); - } else if (offset >= elementHeight) { - this.element.attr("scrollTop", scroll + offset - elementHeight + item.height()); - } - } - this.active = item.eq(0) - .children("a") - .addClass("ui-state-hover") - .attr("id", "ui-active-menuitem") - .end(); - this._trigger("focus", event, { item: item }); - }, - - deactivate: function() { - if (!this.active) { return; } - - this.active.children("a") - .removeClass("ui-state-hover") - .removeAttr("id"); - this._trigger("blur"); - this.active = null; - }, - - next: function(event) { - this.move("next", ".ui-menu-item:first", event); - }, - - previous: function(event) { - this.move("prev", ".ui-menu-item:last", event); - }, - - first: function() { - return this.active && !this.active.prevAll(".ui-menu-item").length; - }, - - last: function() { - return this.active && !this.active.nextAll(".ui-menu-item").length; - }, - - move: function(direction, edge, event) { - if (!this.active) { - this.activate(event, this.element.children(edge)); - return; - } - var next = this.active[direction + "All"](".ui-menu-item").eq(0); - if (next.length) { - this.activate(event, next); - } else { - this.activate(event, this.element.children(edge)); - } - }, - - // TODO merge with previousPage - nextPage: function(event) { - if (this.hasScroll()) { - // TODO merge with no-scroll-else - if (!this.active || this.last()) { - this.activate(event, this.element.children(".ui-menu-item:first")); - return; - } - var base = this.active.offset().top, - height = this.element.height(), - result = this.element.children(".ui-menu-item").filter(function() { - var close = $(this).offset().top - base - height + $(this).height(); - // TODO improve approximation - return close < 10 && close > -10; - }); - - // TODO try to catch this earlier when scrollTop indicates the last page anyway - if (!result.length) { - result = this.element.children(".ui-menu-item:last"); - } - this.activate(event, result); - } else { - this.activate(event, this.element.children(".ui-menu-item") - .filter(!this.active || this.last() ? ":first" : ":last")); - } - }, - - // TODO merge with nextPage - previousPage: function(event) { - if (this.hasScroll()) { - // TODO merge with no-scroll-else - if (!this.active || this.first()) { - this.activate(event, this.element.children(".ui-menu-item:last")); - return; - } - - var base = this.active.offset().top, - height = this.element.height(); - result = this.element.children(".ui-menu-item").filter(function() { - var close = $(this).offset().top - base + height - $(this).height(); - // TODO improve approximation - return close < 10 && close > -10; - }); - - // TODO try to catch this earlier when scrollTop indicates the last page anyway - if (!result.length) { - result = this.element.children(".ui-menu-item:first"); - } - this.activate(event, result); - } else { - this.activate(event, this.element.children(".ui-menu-item") - .filter(!this.active || this.first() ? ":last" : ":first")); - } - }, - - hasScroll: function() { - return this.element.height() < this.element.attr("scrollHeight"); - }, - - select: function( event ) { - this._trigger("selected", event, { item: this.active }); - } -}); - -}(jQuery)); diff --git a/ui/jquery.ui.menu.js b/ui/jquery.ui.menu.js new file mode 100644 index 000000000..6381bedbc --- /dev/null +++ b/ui/jquery.ui.menu.js @@ -0,0 +1,249 @@ +/* + * jQuery UI Menu @VERSION + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Menu + * + * Depends: + * jquery.ui.core.js + * jquery.ui.widget.js + */ +(function($) { + +var idIncrement = 0; + +$.widget("ui.menu", { + _create: function() { + var self = this; + this.menuId = this.element.attr( "id" ) || "ui-menu-" + idIncrement++; + this.element + .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) + .attr({ + id: this.menuId, + role: "listbox" + }) + .bind( "click.menu", function( event ) { + if ( self.options.disabled ) { + return false; + } + if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) { + return; + } + // temporary + event.preventDefault(); + self.select( event ); + }) + .bind( "mouseover.menu", function( event ) { + if ( self.options.disabled ) { + return; + } + var target = $( event.target ).closest( ".ui-menu-item" ); + if ( target.length && target.parent()[0] === self.element[0] ) { + self.activate( event, target ); + } + }) + .bind("mouseout.menu", function( event ) { + if ( self.options.disabled ) { + return; + } + var target = $( event.target ).closest( ".ui-menu-item" ); + if ( target.length && target.parent()[0] === self.element[0] ) { + self.deactivate( event ); + } + }); + this.refresh(); + + if ( !this.options.input ) { + this.options.input = this.element.attr( "tabIndex", 0 ); + } + this.options.input.bind( "keydown.menu", function( event ) { + if ( self.options.disabled ) { + return; + } + switch ( event.keyCode ) { + case $.ui.keyCode.PAGE_UP: + self.previousPage(); + event.preventDefault(); + event.stopImmediatePropagation(); + break; + case $.ui.keyCode.PAGE_DOWN: + self.nextPage(); + event.preventDefault(); + event.stopImmediatePropagation(); + break; + case $.ui.keyCode.UP: + self.previous(); + event.preventDefault(); + event.stopImmediatePropagation(); + break; + case $.ui.keyCode.DOWN: + self.next(); + event.preventDefault(); + event.stopImmediatePropagation(); + break; + case $.ui.keyCode.ENTER: + self.select(); + event.preventDefault(); + event.stopImmediatePropagation(); + break; + } + }); + }, + + destroy: function() { + $.Widget.prototype.destroy.apply( this, arguments ); + + this.element + .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) + .removeAttr( "tabIndex" ) + .removeAttr( "role" ) + .removeAttr( "aria-activedescendant" ); + + this.element.children( ".ui-menu-item" ) + .removeClass( "ui-menu-item" ) + .removeAttr( "role" ) + .children( "a" ) + .removeClass( "ui-corner-all" ) + .removeAttr( "tabIndex" ) + .unbind( ".menu" ); + }, + + refresh: function() { + // don't refresh list items that are already adapted + var items = this.element.children( "li:not(.ui-menu-item):has(a)" ) + .addClass( "ui-menu-item" ) + .attr( "role", "menuitem" ); + + items.children( "a" ) + .addClass( "ui-corner-all" ) + .attr( "tabIndex", -1 ); + }, + + activate: function( event, item ) { + var self = this; + this.deactivate(); + if ( this._hasScroll() ) { + var borderTop = parseFloat( $.curCSS( this.element[0], "borderTopWidth", true) ) || 0, + paddingtop = parseFloat( $.curCSS( this.element[0], "paddingTop", true) ) || 0, + offset = item.offset().top - this.element.offset().top - borderTop - paddingtop, + scroll = this.element.attr( "scrollTop" ), + elementHeight = this.element.height(), + itemHeight = item.height(); + if ( offset < 0 ) { + this.element.attr( "scrollTop", scroll + offset ); + } else if ( offset + itemHeight > elementHeight ) { + this.element.attr( "scrollTop", scroll + offset - elementHeight + itemHeight ); + } + } + this.active = item.first() + .children( "a" ) + .addClass( "ui-state-hover" ) + .attr( "id", function(index, id) { + return (self.itemId = id || self.menuId + "-activedescendant"); + }) + .end(); + // need to remove the attribute before adding it for the screenreader to pick up the change + // see http://groups.google.com/group/jquery-a11y/msg/929e0c1e8c5efc8f + this.element.removeAttr("aria-activedescenant").attr("aria-activedescenant", self.itemId); + this._trigger( "focus", event, { item: item } ); + }, + + deactivate: function(event) { + if (!this.active) { + return; + } + + var self = this; + this.active.children( "a" ).removeClass( "ui-state-hover" ); + // remove only generated id + $( "#" + self.menuId + "-activedescendant" ).removeAttr( "id" ); + this.element.removeAttr( "aria-activedescenant" ); + this._trigger( "blur", event ); + this.active = null; + }, + + next: function(event) { + this._move( "next", ".ui-menu-item", "first", event ); + }, + + previous: function(event) { + this._move( "prev", ".ui-menu-item", "last", event ); + }, + + first: function() { + return this.active && !this.active.prevAll( ".ui-menu-item" ).length; + }, + + last: function() { + return this.active && !this.active.nextAll( ".ui-menu-item" ).length; + }, + + _move: function(direction, edge, filter, event) { + if ( !this.active ) { + this.activate( event, this.element.children(edge)[filter]() ); + return; + } + var next = this.active[ direction + "All" ]( ".ui-menu-item" ).eq( 0 ); + if ( next.length ) { + this.activate( event, next ); + } else { + this.activate( event, this.element.children(edge)[filter]() ); + } + }, + + nextPage: function( event ) { + if ( this._hasScroll() ) { + if ( !this.active || this.last() ) { + this.activate( event, this.element.children( ".ui-menu-item" ).first() ); + return; + } + var base = this.active.offset().top, + height = this.element.height(), + result; + this.active.nextAll( ".ui-menu-item" ).each( function() { + result = $( this ); + return $( this ).offset().top - base - height < 0; + }); + + this.activate( event, result ); + } else { + this.activate( event, this.element.children( ".ui-menu-item" ) + [ !this.active || this.last() ? "first" : "last" ]() ); + } + }, + + previousPage: function( event ) { + if ( this._hasScroll() ) { + if ( !this.active || this.first() ) { + this.activate( event, this.element.children( ".ui-menu-item" ).last() ); + return; + } + + var base = this.active.offset().top, + height = this.element.height(), + result; + this.active.prevAll( ".ui-menu-item" ).each( function() { + result = $( this ); + return $(this).offset().top - base + height > 0; + }); + + this.activate( event, result ); + } else { + this.activate( event, this.element.children( ".ui-menu-item" ) + [ !this.active || this.first() ? ":last" : ":first" ]() ); + } + }, + + _hasScroll: function() { + return this.element.height() < this.element.attr( "scrollHeight" ); + }, + + select: function( event ) { + this._trigger( "select", event, { item: this.active } ); + } +}); + +}( jQuery )); |