aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/tasks/testswarm.js4
-rw-r--r--demos/index.html1
-rw-r--r--demos/selectmenu/custom_render.html122
-rw-r--r--demos/selectmenu/default.html98
-rw-r--r--demos/selectmenu/images/24-podcast-square.pngbin0 -> 681 bytes
-rw-r--r--demos/selectmenu/images/24-rss-square.pngbin0 -> 594 bytes
-rw-r--r--demos/selectmenu/images/24-video-square.pngbin0 -> 649 bytes
-rw-r--r--demos/selectmenu/index.html15
-rw-r--r--grunt.js1
-rw-r--r--tests/unit/selectmenu/all.html30
-rw-r--r--tests/unit/selectmenu/selectmenu.html91
-rw-r--r--tests/unit/selectmenu/selectmenu_common.js21
-rw-r--r--tests/unit/selectmenu/selectmenu_core.js88
-rw-r--r--tests/unit/selectmenu/selectmenu_events.js108
-rw-r--r--tests/unit/selectmenu/selectmenu_methods.js144
-rw-r--r--tests/unit/selectmenu/selectmenu_options.js60
-rw-r--r--tests/visual/selectmenu/compatibility.html182
-rw-r--r--tests/visual/selectmenu/disabled_empty.html164
-rw-r--r--tests/visual/selectmenu/events_methods.html119
-rw-r--r--themes/base/jquery.ui.base.css1
-rw-r--r--themes/base/jquery.ui.selectmenu.css56
-rw-r--r--ui/jquery.ui.selectmenu.js466
22 files changed, 1770 insertions, 1 deletions
diff --git a/build/tasks/testswarm.js b/build/tasks/testswarm.js
index 8e88007bb..838751fc7 100644
--- a/build/tasks/testswarm.js
+++ b/build/tasks/testswarm.js
@@ -24,6 +24,7 @@ var versions = {
"Progressbar": "progressbar/progressbar.html",
"Resizable": "resizable/resizable.html",
"Selectable": "selectable/selectable.html",
+ "Selectmenu": "selectmenu/selectmenu.html",
"Slider": "slider/slider.html",
"Sortable": "sortable/sortable.html",
"Spinner": "spinner/spinner.html",
@@ -50,7 +51,8 @@ function submit( commit, tests, configFile, version, done ) {
}, {
authUsername: config.authUsername,
authToken: config.authToken,
- jobName: 'jQuery UI ' + version + '#<a href="https://github.com/jquery/jquery-ui/commit/' + commit + '">' + commit.substr( 0, 10 ) + '</a>',
+ // TODO don't merge this to master, or undo it
+ jobName: 'jQuery UI / Selectmenu ' + version + '#<a href="https://github.com/jquery/jquery-ui/commit/' + commit + '">' + commit.substr( 0, 10 ) + '</a>',
runMax: config.runMax,
"runNames[]": Object.keys( tests ),
"runUrls[]": testUrls,
diff --git a/demos/index.html b/demos/index.html
index 4739d76cd..338da841a 100644
--- a/demos/index.html
+++ b/demos/index.html
@@ -24,6 +24,7 @@
<li><a href="removeClass/">removeClass</a></li>
<li><a href="resizable/">resizable</a></li>
<li><a href="selectable/">selectable</a></li>
+ <li><a href="selectmenu/">selectmenu</a></li>
<li><a href="show/">show</a></li>
<li><a href="slider/">slider</a></li>
<li><a href="sortable/">sortable</a></li>
diff --git a/demos/selectmenu/custom_render.html b/demos/selectmenu/custom_render.html
new file mode 100644
index 000000000..c4fd2cd3b
--- /dev/null
+++ b/demos/selectmenu/custom_render.html
@@ -0,0 +1,122 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Selectmenu - Default functionality</title>
+ <link rel="stylesheet" href="../../themes/base/jquery.ui.all.css">
+ <script src="../../jquery-1.8.3.js"></script>
+ <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.selectmenu.js"></script>
+ <link rel="stylesheet" href="../demos.css">
+ <script>
+ $(function() {
+
+ $.widget( "custom.iconselectmenu", $.ui.selectmenu, {
+ _renderItem: function( ul, item ) {
+ var li = $( "<li>" ).data( "ui-selectmenu-item", item ),
+ element,
+ span;
+
+ if ( item.disabled ) {
+ li.addClass( "ui-state-disabled" ).text( item.label );
+ } else {
+ element = item.element;
+ span = $( "<span>", {
+ style: element.attr( "style" ),
+ 'class': "ui-icon " + element.attr( "class" )
+ });
+ $( "<a>", {
+ text: item.label,
+ href: '#'
+ }).append( span ).appendTo( li );
+ }
+
+ return li.appendTo( ul );
+ }
+ });
+
+ var files = $( "select#files" ).iconselectmenu();
+ files.iconselectmenu( "menuWidget" ).addClass( "ui-menu-icons" );
+
+ var filesB = $( "select#filesB" ).iconselectmenu();
+ filesB.iconselectmenu( "menuWidget" ).addClass( "ui-menu-icons customicons" );
+
+ var peopleA = $( "select#peopleA" ).iconselectmenu();
+ peopleA.iconselectmenu( "menuWidget").addClass( "ui-menu-icons avatar" );
+ });
+ </script>
+ <style>
+ form { margin: 100px 0 0 0 }
+ h2 { margin: 30px 0 0 0 }
+ fieldset { border: 0; }
+ label { display: block; }
+ select { width: 200px; }
+
+ .ui-selectmenu-menu .ui-menu .ui-icon { top: 0.4em; }
+ .ui-selectmenu-menu .ui-menu .ui-menu-item a { padding-left: 2em; }
+
+ /* select with custom icons */
+ .ui-selectmenu-menu .ui-menu.customicons .ui-menu-item a { padding: 0.5em 0 0.5em 3em; }
+ .ui-selectmenu-menu .ui-menu.customicons .ui-menu-item a .ui-icon { height: 24px; width: 24px; top: 0.2em;}
+ .ui-icon.video { background: url(images/24-video-square.png) 0 0 no-repeat; }
+ .ui-icon.podcast { background: url(images/24-podcast-square.png) 0 0 no-repeat; }
+ .ui-icon.rss { background: url(images/24-rss-square.png) 0 0 no-repeat; }
+
+ /* select with CSS avatar icons */
+ option.avatar { background-repeat: no-repeat !important; padding-left: 20px; }
+ .avatar .ui-icon { background-position: left top; }
+ </style>
+</head>
+<body>
+
+<div class="demo">
+
+<form action="#">
+
+ <h2>"popup" style with framework icons</h2>
+ <fieldset>
+ <label for="files">Select a File:</label>
+ <select name="files" id="files">
+ <option value="jquery" class="ui-icon-script">jQuery.js</option>
+ <option value="jquerylogo" class="ui-icon-image">jQuery Logo</option>
+ <option value="jqueryui" class="ui-icon-script">ui.jQuery.js</option>
+ <option value="jqueryuilogo" selected="selected" class="ui-icon-image">jQuery UI Logo</option>
+ <option value="somefile">Some unknown file</option>
+ </select>
+ </fieldset>
+
+ <h2>"popup" style with custom icon images</h2>
+ <fieldset>
+ <label for="filesB">Select a File:</label>
+ <select name="filesB" id="filesB">
+ <option value="mypodcast" class="podcast">John Resig Podcast</option>
+ <option value="myvideo" class="video">Scott Gonzales Video</option>
+ <option value="myrss" class="rss">jQuery RSS XML</option>
+ </select>
+ </fieldset>
+
+ <h2>"dropdown" style with custom avatar 16x16 images as CSS background</h2>
+ <fieldset>
+ <label for="peopleA">Select a Person:</label>
+ <select name="peopleA" id="peopleA">
+ <option value="1" class="avatar" style="background-image: url(http://www.gravatar.com/avatar/b3e04a46e85ad3e165d66f5d927eb609?d=monsterid&amp;r=g&amp;s=16);">John Resig</option>
+ <option value="2" class="avatar" style="background-image: url(http://www.gravatar.com/avatar/e42b1e5c7cfd2be0933e696e292a4d5f?d=monsterid&amp;r=g&amp;s=16);">Tauren Mills</option>
+ <option value="3" class="avatar" style="background-image: url(http://www.gravatar.com/avatar/bdeaec11dd663f26fa58ced0eb7facc8?d=monsterid&amp;r=g&amp;s=16);">Jane Doe</option>
+ </select>
+ </fieldset>
+
+</form>
+
+</div><!-- End demo -->
+
+
+
+<div class="demo-description">
+<p>The whole rendering process is extendable to make custom styling as easy as possible.</p>
+</div><!-- End demo-description -->
+
+</body>
+</html>
diff --git a/demos/selectmenu/default.html b/demos/selectmenu/default.html
new file mode 100644
index 000000000..20a2c6bc8
--- /dev/null
+++ b/demos/selectmenu/default.html
@@ -0,0 +1,98 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Selectmenu - Default functionality</title>
+ <link rel="stylesheet" href="../../themes/base/jquery.ui.all.css">
+ <script src="../../jquery-1.8.3.js"></script>
+ <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.selectmenu.js"></script>
+ <link rel="stylesheet" href="../demos.css">
+ <script>
+ $(function() {
+ $('#speed').selectmenu();
+
+ $('#files').selectmenu();
+
+ var withOverflow = $('#number').selectmenu();
+ withOverflow.selectmenu("menuWidget").addClass("overflow");
+ });
+ </script>
+ <style>
+ form { margin: 50px 0 0 0 }
+ fieldset { border: 0; }
+ label { display: block; }
+ select { width: 200px; }
+ .overflow { height: 200px; }
+ </style>
+</head>
+<body>
+
+<div class="demo">
+
+<form action="#">
+ <fieldset>
+ <label for="speed">Select a speed</label>
+ <select name="speed" id="speed">
+ <option value="Slower">Slower</option>
+ <option value="Slow">Slow</option>
+ <option value="Medium" selected="selected">Medium</option>
+ <option value="Fast">Fast</option>
+ <option value="Faster">Faster</option>
+ </select>
+ <br />
+ <br />
+ <br />
+ <label for="files">Select a file</label>
+ <select name="files" id="files">
+ <optgroup label="Scripts">
+ <option value="jquery">jQuery.js</option>
+ <option value="jqueryui">ui.jQuery.js</option>
+ </optgroup>
+ <optgroup label="Other files">
+ <option value="somefile">Some unknown file</option>
+ <option value="someotherfile">Some other file</option>
+ </optgroup>
+ </select>
+ <br />
+ <br />
+ <br />
+ <label for="number">Select a number</label>
+ <select name="number" id="number">
+ <option value="1">1</option>
+ <option value="2" selected="selected">2</option>
+ <option value="3">3</option>
+ <option value="4">4</option>
+ <option value="5">5</option>
+ <option value="6">6</option>
+ <option value="7">7</option>
+ <option value="8">8</option>
+ <option value="9">9</option>
+ <option value="10">10</option>
+ <option value="11">11</option>
+ <option value="12">12</option>
+ <option value="13">13</option>
+ <option value="14">14</option>
+ <option value="15">15</option>
+ <option value="16">16</option>
+ <option value="17">17</option>
+ <option value="18">18</option>
+ <option value="19">19</option>
+ </select>
+ </fieldset>
+</form>
+
+</div><!-- End demo -->
+
+
+
+<div class="demo-description">
+<p>The Selectmenu widgets provides a styleable select element replacement. It will act as a proxy back to the original select element, controlling its state for form submission or serialization </p>
+<p>The datasource is a native select element. Supports optgroups.</p>
+</div><!-- End demo-description -->
+
+</body>
+</html>
diff --git a/demos/selectmenu/images/24-podcast-square.png b/demos/selectmenu/images/24-podcast-square.png
new file mode 100644
index 000000000..3c3e38f3f
--- /dev/null
+++ b/demos/selectmenu/images/24-podcast-square.png
Binary files differ
diff --git a/demos/selectmenu/images/24-rss-square.png b/demos/selectmenu/images/24-rss-square.png
new file mode 100644
index 000000000..f59b69ed3
--- /dev/null
+++ b/demos/selectmenu/images/24-rss-square.png
Binary files differ
diff --git a/demos/selectmenu/images/24-video-square.png b/demos/selectmenu/images/24-video-square.png
new file mode 100644
index 000000000..ce50ccfde
--- /dev/null
+++ b/demos/selectmenu/images/24-video-square.png
Binary files differ
diff --git a/demos/selectmenu/index.html b/demos/selectmenu/index.html
new file mode 100644
index 000000000..ef7162c4d
--- /dev/null
+++ b/demos/selectmenu/index.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Selectmenu Demos</title>
+</head>
+<body>
+
+<ul>
+ <li><a href="default.html">Default functionality</a></li>
+ <li><a href="custom_render.html">Custom item rendering functionality</a></li>
+</ul>
+
+</body>
+</html>
diff --git a/grunt.js b/grunt.js
index d599496cc..1281bdbd2 100644
--- a/grunt.js
+++ b/grunt.js
@@ -35,6 +35,7 @@ var
"progressbar",
"resizable",
"selectable",
+ "selectmenu",
"slider",
"spinner",
"tabs",
diff --git a/tests/unit/selectmenu/all.html b/tests/unit/selectmenu/all.html
new file mode 100644
index 000000000..98ff533c7
--- /dev/null
+++ b/tests/unit/selectmenu/all.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Selectmenu Test Suite</title>
+
+ <script src="../../../jquery-1.8.3.js"></script>
+
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <link rel="stylesheet" href="../subsuiteRunner.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../subsuiteRunner.js"></script>
+ <script src="../subsuite.js"></script>
+
+ <script>
+ testAllVersions( "selectmenu" );
+ </script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Selectmenu Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+
+</div>
+</body>
+</html>
diff --git a/tests/unit/selectmenu/selectmenu.html b/tests/unit/selectmenu/selectmenu.html
new file mode 100644
index 000000000..8c1759892
--- /dev/null
+++ b/tests/unit/selectmenu/selectmenu.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Selectmenu Test Suite</title>
+
+ <script src="../../jquery.js"></script>
+ <link rel="stylesheet" href="../../../external/qunit.css">
+ <script src="../../../external/qunit.js"></script>
+ <script src="../../jquery.simulate.js"></script>
+ <script src="../testsuite.js"></script>
+ <script>
+ TestHelpers.loadResources({
+ css: [ "ui.core", "ui.menu" , "ui.selectmenu" ],
+ js: [
+ "ui/jquery.ui.core.js",
+ "ui/jquery.ui.widget.js",
+ "ui/jquery.ui.position.js",
+ "ui/jquery.ui.menu.js",
+ "ui/jquery.ui.selectmenu.js"
+ ]
+ });
+ </script>
+
+ <script src="selectmenu_common.js"></script>
+ <script src="selectmenu_core.js"></script>
+ <script src="selectmenu_events.js"></script>
+ <script src="selectmenu_methods.js"></script>
+ <script src="selectmenu_options.js"></script>
+
+ <script src="../swarminject.js"></script>
+</head>
+<body>
+
+<h1 id="qunit-header">jQuery UI Selectmenu Test Suite</h1>
+<h2 id="qunit-banner"></h2>
+<div id="qunit-testrunner-toolbar"></div>
+<h2 id="qunit-userAgent"></h2>
+<ol id="qunit-tests"></ol>
+<div id="qunit-fixture">
+ <div id="sm-wrap1" class="sm-wrap"></div>
+
+ <div id="sm-wrap2" class="sm-wrap">
+ <label for="speed">Select a speed:</label>
+ <select name="speed" id="speed">
+ <option value="Slower">Slower</option>
+ <option value="Slow">Slow</option>
+ <option value="Medium" selected="selected">Medium</option>
+ <option value="Fast">Fast</option>
+ <option value="Faster">Faster</option>
+ </select>
+ </div>
+
+ <label for="number">Select a number:</label>
+ <select name="number" id="number">
+ <option value="1">1</option>
+ <option value="2" selected="selected">2</option>
+ <option value="3">3</option>
+ <option value="4">4</option>
+ <option value="5">5</option>
+ <option value="6">6</option>
+ <option value="7">7</option>
+ <option value="8">8</option>
+ <option value="9">9</option>
+ <option value="10">10</option>
+ <option value="11">11</option>
+ <option value="12">12</option>
+ <option value="13">13</option>
+ <option value="14">14</option>
+ <option value="15">15</option>
+ <option value="16">16</option>
+ <option value="17">17</option>
+ <option value="18">18</option>
+ <option value="19">19</option>
+ </select>
+
+ <label for="files">Select a file:</label>
+ <select name="files" id="files">
+ <optgroup label="Scripts">
+ <option value="jquery">jQuery.js</option>
+ <option value="jqueryui">ui.jQuery.js</option>
+ </optgroup>
+ <optgroup label="Other files">
+ <option value="somefile">Some unknown file</option>
+ <option value="someotherfile">Some other file</option>
+ </optgroup>
+ </select>
+
+</div>
+</body>
+</html>
diff --git a/tests/unit/selectmenu/selectmenu_common.js b/tests/unit/selectmenu/selectmenu_common.js
new file mode 100644
index 000000000..af76aa581
--- /dev/null
+++ b/tests/unit/selectmenu/selectmenu_common.js
@@ -0,0 +1,21 @@
+TestHelpers.commonWidgetTests( "selectmenu", {
+ defaults: {
+ appendTo: null,
+ disabled: false,
+ icons: {
+ button: "ui-icon-triangle-1-s"
+ },
+ position: {
+ my: "left top",
+ at: "left bottom",
+ collision: "none"
+ },
+ // callbacks
+ create: null,
+ change: null,
+ close: null,
+ focus: null,
+ open: null,
+ select: null
+ }
+});
diff --git a/tests/unit/selectmenu/selectmenu_core.js b/tests/unit/selectmenu/selectmenu_core.js
new file mode 100644
index 000000000..f2cad56f3
--- /dev/null
+++ b/tests/unit/selectmenu/selectmenu_core.js
@@ -0,0 +1,88 @@
+(function( $ ) {
+
+module( "selectmenu: core" );
+
+test("accessibility", function () {
+ var links,
+ element = $("#speed").selectmenu(),
+ button = element.selectmenu("widget"),
+ menu = element.selectmenu("menuWidget");
+
+ button.simulate( "focus" );
+ links = menu.find("li.ui-menu-item a");
+
+ expect(13 + links.length * 2);
+
+ equal( button.attr("role"), "combobox", "button link role" );
+ equal( button.attr("aria-haspopup"), "true", "button link aria-haspopup" );
+ equal( button.attr("aria-expanded"), "false", "button link aria-expanded" );
+ equal( button.attr("aria-autocomplete"), "list", "button link aria-autocomplete" );
+ equal( button.attr("aria-owns"), menu.attr("id"), "button link aria-owns" );
+ equal( button.attr("aria-labelledby"), links.eq( element[0].selectedIndex ).attr( "id" ), "button link aria-labelledby" );
+ equal( button.attr("tabindex"), 0, "button link tabindex" );
+
+ equal( menu.attr("role"), "listbox", "menu role" );
+ equal( menu.attr("aria-labelledby"), button.attr("id"), "menu aria-labelledby" );
+ equal( menu.attr("aria-hidden"), "true", "menu aria-hidden" );
+ equal( menu.attr("tabindex"), 0, "menu tabindex" );
+ equal( menu.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "menu aria-activedescendant" );
+ $.each( links, function(index){
+ equal( $(this).attr("role"), "option", "menu link #" + index +" role" );
+ equal( $(this).attr("tabindex"), -1, "menu link #" + index +" tabindex" );
+ });
+ equal( links.eq(element[0].selectedIndex).attr("aria-selected"), "true", "selected menu link aria-selected" );
+});
+
+
+$.each([
+ {
+ type: "default",
+ selector: "#speed"
+ },
+ {
+ type: "optgroups",
+ selector: "#files"
+ }
+], function( i, settings ) {
+ test("state synchronization - after keydown - " + settings.type, function () {
+ expect(5);
+
+ var links,
+ element = $(settings.selector).selectmenu(),
+ button = element.selectmenu("widget"),
+ menu = element.selectmenu("menuWidget"),
+ selected = element.find("option:selected");
+
+ button.simulate( "focus" );
+ links = menu.find("li.ui-menu-item a");
+
+ button.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } );
+ equal( menu.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "menu aria-activedescendant" );
+ equal( links.eq(element[0].selectedIndex).attr("aria-selected"), "true", "selected menu link aria-selected" );
+ equal( button.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "button aria-activedescendant" );
+ equal( element.find("option:selected").val(), selected.next("option").val() , "original select state" );
+ equal( button.text(), selected.next("option").text(), "button text" );
+ });
+
+ test("state synchronization - after click - " + settings.type, function () {
+ expect(5);
+
+ var links,
+ element = $(settings.selector).selectmenu(),
+ button = element.selectmenu("widget"),
+ menu = element.selectmenu("menuWidget");
+
+ button.simulate( "focus" );
+ links = menu.find("li.ui-menu-item a");
+
+ button.simulate( "click" );
+ menu.find("a").last().simulate( "mouseover" ).trigger( "click" );
+ equal( menu.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "menu aria-activedescendant" );
+ equal( links.eq(element[0].selectedIndex).attr("aria-selected"), "true", "selected menu link aria-selected" );
+ equal( button.attr("aria-activedescendant"), links.eq(element[0].selectedIndex).attr("id"), "button aria-activedescendant" );
+ equal( element.find("option:selected").val(), element.find("option").last().val(), "original select state" );
+ equal( button.text(), element.find("option").last().text(), "button text" );
+ });
+});
+
+})( jQuery );
diff --git a/tests/unit/selectmenu/selectmenu_events.js b/tests/unit/selectmenu/selectmenu_events.js
new file mode 100644
index 000000000..167a6695f
--- /dev/null
+++ b/tests/unit/selectmenu/selectmenu_events.js
@@ -0,0 +1,108 @@
+(function ($) {
+
+module("selectmenu: events", {
+ setup: function () {
+ this.element = $("#speed");
+ }
+});
+
+test("change", function () {
+ expect(5);
+
+ this.element.selectmenu({
+ change: function (event, ui) {
+ ok(event, "change event fired on change");
+ equal(event.type, "selectmenuchange", "event type set to selectmenuchange");
+ ok(ui, "ui object is passed as second argument to event handler");
+ equal(ui.item.element[0].nodeName, "OPTION", "ui.item.element[0] points to original option element");
+ equal(ui.item.value, value, "ui.item.value property updated correctly");
+ }
+ });
+
+ var button = this.element.selectmenu("widget").parent(),
+ menu = this.element.selectmenu("menuWidget").parent(),
+ value = this.element.find("option").first().text();
+
+ button.find("a").simulate( "focus" ).simulate( "click" );
+ menu.find("a").first().simulate( "mouseover" ).trigger( "click" );
+});
+
+
+test("close", function () {
+ expect(3);
+
+ this.element.selectmenu({
+ close: function (event, ui) {
+ ok(event, "close event fired on close");
+ equal(event.type, "selectmenuclose", "event type set to selectmenuclose");
+ ok(ui, "ui object is passed as second argument to event handler");
+ }
+ });
+
+ this.element.selectmenu("open").selectmenu("close");
+});
+
+
+test("focus", function () {
+ expect(4);
+
+ var button,
+ menu,
+ links;
+
+ this.element.selectmenu({
+ focus: function (event, ui) {
+ ok(event, "focus event fired on mouseover");
+ equal(event.type, "selectmenufocus", "event type set to selectmenufocus");
+ ok(ui, "ui object is passed as second argument to event handler");
+ equal(ui.item.element[0].nodeName, "OPTION", "ui points to original option element");
+ }
+ });
+
+ button = this.element.selectmenu("widget"),
+ menu = this.element.selectmenu("menuWidget");
+
+ button.simulate( "focus" );
+ links = menu.find("li.ui-menu-item a");
+
+ button.simulate( "click" );
+
+ menu.find("a").last().simulate( "mouseover" );
+});
+
+
+test("open", function () {
+ expect(3);
+
+ this.element.selectmenu({
+ open: function (event, ui) {
+ ok(event, "open event fired on open");
+ equal(event.type, "selectmenuopen", "event type set to selectmenuopen");
+ ok(ui, "ui object is passed as second argument to event handler");
+ }
+ });
+
+ this.element.selectmenu("open");
+});
+
+
+test("select", function () {
+ expect(4);
+
+ this.element.selectmenu({
+ select: function (event, ui) {
+ ok(event, "select event fired on item select");
+ equal(event.type, "selectmenuselect", "event type set to selectmenuselect");
+ ok(ui, "ui object is passed as second argument to event handler");
+ equal(ui.item.element[0].nodeName, "OPTION", "ui points to original option element");
+ }
+ });
+
+ var button = this.element.selectmenu("widget").parent(),
+ menu = this.element.selectmenu("menuWidget").parent();
+
+ button.find("a").simulate( "focus" ).simulate( "click" );
+ menu.find("a").first().simulate( "mouseover" ).trigger("click");
+});
+
+})(jQuery);
diff --git a/tests/unit/selectmenu/selectmenu_methods.js b/tests/unit/selectmenu/selectmenu_methods.js
new file mode 100644
index 000000000..e8e62fa28
--- /dev/null
+++ b/tests/unit/selectmenu/selectmenu_methods.js
@@ -0,0 +1,144 @@
+(function( $ ) {
+
+module( "selectmenu: methods" );
+
+test( "destroy", function() {
+ expect( 1 );
+ domEqual( "#speed", function() {
+ $( "#speed" ).selectmenu().selectmenu( "destroy" );
+ });
+});
+
+
+test( "open / close", function() {
+ expect( 4 );
+
+ var element = $("#speed").selectmenu(),
+ menu = element.selectmenu("menuWidget");
+
+ element.selectmenu("open");
+ ok( menu.is( ":visible" ), "open: menu visible" );
+ equal( menu.attr("aria-hidden"), "false", "open: menu aria-disabled" );
+
+ element.selectmenu("close");
+ ok( menu.is( ":hidden" ), "close: menu hidden" );
+ equal( menu.attr("aria-hidden"), "true", "close: menu aria-disabled" );
+});
+
+
+test("enable / disable", function () {
+ expect(10);
+
+ var element = $("#speed").selectmenu(),
+ button = element.selectmenu("widget"),
+ menu = element.selectmenu("menuWidget");
+
+ element.selectmenu("disable");
+ ok( element.selectmenu("option", "disabled"), "disable: widget option" );
+ equal( element.attr("disabled"), "disabled", "disable: native select disabled" );
+ equal( button.attr("aria-disabled"), "true", "disable: button wrapper ARIA" );
+ equal( button.attr("tabindex"), -1, "disable: button tabindex" );
+ equal( menu.attr("aria-disabled"), "true", "disable: menu wrapper ARIA" );
+
+ element.selectmenu("enable");
+ ok( !element.selectmenu("option", "disabled"), "enable: widget option" );
+ equal( element.attr("disabled"), undefined, "enable: native select disabled" );
+ equal( button.attr("aria-disabled"), "false", "enable: button wrapper ARIA" );
+ equal( button.attr("tabindex"), 0, "enable: button tabindex" );
+ equal( menu.attr("aria-disabled"), "false", "enable: menu wrapper ARIA" );
+});
+
+
+test("refresh - structure", function () {
+ expect(3);
+
+ var element = $("#speed").selectmenu(),
+ menu = element.selectmenu("menuWidget").parent();
+
+ element.find("option").eq(2).remove();
+ element.find("option").eq(3).remove();
+ element.append("<option value=\"added_option\">Added option</option>");
+ element.find("option").first()
+ .attr("value", "changed_value")
+ .text("Changed value");
+ element.selectmenu("refresh");
+
+ equal( element.find("option").length, menu.find("li").not(".ui-selectmenu-optgroup").length, "menu item length" );
+ equal( element.find("option").last().text(), menu.find("li").not(".ui-selectmenu-optgroup").last().text(), "added item" );
+ equal( element.find("option").first().text(), menu.find("li").not(".ui-selectmenu-optgroup").first().text(), "changed item" );
+});
+
+
+test("refresh - disabled select", function () {
+ expect(4);
+
+ var element = $("#speed").selectmenu(),
+ button = element.selectmenu("widget"),
+ menu = element.selectmenu("menuWidget");
+
+ element.attr("disabled", "disabled");
+ element.selectmenu("refresh");
+
+ ok( element.selectmenu("option", "disabled"), "widget option" );
+ equal( button.attr("aria-disabled"), "true", "button wrapper ARIA" );
+ equal( button.attr("tabindex"), -1, "button tabindex" );
+ equal( menu.attr("aria-disabled"), "true", "menu wrapper ARIA" );
+});
+
+
+test("refresh - disabled option", function () {
+ expect(1);
+
+ var disabledItem,
+ element = $("#speed").selectmenu(),
+ menu = element.selectmenu("menuWidget").parent();
+
+ element.attr("disabled", "disabled");
+ element.find("option").eq(2).attr("disabled", "disabled");
+ element.selectmenu("refresh");
+
+ disabledItem = menu.find("li").not(".ui-selectmenu-optgroup").eq(2);
+ ok( disabledItem.hasClass("ui-state-disabled"), "class" );
+});
+
+
+test("refresh - disabled optgroup", function () {
+
+ var i,
+ item,
+ element = $("#files").selectmenu(),
+ menu = element.selectmenu("menuWidget").parent(),
+ originalDisabledOptgroup = element.find("optgroup").first(),
+ originalDisabledOptions = originalDisabledOptgroup.find("option");
+
+ expect(2 + originalDisabledOptions.length);
+
+ originalDisabledOptgroup.attr("disabled", "disabled");
+ element.selectmenu("refresh");
+
+ item = menu.find("li.ui-selectmenu-optgroup").first();
+ ok( item.hasClass("ui-state-disabled"), "class" );
+
+ equal( menu.find("li").not(".ui-selectmenu-optgroup").filter(".ui-state-disabled").length, originalDisabledOptions.length, "disabled options" );
+ for ( i = 0; i < originalDisabledOptions.length; i++ ) {
+ item = item.next("li");
+ ok( item.hasClass("ui-state-disabled"), "item #" + i + ": class" );
+ }
+});
+
+test( "widget", function() {
+ expect( 4 );
+ var element = $("#speed").selectmenu(),
+ widgetElement = element.selectmenu( "widget" ),
+ menuWidgetElement = element.selectmenu( "menuWidget" );
+
+ element.selectmenu("refresh");
+
+ equal( widgetElement.length, 1, "widget: one element" );
+ ok( widgetElement.is("a.ui-button"), "widget: button element" );
+
+ equal( menuWidgetElement.length, 1, "menuWidget: one element" );
+ ok( menuWidgetElement.is("ul.ui-menu"), "menuWidget: menu element" );
+});
+
+})( jQuery );
diff --git a/tests/unit/selectmenu/selectmenu_options.js b/tests/unit/selectmenu/selectmenu_options.js
new file mode 100644
index 000000000..ea40ebe00
--- /dev/null
+++ b/tests/unit/selectmenu/selectmenu_options.js
@@ -0,0 +1,60 @@
+(function ($) {
+
+module("selectmenu: options");
+
+test("appendTo another element", function () {
+ expect( 8 );
+
+ var detached = $( "<div>" ),
+ element = $("#speed").selectmenu();
+ equal( element.selectmenu( "menuWidget" ).parent().parent()[0], document.body, "defaults to body" );
+ element.selectmenu( "destroy" );
+
+ element.selectmenu({
+ appendTo: ".sm-wrap"
+ });
+ equal( element.selectmenu( "menuWidget" ).parent().parent()[0], $( "#sm-wrap1" )[0], "first found element" );
+ equal( $( "#sm-wrap2 .ui-selectmenu" ).length, 0, "only appends to one element" );
+ element.selectmenu( "destroy" );
+
+ $( "#sm-wrap2" ).addClass( "ui-front" );
+ element.selectmenu();
+ equal( element.selectmenu( "menuWidget" ).parent().parent()[0], $( "#sm-wrap2" )[0], "null, inside .ui-front" );
+ element.selectmenu( "destroy" );
+ $( "#sm-wrap2" ).removeClass( "ui-front" );
+
+ element.selectmenu().selectmenu( "option", "appendTo", "#sm-wrap1" );
+ equal( element.selectmenu( "menuWidget" ).parent().parent()[0], $( "#sm-wrap1" )[0], "modified after init" );
+ element.selectmenu( "destroy" );
+
+ element.selectmenu({
+ appendTo: detached
+ });
+ equal( element.selectmenu( "menuWidget" ).parent().parent()[0], detached[0], "detached jQuery object" );
+ element.selectmenu( "destroy" );
+
+ element.selectmenu({
+ appendTo: detached[0]
+ });
+ equal( element.selectmenu( "menuWidget" ).parent().parent()[0], detached[0], "detached DOM element" );
+ element.selectmenu( "destroy" );
+
+ element.selectmenu().selectmenu( "option", "appendTo", detached );
+ equal( element.selectmenu( "menuWidget" ).parent().parent()[0], detached[0], "detached DOM element via option()" );
+ element.selectmenu( "destroy" );
+});
+
+
+test("CSS styles", function () {
+ expect(2);
+
+ var element = $("#speed").selectmenu(),
+ button = element.selectmenu("widget"),
+ menu = element.selectmenu("menuWidget");
+
+ element.selectmenu("open");
+ ok( button.hasClass("ui-corner-top") && !button.hasClass("ui-corner-all") && button.find("span.ui-icon").hasClass("ui-icon-triangle-1-s"), "button styles dropdown");
+ ok( menu.hasClass("ui-corner-bottom") && !menu.hasClass("ui-corner-all"), "menu styles dropdown");
+});
+
+})(jQuery);
diff --git a/tests/visual/selectmenu/compatibility.html b/tests/visual/selectmenu/compatibility.html
new file mode 100644
index 000000000..6210aa293
--- /dev/null
+++ b/tests/visual/selectmenu/compatibility.html
@@ -0,0 +1,182 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Selectmenu - Compatibility with other widgets</title>
+ <link rel="stylesheet" href="../../../themes/base/jquery.ui.all.css">
+ <script src="../../jquery-1.8.3.js"></script>
+ <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.tabs.js"></script>
+ <script src="../../../ui/jquery.ui.dialog.js"></script>
+ <script src="../../../ui/jquery.ui.autocomplete.js"></script>
+ <script src="../../../ui/jquery.ui.button.js"></script>
+ <script src="../../../ui/jquery.ui.menu.js"></script>
+ <script src="../../../ui/jquery.ui.selectmenu.js"></script>
+ <link rel="stylesheet" href="../../../demos/demos.css">
+ <script>
+ $(function() {
+ var availableTags = [
+ "ActionScript",
+ "AppleScript",
+ "Asp",
+ "BASIC",
+ "C",
+ "C++",
+ "Clojure",
+ "COBOL",
+ "ColdFusion",
+ "Erlang",
+ "Fortran",
+ "Groovy",
+ "Haskell",
+ "Java",
+ "JavaScript",
+ "Lisp",
+ "Perl",
+ "PHP",
+ "Python",
+ "Ruby",
+ "Scala",
+ "Scheme"
+ ];
+ $( "#tags" ).autocomplete({
+ source: availableTags
+ });
+ $( "#tabs" ).tabs();
+ $( "#dialog" ).dialog();
+ $( "#menu" ).menu({
+ position: { of: "ul:has(a.ui-state-focus):last" },
+ icons: {
+ submenu: "ui-icon-carat-1-e"
+ }
+ });
+
+ $('select').selectmenu();
+ });
+ </script>
+ <style>
+ .demo { width: 400px }
+ form { margin: 20px 0 0 0 }
+ fieldset { border: 0; }
+ label { display: block; }
+ select { width: 200px; }
+ #tabs { margin: 50px 0 0 0 }
+ #menu { width: 150px; margin: 50px 0 0 0 }
+ </style>
+</head>
+<body>
+
+<div class="demo">
+
+<div class="ui-widget">
+ <label for="tags">Tags: </label>
+ <input id="tags">
+</div>
+
+
+<ul id="menu">
+ <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="#">Delphi</a>
+ <ul>
+ <li><a href="#">Ada</a></li>
+ <li><a href="#">Saarland</a></li>
+ <li><a href="#">Salzburg</a></li>
+ </ul>
+ </li>
+ <li><a href="#">Saarland</a></li>
+ <li>
+ <a href="#">Salzburg</a>
+ <ul>
+ <li>
+ <a href="#">Delphi</a>
+ <ul>
+ <li><a href="#">Ada</a></li>
+ <li><a href="#">Saarland</a></li>
+ <li><a href="#">Salzburg</a></li>
+ </ul>
+ </li>
+ <li>
+ <a href="#">Adamsville</a>
+ <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="#">Delphi</a>
+ <ul>
+ <li><a href="#">Ada</a></li>
+ <li><a href="#">Saarland</a></li>
+ <li><a href="#">Salzburg</a></li>
+ </ul>
+ </li>
+ <li><a href="#">Saarland</a></li>
+ </ul>
+ </li>
+ <li><a href="#">Perch</a>
+ <ul>
+ <li><a href="#">Addyston</a></li>
+ <li><a href="#">Delphi</a></li>
+ <li><a href="#">Perch</a></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+
+<div id="tabs">
+ <ul>
+ <li><a href="#tabs-1">Nunc tincidunt</a></li>
+ <li><a href="#tabs-2">Selectmenu</a></li>
+ <li><a href="#tabs-3">Aenean lacinia</a></li>
+ </ul>
+ <div id="tabs-1">
+ <p>Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.</p>
+ </div>
+ <div id="tabs-2">
+ <form action="#">
+ <fieldset>
+ <label for="speed1">Select a speed:</label>
+ <select name="speed1" id="speed1">
+ <option value="Slower">Slower</option>
+ <option value="Slow">Slow</option>
+ <option value="Medium" selected="selected">Medium</option>
+ <option value="Fast">Fast</option>
+ <option value="Faster">Faster</option>
+ </select>
+ </fieldset>
+ </form>
+ </div>
+ <div id="tabs-3">
+ <p>Mauris eleifend est et turpis. Duis id erat. Suspendisse potenti. Aliquam vulputate, pede vel vehicula accumsan, mi neque rutrum erat, eu congue orci lorem eget lorem. Vestibulum non ante. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce sodales. Quisque eu urna vel enim commodo pellentesque. Praesent eu risus hendrerit ligula tempus pretium. Curabitur lorem enim, pretium nec, feugiat nec, luctus a, lacus.</p>
+ <p>Duis cursus. Maecenas ligula eros, blandit nec, pharetra at, semper at, magna. Nullam ac lacus. Nulla facilisi. Praesent viverra justo vitae neque. Praesent blandit adipiscing velit. Suspendisse potenti. Donec mattis, pede vel pharetra blandit, magna ligula faucibus eros, id euismod lacus dolor eget odio. Nam scelerisque. Donec non libero sed nulla mattis commodo. Ut sagittis. Donec nisi lectus, feugiat porttitor, tempor ac, tempor vitae, pede. Aenean vehicula velit eu tellus interdum rutrum. Maecenas commodo. Pellentesque nec elit. Fusce in lacus. Vivamus a libero vitae lectus hendrerit hendrerit.</p>
+ </div>
+</div>
+
+<div id="dialog" title="Basic dialog">
+ <p>Some example content</p>
+ <p><a href="#nogo">Test Link</a></p>
+ <form action="#">
+ <fieldset>
+ <label for="speed2">Select a speed:</label>
+ <select name="speed2" id="speed2">
+ <option value="Slower">Slower</option>
+ <option value="Slow">Slow</option>
+ <option value="Medium" selected="selected">Medium</option>
+ <option value="Fast">Fast</option>
+ <option value="Faster">Faster</option>
+ </select>
+ </fieldset>
+ </form>
+</div>
+
+</div><!-- End demo -->
+
+</body>
+</html>
diff --git a/tests/visual/selectmenu/disabled_empty.html b/tests/visual/selectmenu/disabled_empty.html
new file mode 100644
index 000000000..e7a9e9fb2
--- /dev/null
+++ b/tests/visual/selectmenu/disabled_empty.html
@@ -0,0 +1,164 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Selectmenu - Disabled & empty elements functionality</title>
+ <link rel="stylesheet" href="../../../themes/base/jquery.ui.all.css">
+ <script src="../../jquery-1.8.3.js"></script>
+ <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.selectmenu.js"></script>
+ <link rel="stylesheet" href="../../../demos/demos.css">
+ <script>
+ $(function() {
+ /* disabled */
+ $('select#disabled1').selectmenu();
+ var withOverflow = $('select#disabled2').selectmenu();
+ withOverflow.selectmenu("menuWidget").addClass("overflow");
+ $('select#disabled3').selectmenu();
+ var disabled4 = $('select#disabled4').selectmenu();
+
+ $("#disable_select").toggle( function() {
+ disabled4.selectmenu("disable");
+ }, function() {
+ disabled4.removeAttr("disabled");
+ disabled4.selectmenu("refresh");
+ });
+ $("#disable_option").toggle( function() {
+ disabled4.find("option:eq(0)").attr("disabled", "disabled");
+ disabled4.selectmenu("refresh");
+ }, function() {
+ disabled4.find("option:eq(0)").removeAttr("disabled");
+ disabled4.selectmenu("refresh");
+ });
+ $("#disable_optgroup").toggle( function() {
+ disabled4.find("optgroup:eq(0)").attr("disabled", "disabled");
+ disabled4.selectmenu("refresh");
+ }, function() {
+ disabled4.find("optgroup:eq(0)").removeAttr("disabled");
+ disabled4.selectmenu("refresh");
+ });
+
+ /* empty */
+ $('select.empty').selectmenu();
+ });
+ </script>
+ <style>
+ fieldset { border: 0; }
+ label { display: block; }
+ select { width: 200px; }
+ .overflow { height: 200px; }
+ </style>
+</head>
+<body>
+
+<div class="demo">
+
+<form action="#">
+ <h2>Disabled tests</h2>
+ <fieldset>
+ <label for="disabled1">Select a speed:</label>
+ <select disabled="disabled" name="disabled1" id="disabled1">
+ <option value="Slower">Slower</option>
+ <option value="Slow">Slow</option>
+ <option value="Medium" selected="selected">Medium</option>
+ <option value="Fast">Fast</option>
+ <option value="Faster">Faster</option>
+ </select>
+ <br />
+ <br />
+ <label for="disabled2">Select a number:</label>
+ <select name="disabled2" id="disabled2">
+ <option value="1">1</option>
+ <option value="2" selected="selected">2</option>
+ <option value="3">3</option>
+ <option disabled="disabled" value="4">4</option>
+ <option value="5">5</option>
+ <option value="6">6</option>
+ <option value="7">7</option>
+ <option disabled="disabled" value="8">8</option>
+ <option value="9">9</option>
+ <option value="10">10</option>
+ <option disabled="disabled" value="11">11</option>
+ <option value="12">12</option>
+ <option value="13">13</option>
+ <option disabled="disabled" value="14">14</option>
+ <option disabled="disabled" value="15">15</option>
+ <option value="16">16</option>
+ <option value="17">17</option>
+ <option value="18">18</option>
+ <option value="19">19</option>
+ </select>
+ <br />
+ <br />
+ <label for="disabled3">Select a file:</label>
+ <select name="disabled3" id="disabled3">
+ <optgroup disabled="disabled" label="Scripts">
+ <option value="jquery">jQuery.js</option>
+ <option value="jqueryui">ui.jQuery.js</option>
+ </optgroup>
+ <optgroup label="Other files">
+ <option value="somefile">Some unknown file</option>
+ <option value="someotherfile">Some other file</option>
+ </optgroup>
+ </select>
+ <br />
+ <br />
+ <label for="disabled4">Select a file:</label>
+ <select name="disabled4" id="disabled4">
+ <optgroup label="Scripts">
+ <option value="jquery">jQuery.js</option>
+ <option value="jqueryui">ui.jQuery.js</option>
+ </optgroup>
+ <optgroup label="Other files">
+ <option value="somefile">Some unknown file</option>
+ <option value="someotherfile">Some other file</option>
+ </optgroup>
+ </select>
+ <button id="disable_select">Toggle disable select</button>
+ <button id="disable_option">Toggle disable option</button>
+ <button id="disable_optgroup">Toggle disable optgroup</button>
+ </fieldset>
+ <br />
+ <h2>Empty tests</h2>
+ <fieldset>
+ <select name="speed1" class="empty"></select>
+ <br />
+ <br />
+ <select name="speed2" class="empty">
+ <option value=""></option>
+ </select>
+ <br />
+ <br />
+ <select name="number" class="empty">
+ <option value="1">1</option>
+ <option value="2" selected="selected">2</option>
+ <option value="3">3</option>
+ <option value="4">4</option>
+ <option value=""></option>
+ <option value="6">6</option>
+ <option value="7">7</option>
+ <option value=""></option>
+ <option value="9">9</option>
+ </select>
+ <br />
+ <br />
+ <select name="files" class="empty">
+ <optgroup label="Scripts"></optgroup>
+ <optgroup label="Other files">
+ <option value="somefile">Some unknown file</option>
+ <option value="someotherfile">Some other file</option>
+ </optgroup>
+ </select>
+ </fieldset>
+</form>
+<br />
+
+</div><!-- End demo -->
+
+
+
+</body>
+</html>
diff --git a/tests/visual/selectmenu/events_methods.html b/tests/visual/selectmenu/events_methods.html
new file mode 100644
index 000000000..2829337b4
--- /dev/null
+++ b/tests/visual/selectmenu/events_methods.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8">
+ <title>jQuery UI Selectmenu - Events & methods functionality</title>
+ <link rel="stylesheet" href="../../../themes/base/jquery.ui.all.css">
+ <script src="../../jquery-1.8.3.js"></script>
+ <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.selectmenu.js"></script>
+ <link rel="stylesheet" href="../../../demos/demos.css">
+ <script>
+ $(function() {
+ var log = $("#log"),
+ index = 0;
+
+ var mySelectmenu = $('select').selectmenu({
+ open: function(event, ui) {
+ $("<div/>").text( index++ + " Opened").prependTo(log);
+ },
+ close: function(event, ui) {
+ $("<div/>").text( index++ + " Closed").prependTo(log);
+ },
+ focus : function(event, ui) {
+ $("<div/>").text( index++ + " Focused: " + ui.item.label + " #" + ui.item.index ).prependTo(log);
+ },
+ select: function(event, ui) {
+ $("<div/>").text( index++ + " Selected: " + ui.item.label + " #" + ui.item.index ).prependTo(log);
+ },
+ change: function(event, ui) {
+ $("<div/>").text( index++ + " Changed to: " + ui.item.label + " #" + ui.item.index ).prependTo(log);
+ }
+ });
+ $('select').show();
+
+ $("#destroy").click( function() {
+ mySelectmenu.selectmenu("destroy");
+ return false;
+ });
+
+ $("#refresh_add").click( function() {
+ mySelectmenu.append('<option value="fastsound">Faster than sound</option>');
+ mySelectmenu.selectmenu("refresh");
+ return false;
+ });
+
+ $("#refresh_selected").click( function() {
+ mySelectmenu[0].selectedIndex = 0;
+ mySelectmenu.selectmenu("refresh");
+ return false;
+ });
+
+ $("#refresh").click( function() {
+ mySelectmenu.selectmenu("refresh");
+ return false;
+ });
+
+ $("#open").click( function() {
+ mySelectmenu.selectmenu("open");
+ return false;
+ });
+
+ $("#close").click( function() {
+ mySelectmenu.selectmenu("close");
+ return false;
+ });
+ });
+ </script>
+ <style>
+ form { margin: 20px 0 0 0 }
+ fieldset { border: 0; }
+ label { display: block; }
+ select { width: 200px; }
+
+ #log { height: 400px; width: 270px; overflow: auto; }
+ #control { margin-left: 300px; }
+ #control fieldset { border: 0; width: 270px; }
+ #control button { display: block; }
+ </style>
+</head>
+<body>
+
+<div class="demo">
+
+
+<div style="float: left;">
+ Log:
+ <div id="log" class="ui-widget-content"></div>
+</div>
+
+<div id="control">
+ <form action="#">
+ <fieldset>
+ <label for="speed">Select a speed:</label>
+ <select name="speed" id="speed">
+ <option value="Slower">Slower</option>
+ <option value="Slow">Slow</option>
+ <option value="Medium" selected="selected">Medium</option>
+ <option value="Fast">Fast</option>
+ <option value="Faster">Faster</option>
+ </select>
+ </fieldset>
+ <button id="destroy">Destroy</button>
+ <button id="refresh_add">Add item</button>
+ <button id="refresh">Refresh</button>
+ <button id="refresh_selected">Change to first item</button>
+ <button id="open">Open</button>
+ <button id="close">Close</button>
+ </form>
+</div>
+
+</div><!-- End demo -->
+
+
+
+</body>
+</html>
diff --git a/themes/base/jquery.ui.base.css b/themes/base/jquery.ui.base.css
index 29dad37d1..752dd9715 100644
--- a/themes/base/jquery.ui.base.css
+++ b/themes/base/jquery.ui.base.css
@@ -19,6 +19,7 @@
@import url("jquery.ui.progressbar.css");
@import url("jquery.ui.resizable.css");
@import url("jquery.ui.selectable.css");
+@import url("jquery.ui.selectmenu.css");
@import url("jquery.ui.slider.css");
@import url("jquery.ui.spinner.css");
@import url("jquery.ui.tabs.css");
diff --git a/themes/base/jquery.ui.selectmenu.css b/themes/base/jquery.ui.selectmenu.css
new file mode 100644
index 000000000..c8099ea8f
--- /dev/null
+++ b/themes/base/jquery.ui.selectmenu.css
@@ -0,0 +1,56 @@
+/*!
+ * jQuery UI Selectmenu @VERSION
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectmenu#theming
+ */
+.ui-selectmenu-menu {
+ padding: 0;
+ margin: 0;
+ position:absolute;
+ top: 0;
+ display: none;
+}
+.ui-selectmenu-menu ul.ui-menu {
+ overflow: auto;
+ overflow-y: auto ;
+ overflow-x: hidden;
+}
+.ui-selectmenu-menu .ui-menu .ui-menu-item a {
+ padding: 0.3em 1em 0.3em 1em;
+}
+.ui-selectmenu-menu .ui-menu li.ui-selectmenu-optgroup {
+ font-size: 1em;
+ font-weight: bold;
+ line-height: 1.5;
+ padding: 2px 0.4em;
+ margin: 0.5em 0 0 0;
+ height: auto;
+ border: 0;
+}
+.ui-selectmenu-open {
+ display: block;
+}
+.ui-selectmenu-button a.ui-button {
+ display: inline-block;
+ overflow: hidden;
+ position: relative;
+ text-decoration: none;
+}
+.ui-selectmenu-button span.ui-icon {
+ right: 0.5em;
+ left: auto;
+ margin-top: -8px;
+ position: absolute;
+ top: 50%;
+}
+.ui-selectmenu-button span.ui-selectmenu-text {
+ text-align: left;
+ padding: 0.4em 2.1em 0.4em 1em;
+ display: block;
+ line-height: 1.4;
+} \ No newline at end of file
diff --git a/ui/jquery.ui.selectmenu.js b/ui/jquery.ui.selectmenu.js
new file mode 100644
index 000000000..0b6922412
--- /dev/null
+++ b/ui/jquery.ui.selectmenu.js
@@ -0,0 +1,466 @@
+/*!
+ * jQuery UI Selectmenu @VERSION
+ * http://jqueryui.com
+ *
+ * Copyright 2012 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/selectmenu
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.position.js
+ * jquery.ui.menu.js
+ */
+(function( $, undefined ) {
+
+$.widget( "ui.selectmenu", {
+ version: "@VERSION",
+ defaultElement: "<select>",
+ options: {
+ appendTo: null,
+ icons: {
+ button: "ui-icon-triangle-1-s"
+ },
+ position: {
+ my: "left top",
+ at: "left bottom",
+ collision: "none"
+ },
+
+ // callbacks
+ change: null,
+ close: null,
+ focus: null,
+ open: null,
+ select: null
+ },
+
+ _create: function() {
+ var selectmenuId = this.element.uniqueId().attr( "id" );
+ this.ids = { id: selectmenuId, button: selectmenuId + "-button", menu: selectmenuId + "-menu" };
+
+ this._drawButton();
+ this._drawMenu();
+
+ this._on( document, this._documentClick );
+
+ if ( this.options.disabled ) {
+ this.disable();
+ }
+ },
+
+ _drawButton: function() {
+ var tabindex = this.element.attr( "tabindex" );
+
+ // fix existing label
+ this.label = $( "label[for='" + this.ids.id + "']" ).attr( "for", this.ids.button );
+ this._on( this.label, {
+ "click": function( event ) {
+ this.button.focus();
+ event.preventDefault();
+ }
+ });
+
+ // hide original select tag
+ this.element.hide();
+
+ // create button
+ this.button = $( "<a>", {
+ "class": "ui-button ui-widget ui-state-default ui-corner-all",
+ href: "#" + this.ids.id,
+ tabindex: ( tabindex ? tabindex : this.options.disabled ? -1 : 0 ),
+ id: this.ids.button,
+ width: this.element.outerWidth(),
+ role: "combobox",
+ "aria-expanded": false,
+ "aria-autocomplete": "list",
+ "aria-owns": this.ids.menu,
+ "aria-haspopup": true
+ });
+
+ this.button.prepend( $( "<span>", {
+ "class": "ui-icon " + this.options.icons.button
+ }));
+
+ this.buttonText = $( "<span>", {
+ "class": "ui-selectmenu-text"
+ })
+ .appendTo( this.button );
+ this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
+
+ // wrap and insert new button
+ this.buttonWrap = $( "<span>", {
+ "class": "ui-selectmenu-button"
+ })
+ .append( this.button )
+ .insertAfter( this.element );
+
+ this._on( this.button, this._buttonEvents );
+ this._hoverable( this.button );
+ this._focusable( this.button );
+ },
+
+ _drawMenu: function() {
+ var menuInstance,
+ that = this;
+
+ // create menu portion, append to body
+ this.menu = $( "<ul>", {
+ "aria-hidden": true,
+ "aria-labelledby": this.ids.button,
+ id: this.ids.menu
+ });
+
+ // wrap menu
+ this.menuWrap = $( "<div>", {
+ "class": "ui-selectmenu-menu",
+ width: this.button.outerWidth()
+ })
+ .append( this.menu )
+ .appendTo( this._appendTo() );
+
+ // init menu widget
+ menuInstance = this.menu.menu({
+ select: function( event, ui ) {
+ var item = ui.item.data( "ui-selectmenu-item" );
+
+ that._select( item, event );
+
+ if ( that.isOpen ) {
+ event.preventDefault();
+ that.close( event );
+ }
+ },
+ focus: function( event, ui ) {
+ var item = ui.item.data( "ui-selectmenu-item" );
+ // prevent inital focus from firing and checks if its a newly focused item
+ if ( that.focus !== undefined && item.index !== that.focus ) {
+ that._trigger( "focus", event, { item: item } );
+ if ( !that.isOpen ) {
+ that._select( item, event );
+ }
+ }
+ that.focus = item.index;
+
+ // Set ARIA active descendant
+ that.button.attr( "aria-activedescendant", that.menuItems.eq( item.index ).find( "a" ).attr( "id" ) );
+ },
+ // set ARIA role
+ role: "listbox"
+ })
+ .data( "ui-menu" );
+
+ // adjust border radius
+ this.menu.addClass( "ui-corner-bottom" ).removeClass( "ui-corner-all" );
+
+ // make sure focus stays on selected item
+ menuInstance.delay = 999999999;
+ // unbind uneeded Menu events
+ menuInstance._off( this.menu, "mouseleave" );
+ },
+
+ refresh: function() {
+ this.menu.empty();
+
+ var item,
+ options = this.element.find( "option" );
+ if ( options.length ) {
+ this._readOptions( options );
+ this._renderMenu( this.menu, this.items );
+
+ this.menu.menu( "refresh" );
+ this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
+
+ // select current item
+ item = this._getSelectedItem();
+ // make sure menu is selected item aware
+ this.menu.menu( "focus", null, item );
+ this._setSelected( item.data( "ui-selectmenu-item" ) );
+
+ // set disabled state
+ this._setOption( "disabled", this._getCreateOptions().disabled );
+ }
+ },
+
+ open: function( event ) {
+ if ( this.options.disabled ) {
+ return;
+ }
+
+ this.isOpen = true;
+ this._toggleAttr();
+ this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
+
+ this._trigger( "open", event );
+ },
+
+ close: function( event ) {
+ if ( !this.isOpen ) {
+ return;
+ }
+
+ this.isOpen = false;
+ this._toggleAttr();
+
+ // check if we have an item to select
+ if ( this.menuItems ) {
+ var id = this._getSelectedItem().find( "a" ).attr( "id" );
+ this.button.attr( "aria-activedescendant", id );
+ this.menu.attr( "aria-activedescendant", id );
+ }
+
+ this._trigger( "close", event );
+ },
+
+ widget: function() {
+ return this.button;
+ },
+
+ menuWidget: function() {
+ return this.menu;
+ },
+
+ _renderMenu: function( ul, items ) {
+ var that = this,
+ currentOptgroup = "";
+
+ $.each( items, function( index, item ) {
+ if ( item.optgroup !== currentOptgroup ) {
+ $( "<li>", {
+ "class": "ui-selectmenu-optgroup" + ( item.element.parent( "optgroup" ).attr( "disabled" ) ? " ui-state-disabled" : "" ),
+ text: item.optgroup
+ }).appendTo( ul );
+ currentOptgroup = item.optgroup;
+ }
+ that._renderItem( ul, item );
+ });
+ },
+
+ _renderItem: function( ul, item ) {
+ var li = $( "<li>" ).data( "ui-selectmenu-item", item ),
+ a = $( "<a>", { href: "#" });
+
+ if ( item.disabled ) {
+ li.addClass( "ui-state-disabled" );
+ }
+ this._setText( a, item.label );
+
+ return li.append( a ).appendTo( ul );
+ },
+
+ _setText: function( element, value ) {
+ if ( value ) {
+ element.text( value );
+ } else {
+ element.html( "&#160;" );
+ }
+ },
+
+ _move: function( direction, event ) {
+ if ( direction === "first" || direction === "last" ) {
+ // set focus manually for first or last item
+ this.menu.menu( "focus", event, this.menuItems[ direction ]() );
+ } else {
+ // move to and focus next or prev item
+ this.menu.menu( direction, event );
+ }
+ },
+
+ _getSelectedItem: function() {
+ return this.menuItems.eq( this.element[ 0 ].selectedIndex );
+ },
+
+ _toggle: function( event ) {
+ if ( this.isOpen ) {
+ this.close( event );
+ } else {
+ this.open( event );
+ }
+ },
+
+ _documentClick: {
+ click: function( event ) {
+ if ( this.isOpen && !$( event.target ).closest( "li.ui-state-disabled, li.ui-selectmenu-optgroup, #" + this.ids.button ).length ) {
+ this.close( event );
+ }
+ }
+ },
+
+ _buttonEvents: {
+ focus: function() {
+ // init Menu on first focus
+ this.refresh();
+ // reset focus class as its removed by ui.widget._setOption
+ this.button.addClass( "ui-state-focus" );
+ this._off( this.button, "focus" );
+ },
+ click: function( event ) {
+ this._toggle( event );
+ event.preventDefault();
+ },
+ keydown: function( event ) {
+ var prevDef = true;
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.TAB:
+ case $.ui.keyCode.ESCAPE:
+ if ( this.isOpen ) {
+ this.close( event );
+ }
+ prevDef = false;
+ break;
+ case $.ui.keyCode.ENTER:
+ if ( this.isOpen ) {
+ this.menu.menu( "select", event );
+ }
+ break;
+ case $.ui.keyCode.UP:
+ if ( event.altKey ) {
+ this._toggle( event );
+ } else {
+ this._move( "previous", event );
+ }
+ break;
+ case $.ui.keyCode.DOWN:
+ if ( event.altKey ) {
+ this._toggle( event );
+ } else {
+ this._move( "next", event );
+ }
+ break;
+ case $.ui.keyCode.SPACE:
+ if ( this.isOpen ) {
+ this.menu.menu( "select", event );
+ } else {
+ this._toggle( event );
+ }
+ break;
+ case $.ui.keyCode.LEFT:
+ this._move( "previous", event );
+ break;
+ case $.ui.keyCode.RIGHT:
+ this._move( "next", event );
+ break;
+ case $.ui.keyCode.HOME:
+ case $.ui.keyCode.PAGE_UP:
+ this._move( "first", event );
+ break;
+ case $.ui.keyCode.END:
+ case $.ui.keyCode.PAGE_DOWN:
+ this._move( "last", event );
+ break;
+ default:
+ this.menu.trigger( event );
+ prevDef = false;
+ }
+ if ( prevDef ) {
+ event.preventDefault();
+ }
+ }
+ },
+
+ _select: function( item, event ) {
+ var oldIndex = this.element[ 0 ].selectedIndex;
+ // change native select element
+ this.element[ 0 ].selectedIndex = item.index;
+ this._setSelected( item );
+ this._trigger( "select", event, { item: item } );
+
+ if ( item.index !== oldIndex ) {
+ this._trigger( "change", event, { item: item } );
+ }
+ },
+
+ _setSelected: function( item ) {
+ this._setText( this.buttonText, item.label );
+ // change ARIA attr
+ this.menuItems.find( "a" ).attr( "aria-selected", false );
+ this.menuItems.eq( item.index ).find( "a" ).attr( "aria-selected", true );
+ this.button.attr( "aria-labelledby", this.menuItems.eq( item.index ).find( "a" ).attr( "id" ) );
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "icons" ) {
+ this.button.find( "span.ui-icon" )
+ .removeClass( this.options.icons.button )
+ .addClass( value.button );
+ }
+
+ this._super( key, value );
+
+ if ( key === "appendTo" ) {
+ this.menuWrap.appendTo( this._appendTo() );
+ }
+ if ( key === "disabled" ) {
+ this.menu.menu( "option", "disabled", value );
+ if ( value ) {
+ this.element.attr( "disabled", "disabled" );
+ this.button.attr( "tabindex", -1 );
+ this.close();
+ } else {
+ this.element.removeAttr( "disabled" );
+ this.button.attr( "tabindex", 0 );
+ }
+ }
+ },
+
+ _appendTo: function() {
+ var element = this.options.appendTo;
+
+ if ( element ) {
+ element = element.jquery || element.nodeType ?
+ $( element ) :
+ this.document.find( element ).eq( 0 );
+ }
+
+ if ( !element ) {
+ element = this.element.closest( ".ui-front" );
+ }
+
+ if ( !element.length ) {
+ element = this.document[0].body;
+ }
+
+ return element;
+ },
+
+ _toggleAttr: function(){
+ this.button.toggleClass( "ui-corner-top", this.isOpen ).toggleClass( "ui-corner-all", !this.isOpen );
+ this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
+ this.menu.attr( "aria-hidden", !this.isOpen);
+ this.button.attr( "aria-expanded", this.isOpen);
+ },
+
+ _getCreateOptions: function() {
+ return { disabled: !!this.element.attr( "disabled" ) };
+ },
+
+ _readOptions: function( options ) {
+ var data = [];
+ options.each( function( index, item ) {
+ var option = $( item ),
+ optgroup = option.parent( "optgroup" );
+ data.push({
+ element: option,
+ index: index,
+ value: option.attr( "value" ),
+ label: option.text(),
+ optgroup: optgroup.attr( "label" ) || "",
+ disabled: optgroup.attr( "disabled" ) || option.attr( "disabled" )
+ });
+ });
+ this.items = data;
+ },
+
+ _destroy: function() {
+ this.menuWrap.remove();
+ this.buttonWrap.remove();
+ this.element.show();
+ this.element.removeUniqueId();
+ this.label.attr( "for", this.ids.id );
+ }
+});
+
+}( jQuery ));