From 4f15e66f5373170caf307237b9a8b2c505ae3dbf Mon Sep 17 00:00:00 2001 From: kborchers Date: Sun, 22 Jan 2012 11:26:41 -0600 Subject: Menu: Added unit tests for the enable, disable and refresh methods as well as the disabled option. Cleaned up some variable names in unit tests. --- tests/unit/menu/menu_core.js | 28 ++++++++++++++-------------- tests/unit/menu/menu_events.js | 12 ++++++------ tests/unit/menu/menu_methods.js | 30 ++++++++++++++++++++++++++++++ tests/unit/menu/menu_options.js | 28 ++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 20 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/menu/menu_core.js b/tests/unit/menu/menu_core.js index c0feae75c..bccf4a1f2 100644 --- a/tests/unit/menu/menu_core.js +++ b/tests/unit/menu/menu_core.js @@ -9,27 +9,27 @@ module("menu: core"); test("accessibility", function () { expect(5); - var ac = $('#menu1').menu(); + var menu = $('#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"), "menu", "main role"); - ok( !ac.attr("aria-activedescendant"), "aria attribute not yet active"); + ok( menu.hasClass("ui-menu ui-widget ui-widget-content ui-corner-all"), "menu class"); + equals( menu.attr("role"), "menu", "main role"); + ok( !menu.attr("aria-activedescendant"), "aria attribute not yet active"); - var item = ac.find( "li:first" ).find( "a" ).attr( "id", "xid" ).end(); - ac.menu( "focus", $.Event(), item ); - equals( ac.attr("aria-activedescendant"), "xid", "aria attribute, id from dom"); + var item = menu.find( "li:first" ).find( "a" ).attr( "id", "xid" ).end(); + menu.menu( "focus", $.Event(), item ); + equals( menu.attr("aria-activedescendant"), "xid", "aria attribute, id from dom"); - var item = ac.find( "li:last" ); - ac.menu( "focus", $.Event(), item ); - equals( ac.attr("aria-activedescendant"), "menu1-4", "aria attribute, generated id"); + var item = menu.find( "li:last" ); + menu.menu( "focus", $.Event(), item ); + equals( menu.attr("aria-activedescendant"), "menu1-4", "aria attribute, generated id"); }); test("items class and role", function () { - var ac = $('#menu1').menu(); - expect(1 + 5 * $("li",ac).length); - ok( ($("li",ac).length > 0 ), "number of menu items"); - $("li",ac).each(function(item) { + var menu = $('#menu1').menu(); + expect(1 + 5 * $("li",menu).length); + ok( ($("li",menu).length > 0 ), "number of menu items"); + $("li",menu).each(function(item) { ok( $(this).hasClass("ui-menu-item"), "menu item ("+ item + ") class for item"); equals( $(this).attr("role"), "presentation", "menu item ("+ item + ") role"); equals( $("a", this).attr("role"), "menuitem", "menu item ("+ item + ") role"); diff --git a/tests/unit/menu/menu_events.js b/tests/unit/menu/menu_events.js index 9e68e0c67..8df43fa21 100644 --- a/tests/unit/menu/menu_events.js +++ b/tests/unit/menu/menu_events.js @@ -7,7 +7,7 @@ module("menu: events"); test("handle click on menu", function() { expect(1); - var ac = $('#menu1').menu({ + var menu = $('#menu1').menu({ select: function(event, ui) { menu_log(); } @@ -15,15 +15,15 @@ test("handle click on menu", function() { menu_log("click",true); menu_click($('#menu1'),"1"); menu_log("afterclick"); - menu_click( ac,"2"); + menu_click( menu,"2"); menu_click($('#menu1'),"3"); - menu_click( ac,"1"); + menu_click( menu,"1"); equals( $("#log").html(), "1,3,2,afterclick,1,click,", "Click order not valid."); }); test("handle click on custom item menu", function() { expect(1); - var ac = $('#menu5').menu({ + var menu = $('#menu5').menu({ select: function(event, ui) { menu_log(); }, @@ -32,9 +32,9 @@ test("handle click on custom item menu", function() { menu_log("click",true); menu_click($('#menu5'),"1"); menu_log("afterclick"); - menu_click( ac,"2"); + menu_click( menu,"2"); menu_click($('#menu5'),"3"); - menu_click( ac,"1"); + menu_click( menu,"1"); equals( $("#log").html(), "1,3,2,afterclick,1,click,", "Click order not valid."); }); diff --git a/tests/unit/menu/menu_methods.js b/tests/unit/menu/menu_methods.js index 0ecaf7328..3bcab3361 100644 --- a/tests/unit/menu/menu_methods.js +++ b/tests/unit/menu/menu_methods.js @@ -5,6 +5,36 @@ module("menu: methods"); +test( "enable/disable", function() { + expect( 3 ); + var menu = $( "#menu1" ).menu({ + select: function(event, ui) { + menu_log(); + } + }); + menu.menu("disable"); + ok(menu.is(".ui-state-disabled"),"Missing ui-state-disabled class"); + menu_log("click",true); + menu_click(menu,"1"); + menu_log("afterclick"); + menu.menu("enable"); + ok(menu.not(".ui-state-disabled"),"Has ui-state-disabled class"); + menu_log("click"); + menu_click(menu,"1"); + menu_log("afterclick"); + equals( $("#log").html(), "afterclick,1,click,afterclick,click,", "Click order not valid."); +}); + +test( "refresh", function() { + expect( 3 ); + var menu = $( "#menu1" ).menu(); + equals(menu.find(".ui-menu-item").length,5,"Incorrect number of menu items"); + menu.append("
  • test item
  • ").menu("refresh"); + equals(menu.find(".ui-menu-item").length,6,"Incorrect number of menu items"); + menu.find(".ui-menu-item:last").remove().end().menu("refresh"); + equals(menu.find(".ui-menu-item").length,5,"Incorrect number of menu items"); +}); + test("destroy", function() { domEqual("#menu1", function() { $("#menu1").menu().menu("destroy"); diff --git a/tests/unit/menu/menu_options.js b/tests/unit/menu/menu_options.js index 03822fd74..479aab0d1 100644 --- a/tests/unit/menu/menu_options.js +++ b/tests/unit/menu/menu_options.js @@ -5,6 +5,34 @@ module("menu: options"); +test( "{ disabled: true }", function() { + expect( 2 ); + var menu = $( "#menu1" ).menu({ + disabled: true, + select: function(event, ui) { + menu_log(); + } + }); + ok(menu.is(".ui-state-disabled"),"Missing ui-state-disabled class"); + menu_log("click",true); + menu_click(menu,"1"); + menu_log("afterclick"); + equals( $("#log").html(), "afterclick,click,", "Click order not valid."); +}); +test( "{ disabled: false }", function() { + expect( 2 ); + var menu = $( "#menu1" ).menu({ + disabled: false, + select: function(event, ui) { + menu_log(); + } + }); + ok(menu.not(".ui-state-disabled"),"Has ui-state-disabled class"); + menu_log("click",true); + menu_click(menu,"1"); + menu_log("afterclick"); + equals( $("#log").html(), "afterclick,1,click,", "Click order not valid."); +}); })(jQuery); -- cgit v1.2.3 From 3919256abd7b91dcc8437c245f98d623103f97e0 Mon Sep 17 00:00:00 2001 From: Scott González Date: Tue, 31 Jan 2012 11:46:31 -0500 Subject: Accordion: Pass header and content in create event. Fixes #7869 - Accordion: Provide header and content details in create event. --- tests/unit/accordion/accordion_events.js | 39 ++++++++++++++++++++++++++++++++ ui/jquery.ui.accordion.js | 7 ++++++ 2 files changed, 46 insertions(+) (limited to 'tests/unit') diff --git a/tests/unit/accordion/accordion_events.js b/tests/unit/accordion/accordion_events.js index 12acf2a44..b5c3ea228 100644 --- a/tests/unit/accordion/accordion_events.js +++ b/tests/unit/accordion/accordion_events.js @@ -2,6 +2,45 @@ module( "accordion: events", accordion_setupTeardown() ); +test( "create", function() { + expect( 10 ); + + var element = $( "#list1" ), + headers = element.children( "h3" ), + contents = headers.next(); + + element.accordion({ + create: function( event, ui ) { + equals( ui.header.size(), 1, "header size" ); + strictEqual( ui.header[ 0 ], headers[ 0 ], "header" ); + equals( ui.content.size(), 1, "content size" ); + strictEqual( ui.content[ 0 ], contents[ 0 ], "content" ); + } + }); + element.accordion( "destroy" ); + + element.accordion({ + active: 2, + create: function( event, ui ) { + equals( ui.header.size(), 1, "header size" ); + strictEqual( ui.header[ 0 ], headers[ 2 ], "header" ); + equals( ui.content.size(), 1, "content size" ); + strictEqual( ui.content[ 0 ], contents[ 2 ], "content" ); + } + }); + element.accordion( "destroy" ); + + element.accordion({ + active: false, + collapsible: true, + create: function( event, ui ) { + equals( ui.header.size(), 0, "header size" ); + equals( ui.content.size(), 0, "content size" ); + } + }); + element.accordion( "destroy" ); +}); + test( "beforeActivate", function() { expect( 38 ); var element = $( "#list1" ).accordion({ diff --git a/ui/jquery.ui.accordion.js b/ui/jquery.ui.accordion.js index a019ca127..97549cb10 100644 --- a/ui/jquery.ui.accordion.js +++ b/ui/jquery.ui.accordion.js @@ -103,6 +103,13 @@ $.widget( "ui.accordion", { this._setupEvents( options.event ); }, + _getCreateEventData: function() { + return { + header: this.active, + content: !this.active.length ? $() : this.active.next() + }; + }, + _createIcons: function() { var icons = this.options.icons; if ( icons ) { -- cgit v1.2.3 From 853b515e5c6f02dff1a4693eaf6c16d8bafc1395 Mon Sep 17 00:00:00 2001 From: Scott González Date: Tue, 31 Jan 2012 13:11:20 -0500 Subject: Accordion: Adjusted tests for icons: false. --- tests/unit/accordion/accordion_options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tests/unit') diff --git a/tests/unit/accordion/accordion_options.js b/tests/unit/accordion/accordion_options.js index a60bb27e1..8206b1d62 100644 --- a/tests/unit/accordion/accordion_options.js +++ b/tests/unit/accordion/accordion_options.js @@ -255,7 +255,7 @@ test( "{ icons: false }", function() { var element = $( "#list1" ); function icons( on ) { deepEqual( element.find( "span.ui-icon").length, on ? 3 : 0 ); - deepEqual( element.hasClass( "ui-accordion-icons" ), on ); + deepEqual( element.find( ".ui-accordion-header.ui-accordion-icons" ).length, on ? 3 : 0 ); } element.accordion(); icons( true ); -- cgit v1.2.3 From 62a70da959e71a2d5c8ecc27548ea38733ec3128 Mon Sep 17 00:00:00 2001 From: Scott González Date: Tue, 31 Jan 2012 14:21:18 -0500 Subject: Autocomplete: Added test for close method. --- tests/unit/autocomplete/autocomplete_core.js | 4 ---- tests/unit/autocomplete/autocomplete_methods.js | 11 +++++++++-- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/autocomplete/autocomplete_core.js b/tests/unit/autocomplete/autocomplete_core.js index d98f56abf..bc61b9100 100644 --- a/tests/unit/autocomplete/autocomplete_core.js +++ b/tests/unit/autocomplete/autocomplete_core.js @@ -162,8 +162,4 @@ test( "allow form submit on enter when menu is not active", function() { } })(); -(function() { - -})(); - }( jQuery ) ); diff --git a/tests/unit/autocomplete/autocomplete_methods.js b/tests/unit/autocomplete/autocomplete_methods.js index 3fe035d28..1600d73dc 100644 --- a/tests/unit/autocomplete/autocomplete_methods.js +++ b/tests/unit/autocomplete/autocomplete_methods.js @@ -9,15 +9,19 @@ test( "destroy", function() { }); }); -test( "search", function() { - expect( 3 ); +test( "search, close", function() { + expect( 6 ); var data = [ "c++", "java", "php", "coldfusion", "javascript", "asp", "ruby", "python", "c", "scala", "groovy", "haskell", "perl" ], element = $( "#autocomplete" ).autocomplete({ source: data, minLength: 0 }), menu = element.autocomplete( "widget" ); + + ok( menu.is( ":hidden" ), "menu is hidden on init" ); + element.autocomplete( "search" ); + ok( menu.is( ":visible" ), "menu is visible after search" ); equal( menu.find( ".ui-menu-item" ).length, data.length, "all items for a blank search" ); element.val( "has" ).autocomplete( "search" ); @@ -25,6 +29,9 @@ test( "search", function() { element.autocomplete( "search", "ja" ); equal( menu.find( ".ui-menu-item" ).length, 2, "only java and javascript for 'ja'" ); + + element.autocomplete( "close" ); + ok( menu.is( ":hidden" ), "menu is hidden after close" ); }); }( jQuery ) ); -- cgit v1.2.3 From 8cd4a8330ca79f222e193de585e2746b4ad3500d Mon Sep 17 00:00:00 2001 From: Scott González Date: Wed, 1 Feb 2012 16:59:26 -0500 Subject: Widget: Allow redefining a widget after other widgets have inherited from it. --- tests/unit/tabs/tabs_deprecated.js | 10 +- tests/unit/widget/widget_core.js | 45 ++++++- ui/jquery.ui.tabs.js | 256 +++++++++++++++++-------------------- ui/jquery.ui.widget.js | 74 +++++++---- 4 files changed, 217 insertions(+), 168 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/tabs/tabs_deprecated.js b/tests/unit/tabs/tabs_deprecated.js index 1323c774a..d0d13fa84 100644 --- a/tests/unit/tabs/tabs_deprecated.js +++ b/tests/unit/tabs/tabs_deprecated.js @@ -281,7 +281,7 @@ test( "enable", function() { var element = $( "#tabs1" ).tabs({ disabled: [ 0, 1 ], - enable: function ( event, ui ) { + enable: function( event, ui ) { equals( ui.tab, element.find( ".ui-tabs-nav a" )[ 1 ], "ui.tab" ); equals( ui.panel, element.find( ".ui-tabs-panel" )[ 1 ], "ui.panel" ); equals( ui.index, 1, "ui.index" ); @@ -296,10 +296,10 @@ test( "disable", function() { expect( 3 ); var element = $( "#tabs1" ).tabs({ - disable: function ( event, ui ) { - equals( ui.tab, element.find( ".ui-tabs-nav a" )[ 1 ], "ui.tab" ); - equals( ui.panel, element.find( ".ui-tabs-panel" )[ 1 ], "ui.panel" ); - equals( ui.index, 1, "ui.index" ); + disable: function( event, ui ) { + equals( ui.tab, element.find( ".ui-tabs-nav a" )[ 1 ], "ui.tab" ); + equals( ui.panel, element.find( ".ui-tabs-panel" )[ 1 ], "ui.panel" ); + equals( ui.index, 1, "ui.index" ); } }); element.tabs( "disable", 1 ); diff --git a/tests/unit/widget/widget_core.js b/tests/unit/widget/widget_core.js index df83abe91..86fa658aa 100644 --- a/tests/unit/widget/widget_core.js +++ b/tests/unit/widget/widget_core.js @@ -1050,11 +1050,54 @@ test( "redefine", function() { } }); - var instance = new $.ui.testWidget(); + var instance = new $.ui.testWidget({}); instance.method( "foo" ); equal( $.ui.testWidget.foo, "bar", "static properties remain" ); }); +test( "redefine deep prototype chain", function() { + expect( 8 ); + $.widget( "ui.testWidget", { + method: function( str ) { + strictEqual( this, instance, "original invoked with correct this" ); + equal( str, "level 4", "original invoked with correct parameter" ); + } + }); + $.widget( "ui.testWidget2", $.ui.testWidget, { + method: function( str ) { + strictEqual( this, instance, "testWidget2 invoked with correct this" ); + equal( str, "level 2", "testWidget2 invoked with correct parameter" ); + this._super( "level 3" ); + } + }); + $.widget( "ui.testWidget3", $.ui.testWidget2, { + method: function( str ) { + strictEqual( this, instance, "testWidget3 invoked with correct this" ); + equal( str, "level 1", "testWidget3 invoked with correct parameter" ); + this._super( "level 2" ); + } + }); + // redefine testWidget after other widgets have inherited from it + // this tests whether the inheriting widgets get updated prototype chains + $.widget( "ui.testWidget", $.ui.testWidget, { + method: function( str ) { + strictEqual( this, instance, "new invoked with correct this" ); + equal( str, "level 3", "new invoked with correct parameter" ); + this._super( "level 4" ); + } + }); + // redefine testWidget3 after it has been automatically redefined + // this tests whether we properly handle _super() when the topmost prototype + // doesn't have the method defined + $.widget( "ui.testWidget3", $.ui.testWidget3, {} ); + + var instance = new $.ui.testWidget3({}); + instance.method( "level 1" ); + + delete $.ui.testWidget3; + delete $.ui.testWidget2; +}); + asyncTest( "_delay", function() { expect( 6 ); var order = 0, diff --git a/ui/jquery.ui.tabs.js b/ui/jquery.ui.tabs.js index 7a701405c..dc52591b9 100644 --- a/ui/jquery.ui.tabs.js +++ b/ui/jquery.ui.tabs.js @@ -596,86 +596,79 @@ if ( $.uiBackCompat !== false ) { }; // url method - (function( $, prototype ) { - prototype.url = function( index, url ) { + $.widget( "ui.tabs", $.ui.tabs, { + url: function( index, url ) { this.anchors.eq( index ).attr( "href", url ); - }; - }( jQuery, jQuery.ui.tabs.prototype ) ); + } + }); // ajaxOptions and cache options - (function( $, prototype ) { - $.extend( prototype.options, { + $.widget( "ui.tabs", $.ui.tabs, { + options: { ajaxOptions: null, cache: false - }); - - var _create = prototype._create, - _setOption = prototype._setOption, - _destroy = prototype._destroy, - oldurl = prototype.url || $.noop; - - $.extend( prototype, { - _create: function() { - _create.call( this ); + }, - var self = this; + _create: function() { + this._super(); - this.element.bind( "tabsbeforeload.tabs", function( event, ui ) { - // tab is already cached - if ( $.data( ui.tab[ 0 ], "cache.tabs" ) ) { - event.preventDefault(); - return; - } + var self = this; - $.extend( ui.ajaxSettings, self.options.ajaxOptions, { - error: function( xhr, s, e ) { - try { - // Passing index avoid a race condition when this method is - // called after the user has selected another tab. - // Pass the anchor that initiated this request allows - // loadError to manipulate the tab content panel via $(a.hash) - self.options.ajaxOptions.error( xhr, s, ui.tab.closest( "li" ).index(), ui.tab[ 0 ] ); - } - catch ( e ) {} - } - }); + this.element.bind( "tabsbeforeload.tabs", function( event, ui ) { + // tab is already cached + if ( $.data( ui.tab[ 0 ], "cache.tabs" ) ) { + event.preventDefault(); + return; + } - ui.jqXHR.success(function() { - if ( self.options.cache ) { - $.data( ui.tab[ 0 ], "cache.tabs", true ); + $.extend( ui.ajaxSettings, self.options.ajaxOptions, { + error: function( xhr, s, e ) { + try { + // Passing index avoid a race condition when this method is + // called after the user has selected another tab. + // Pass the anchor that initiated this request allows + // loadError to manipulate the tab content panel via $(a.hash) + self.options.ajaxOptions.error( xhr, s, ui.tab.closest( "li" ).index(), ui.tab[ 0 ] ); } - }); + catch ( e ) {} + } }); - }, - _setOption: function( key, value ) { - // reset cache if switching from cached to not cached - if ( key === "cache" && value === false ) { - this.anchors.removeData( "cache.tabs" ); - } - _setOption.apply( this, arguments ); - }, + ui.jqXHR.success(function() { + if ( self.options.cache ) { + $.data( ui.tab[ 0 ], "cache.tabs", true ); + } + }); + }); + }, - _destroy: function() { + _setOption: function( key, value ) { + // reset cache if switching from cached to not cached + if ( key === "cache" && value === false ) { this.anchors.removeData( "cache.tabs" ); - _destroy.call( this ); - }, - - url: function( index, url ){ - this.anchors.eq( index ).removeData( "cache.tabs" ); - oldurl.apply( this, arguments ); } - }); - }( jQuery, jQuery.ui.tabs.prototype ) ); + this._super( key, value ); + }, + + _destroy: function() { + this.anchors.removeData( "cache.tabs" ); + this._super(); + }, + + url: function( index, url ){ + this.anchors.eq( index ).removeData( "cache.tabs" ); + this._superApply( arguments ); + } + }); // abort method - (function( $, prototype ) { - prototype.abort = function() { + $.widget( "ui.tabs", $.ui.tabs, { + abort: function() { if ( this.xhr ) { this.xhr.abort(); } - }; - }( jQuery, jQuery.ui.tabs.prototype ) ); + } + }); // spinner $.widget( "ui.tabs", $.ui.tabs, { @@ -702,16 +695,13 @@ if ( $.uiBackCompat !== false ) { }); // enable/disable events - (function( $, prototype ) { - $.extend( prototype.options, { + $.widget( "ui.tabs", $.ui.tabs, { + options: { enable: null, disable: null - }); - - var enable = prototype.enable, - disable = prototype.disable; + }, - prototype.enable = function( index ) { + enable: function( index ) { var options = this.options, trigger; @@ -720,14 +710,14 @@ if ( $.uiBackCompat !== false ) { trigger = true; } - enable.apply( this, arguments ); + this._superApply( arguments ); if ( trigger ) { this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); } - }; + }, - prototype.disable = function( index ) { + disable: function( index ) { var options = this.options, trigger; @@ -736,23 +726,23 @@ if ( $.uiBackCompat !== false ) { trigger = true; } - disable.apply( this, arguments ); + this._superApply( arguments ); if ( trigger ) { this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); } - }; - }( jQuery, jQuery.ui.tabs.prototype ) ); + } + }); // add/remove methods and events - (function( $, prototype ) { - $.extend( prototype.options, { + $.widget( "ui.tabs", $.ui.tabs, { + options: { add: null, remove: null, tabTemplate: "
  • #{label}
  • " - }); + }, - prototype.add = function( url, label, index ) { + add: function( url, label, index ) { if ( index === undefined ) { index = this.anchors.length; } @@ -803,9 +793,9 @@ if ( $.uiBackCompat !== false ) { this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) ); return this; - }; + }, - prototype.remove = function( index ) { + remove: function( index ) { index = this._getIndex( index ); var options = this.options, tab = this.lis.eq( index ).remove(), @@ -832,125 +822,117 @@ if ( $.uiBackCompat !== false ) { this._trigger( "remove", null, this._ui( tab.find( "a" )[ 0 ], panel[ 0 ] ) ); return this; - }; - }( jQuery, jQuery.ui.tabs.prototype ) ); + } + }); // length method - (function( $, prototype ) { - prototype.length = function() { + $.widget( "ui.tabs", $.ui.tabs, { + length: function() { return this.anchors.length; - }; - }( jQuery, jQuery.ui.tabs.prototype ) ); + } + }); // panel ids (idPrefix option + title attribute) - (function( $, prototype ) { - $.extend( prototype.options, { + $.widget( "ui.tabs", $.ui.tabs, { + options: { idPrefix: "ui-tabs-" - }); + }, - var _tabId = prototype._tabId; - prototype._tabId = function( a ) { + _tabId: function( a ) { return $( a ).attr( "aria-controls" ) || a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) || this.options.idPrefix + getNextTabId(); - }; - }( jQuery, jQuery.ui.tabs.prototype ) ); + } + }); // _createPanel method - (function( $, prototype ) { - $.extend( prototype.options, { + $.widget( "ui.tabs", $.ui.tabs, { + options: { panelTemplate: "
    " - }); + }, - var _createPanel = prototype._createPanel; - prototype._createPanel = function( id ) { + _createPanel: function( id ) { return $( this.options.panelTemplate ) - .attr( "id", id ) - .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) - .data( "destroy.tabs", true ); - }; - }( jQuery, jQuery.ui.tabs.prototype ) ); + .attr( "id", id ) + .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) + .data( "destroy.tabs", true ); + } + }); // selected option - (function( $, prototype ) { - var _create = prototype._create, - _setOption = prototype._setOption, - _eventHandler = prototype._eventHandler; - - prototype._create = function() { + $.widget( "ui.tabs", $.ui.tabs, { + _create: function() { var options = this.options; if ( options.active === null && options.selected !== undefined ) { options.active = options.selected === -1 ? false : options.selected; } - _create.call( this ); + this._super(); options.selected = options.active; if ( options.selected === false ) { options.selected = -1; } - }; + }, - prototype._setOption = function( key, value ) { + _setOption: function( key, value ) { if ( key !== "selected" ) { - return _setOption.apply( this, arguments ); + return this._super( key, value ); } var options = this.options; - _setOption.call( this, "active", value === -1 ? false : value ); + this._super( "active", value === -1 ? false : value ); options.selected = options.active; if ( options.selected === false ) { options.selected = -1; } - }; + }, - prototype._eventHandler = function( event ) { - _eventHandler.apply( this, arguments ); + _eventHandler: function( event ) { + this._superApply( arguments ); this.options.selected = this.options.active; if ( this.options.selected === false ) { this.options.selected = -1; } - }; - }( jQuery, jQuery.ui.tabs.prototype ) ); + } + }); // show and select event - (function( $, prototype ) { - $.extend( prototype.options, { + $.widget( "ui.tabs", $.ui.tabs, { + options: { show: null, select: null - }); - var _create = prototype._create, - _trigger = prototype._trigger; - - prototype._create = function() { - _create.call( this ); + }, + _create: function() { + this._super(); if ( this.options.active !== false ) { this._trigger( "show", null, this._ui( this.active[ 0 ], this._getPanelForTab( this.active )[ 0 ] ) ); } - }; - prototype._trigger = function( type, event, data ) { - var ret = _trigger.apply( this, arguments ); + }, + _trigger: function( type, event, data ) { + var ret = this._superApply( arguments ); if ( !ret ) { return false; } if ( type === "beforeActivate" && data.newTab.length ) { - ret = _trigger.call( this, "select", event, { + ret = this._super( "select", event, { tab: data.newTab[ 0], panel: data.newPanel[ 0 ], index: data.newTab.closest( "li" ).index() }); } else if ( type === "activate" && data.newTab.length ) { - ret = _trigger.call( this, "show", event, { + ret = this._super( "show", event, { tab: data.newTab[ 0 ], panel: data.newPanel[ 0 ], index: data.newTab.closest( "li" ).index() }); } - }; - }( jQuery, jQuery.ui.tabs.prototype ) ); + return ret; + } + }); // select method - (function( $, prototype ) { - prototype.select = function( index ) { + $.widget( "ui.tabs", $.ui.tabs, { + select: function( index ) { index = this._getIndex( index ); if ( index === -1 ) { if ( this.options.collapsible && this.options.selected !== -1 ) { @@ -960,8 +942,8 @@ if ( $.uiBackCompat !== false ) { } } this.anchors.eq( index ).trigger( this.options.event + ".tabs" ); - }; - }( jQuery, jQuery.ui.tabs.prototype ) ); + } + }); // cookie option var listId = 0; diff --git a/ui/jquery.ui.widget.js b/ui/jquery.ui.widget.js index ad03e6f44..bf26373e1 100644 --- a/ui/jquery.ui.widget.js +++ b/ui/jquery.ui.widget.js @@ -23,8 +23,9 @@ $.cleanData = function( elems ) { }; $.widget = function( name, base, prototype ) { - var namespace = name.split( "." )[ 0 ], - fullName; + var fullName, existingConstructor, constructor, basePrototype, + namespace = name.split( "." )[ 0 ]; + name = name.split( "." )[ 1 ]; fullName = namespace + "-" + name; @@ -39,12 +40,11 @@ $.widget = function( name, base, prototype ) { }; $[ namespace ] = $[ namespace ] || {}; - // create the constructor using $.extend() so we can carry over any - // static properties stored on the existing constructor (if there is one) - $[ namespace ][ name ] = $.extend( function( options, element ) { + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { // allow instantiation without "new" keyword if ( !this._createWidget ) { - return new $[ namespace ][ name ]( options, element ); + return new constructor( options, element ); } // allow instantiation without initializing for simple inheritance @@ -52,9 +52,19 @@ $.widget = function( name, base, prototype ) { if ( arguments.length ) { this._createWidget( options, element ); } - }, $[ namespace ][ name ], { version: prototype.version } ); + }; + // extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + // copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + // track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + }); - var basePrototype = new base(); + basePrototype = new base(); // we need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from @@ -83,17 +93,41 @@ $.widget = function( name, base, prototype ) { return returnValue; }; - }()); + })(); } }); - $[ namespace ][ name ].prototype = $.widget.extend( basePrototype, { + constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: name + }, prototype, { + constructor: constructor, namespace: namespace, widgetName: name, - widgetEventPrefix: name, widgetBaseClass: fullName - }, prototype ); + }); - $.widget.bridge( name, $[ namespace ][ name ] ); + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); + }); + // remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); }; $.widget.extend = function( target ) { @@ -157,18 +191,8 @@ $.widget.bridge = function( name, object ) { }; }; -$.Widget = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new $[ namespace ][ name ]( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } -}; +$.Widget = function( options, element ) {}; +$.Widget._childConstructors = []; $.Widget.prototype = { widgetName: "widget", -- cgit v1.2.3 From 3ef4db267040844d7a36165c9fa72e77e9118429 Mon Sep 17 00:00:00 2001 From: kborchers Date: Mon, 6 Feb 2012 15:01:40 -0600 Subject: Menu: Focus the menu before performing keyboard unit tests. --- tests/unit/menu/menu_events.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/menu/menu_events.js b/tests/unit/menu/menu_events.js index 8df43fa21..3a3e6b47f 100644 --- a/tests/unit/menu/menu_events.js +++ b/tests/unit/menu/menu_events.js @@ -144,13 +144,14 @@ test("handle keyboard navigation on menu without scroll and without submenus", f }); menu_log("keydown",true); + element.focus(); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - equals( $("#log").html(), "1,0,keydown,", "Keydown DOWN"); + equals( $("#log").html(), "2,1,0,keydown,", "Keydown DOWN"); menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); - equals( $("#log").html(), "0,keydown,", "Keydown UP"); + equals( $("#log").html(), "1,keydown,", "Keydown UP"); menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); @@ -205,13 +206,15 @@ asyncTest("handle keyboard navigation on menu without scroll and with submenus", }); menu_log("keydown",true); + element.focus(); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - equals( $("#log").html(), "1,0,keydown,", "Keydown DOWN"); + equals( $("#log").html(), "2,1,0,keydown,", "Keydown DOWN"); menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); - equals( $("#log").html(), "0,keydown,", "Keydown UP"); + element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); + equals( $("#log").html(), "0,1,keydown,", "Keydown UP"); menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); @@ -294,13 +297,15 @@ test("handle keyboard navigation on menu with scroll and without submenus", func }); menu_log("keydown",true); + element.focus(); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - equals( $("#log").html(), "1,0,keydown,", "Keydown DOWN"); + equals( $("#log").html(), "2,1,0,keydown,", "Keydown DOWN"); menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); - equals( $("#log").html(), "0,keydown,", "Keydown UP"); + element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); + equals( $("#log").html(), "0,1,keydown,", "Keydown UP"); menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); @@ -363,13 +368,15 @@ asyncTest("handle keyboard navigation on menu with scroll and with submenus", fu }); menu_log("keydown",true); + element.focus(); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - equals( $("#log").html(), "1,0,keydown,", "Keydown DOWN"); + equals( $("#log").html(), "2,1,0,keydown,", "Keydown DOWN"); menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); - equals( $("#log").html(), "0,keydown,", "Keydown UP"); + element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); + equals( $("#log").html(), "0,1,keydown,", "Keydown UP"); menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); -- cgit v1.2.3 From 2fd2ab23c966c8ddcb6f95eb07dcf38a997c93c7 Mon Sep 17 00:00:00 2001 From: Scott González Date: Thu, 9 Feb 2012 16:19:50 -0500 Subject: Menu tests: Handle async focus events in IE. --- tests/unit/menu/menu_events.js | 200 +++++++++++++++++++++-------------------- 1 file changed, 101 insertions(+), 99 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/menu/menu_events.js b/tests/unit/menu/menu_events.js index 3a3e6b47f..c7031b282 100644 --- a/tests/unit/menu/menu_events.js +++ b/tests/unit/menu/menu_events.js @@ -211,78 +211,79 @@ asyncTest("handle keyboard navigation on menu without scroll and with submenus", element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); equals( $("#log").html(), "2,1,0,keydown,", "Keydown DOWN"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); - element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); - equals( $("#log").html(), "0,1,keydown,", "Keydown UP"); - - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); - equals( $("#log").html(), "keydown,", "Keydown LEFT (no effect)"); - - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ); - - setTimeout( function() { - equals( $("#log").html(), "0,4,3,2,1,keydown,", "Keydown RIGHT (open submenu)"); - }, 50); + setTimeout(function() { + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); + equals( $("#log").html(), "0,1,keydown,", "Keydown UP"); - setTimeout( function() { menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); - equals( $("#log").html(), "4,keydown,", "Keydown LEFT (close submenu)"); + equals( $("#log").html(), "keydown,", "Keydown LEFT (no effect)"); - //re-open submenu + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ); setTimeout( function() { - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); - equals( $("#log").html(), "2,keydown,", "Keydown PAGE_DOWN"); + equals( $("#log").html(), "0,4,3,2,1,keydown,", "Keydown RIGHT (open submenu)"); + }, 50); + setTimeout( function() { menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); - equals( $("#log").html(), "keydown,", "Keydown PAGE_DOWN (no effect)"); + element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); + equals( $("#log").html(), "4,keydown,", "Keydown LEFT (close submenu)"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); - equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP"); + //re-open submenu + element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); - equals( $("#log").html(), "keydown,", "Keydown PAGE_UP (no effect)"); + setTimeout( function() { + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + equals( $("#log").html(), "2,keydown,", "Keydown PAGE_DOWN"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.END } ); - equals( $("#log").html(), "2,keydown,", "Keydown END"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + equals( $("#log").html(), "keydown,", "Keydown PAGE_DOWN (no effect)"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } ); - equals( $("#log").html(), "0,keydown,", "Keydown HOME"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); + equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); - equals( $("#log").html(), "4,keydown,", "Keydown ESCAPE (close submenu)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); + equals( $("#log").html(), "keydown,", "Keydown PAGE_UP (no effect)"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.END } ); + equals( $("#log").html(), "2,keydown,", "Keydown END"); - setTimeout( function() { - equals( $("#log").html(), "0,keydown,", "Keydown ENTER (open submenu)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } ); + equals( $("#log").html(), "0,keydown,", "Keydown HOME"); + + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + equals( $("#log").html(), "4,keydown,", "Keydown ESCAPE (close submenu)"); menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); - equals( $("#log").html(), "Ada,keydown,", "Keydown ENTER (select item)"); - start(); - }, 200); - }, 150); - }, 100); + setTimeout( function() { + equals( $("#log").html(), "0,keydown,", "Keydown ENTER (open submenu)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + equals( $("#log").html(), "Ada,keydown,", "Keydown ENTER (select item)"); + + start(); + }, 200); + }, 150); + }, 100); + }, 50); }); test("handle keyboard navigation on menu with scroll and without submenus", function() { @@ -373,75 +374,76 @@ asyncTest("handle keyboard navigation on menu with scroll and with submenus", fu element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); equals( $("#log").html(), "2,1,0,keydown,", "Keydown DOWN"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); - element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); - equals( $("#log").html(), "0,1,keydown,", "Keydown UP"); - - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); - equals( $("#log").html(), "keydown,", "Keydown LEFT (no effect)"); - - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ); - - setTimeout( function() { - equals( $("#log").html(), "0,1,keydown,", "Keydown RIGHT (open submenu)"); - }, 50); + setTimeout(function() { + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); + equals( $("#log").html(), "0,1,keydown,", "Keydown UP"); - setTimeout( function() { menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); - equals( $("#log").html(), "1,keydown,", "Keydown LEFT (close submenu)"); + equals( $("#log").html(), "keydown,", "Keydown LEFT (no effect)"); - //re-open submenu + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ); setTimeout( function() { - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); - equals( $("#log").html(), "10,keydown,", "Keydown PAGE_DOWN"); + equals( $("#log").html(), "0,1,keydown,", "Keydown RIGHT (open submenu)"); + }, 50); + setTimeout( function() { menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); - equals( $("#log").html(), "20,keydown,", "Keydown PAGE_DOWN"); + element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); + equals( $("#log").html(), "1,keydown,", "Keydown LEFT (close submenu)"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); - equals( $("#log").html(), "10,keydown,", "Keydown PAGE_UP"); + //re-open submenu + element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); - equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP"); + setTimeout( function() { + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + equals( $("#log").html(), "10,keydown,", "Keydown PAGE_DOWN"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.END } ); - equals( $("#log").html(), "27,keydown,", "Keydown END"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + equals( $("#log").html(), "20,keydown,", "Keydown PAGE_DOWN"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } ); - equals( $("#log").html(), "0,keydown,", "Keydown HOME"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); + equals( $("#log").html(), "10,keydown,", "Keydown PAGE_UP"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); - equals( $("#log").html(), "1,keydown,", "Keydown ESCAPE (close submenu)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); + equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.END } ); + equals( $("#log").html(), "27,keydown,", "Keydown END"); - setTimeout( function() { - equals( $("#log").html(), "0,keydown,", "Keydown ENTER (open submenu)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } ); + equals( $("#log").html(), "0,keydown,", "Keydown HOME"); + + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + equals( $("#log").html(), "1,keydown,", "Keydown ESCAPE (close submenu)"); menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); - equals( $("#log").html(), "Aberdeen,keydown,", "Keydown ENTER (select item)"); - start(); - }, 200); - }, 150); - }, 100); + setTimeout( function() { + equals( $("#log").html(), "0,keydown,", "Keydown ENTER (open submenu)"); + + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + equals( $("#log").html(), "Aberdeen,keydown,", "Keydown ENTER (select item)"); + start(); + }, 200); + }, 150); + }, 100); + }, 50); }); })(jQuery); -- cgit v1.2.3 From 530d4cb40814c68163197f8091322e2258f0e57a Mon Sep 17 00:00:00 2001 From: Scott González Date: Sat, 11 Feb 2012 10:12:51 -0500 Subject: Autocomplete: Cancel search when closing the menu. Fixes #7523 - Autocomplete cancel pending request when text changes below minLength. --- tests/unit/autocomplete/autocomplete_options.js | 33 +++++++++++++++++++++++++ ui/jquery.ui.autocomplete.js | 8 +++++- 2 files changed, 40 insertions(+), 1 deletion(-) (limited to 'tests/unit') diff --git a/tests/unit/autocomplete/autocomplete_options.js b/tests/unit/autocomplete/autocomplete_options.js index 114e9a42b..799a249d8 100644 --- a/tests/unit/autocomplete/autocomplete_options.js +++ b/tests/unit/autocomplete/autocomplete_options.js @@ -102,6 +102,39 @@ test( "minLength", function() { ok( menu.is( ":visible" ), "blank enough for minLength: 0" ); }); +asyncTest( "minLength, exceed then drop below", function() { + expect( 4 ); + var element = $( "#autocomplete" ).autocomplete({ + minLength: 2, + source: function( req, res ) { + equal( req.term, "12", "correct search term" ); + setTimeout(function() { + res([ "item" ]); + }, 1 ); + } + }), + menu = element.autocomplete( "widget" ); + + ok( menu.is( ":hidden" ), "menu is hidden before first search" ); + element.autocomplete( "search", "12" ); + + ok( menu.is( ":hidden" ), "menu is hidden before second search" ); + element.autocomplete( "search", "1" ); + + setTimeout(function() { + ok( menu.is( ":hidden" ), "menu is hidden after searches" ); + start(); + }, 50 ); +}); + +// TODO: figure out how to implement this test +// When fixing #7523, I couldn't figure out a test that would fail when +// calling .close() (instead of ._close()) from ._response(). +// Use the remote demo and type "je", delete, "a", you should get results for "ja" +// but if we call .close() from ._response() the results are ignored. +//asyncTest( "minLength, exceed then drop below", function() { +//}); + test( "source, local string array", function() { expect( 1 ); var element = $( "#autocomplete" ).autocomplete({ diff --git a/ui/jquery.ui.autocomplete.js b/ui/jquery.ui.autocomplete.js index 14e8a2a86..ba0062410 100644 --- a/ui/jquery.ui.autocomplete.js +++ b/ui/jquery.ui.autocomplete.js @@ -383,7 +383,8 @@ $.widget( "ui.autocomplete", { this._suggest( content ); this._trigger( "open" ); } else { - this.close(); + // use ._close() instad of .close() so we don't cancel future searches + this._close(); } this.pending--; if ( !this.pending ) { @@ -392,6 +393,11 @@ $.widget( "ui.autocomplete", { }, close: function( event ) { + this.cancelSearch = true; + this._close( event ); + }, + + _close: function( event ) { clearTimeout( this.closing ); if ( this.menu.element.is(":visible") ) { this.menu.element.hide(); -- cgit v1.2.3 From f262a531fa0978c3aaa0cc1c0a75cb1b8fec0155 Mon Sep 17 00:00:00 2001 From: Scott González Date: Wed, 15 Feb 2012 11:41:30 -0500 Subject: Autocomplete: Added a test for exceeding minLength, then falling below, then exceeding again. --- tests/unit/autocomplete/autocomplete_options.js | 35 ++++++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/autocomplete/autocomplete_options.js b/tests/unit/autocomplete/autocomplete_options.js index 799a249d8..1ab40f36c 100644 --- a/tests/unit/autocomplete/autocomplete_options.js +++ b/tests/unit/autocomplete/autocomplete_options.js @@ -127,13 +127,34 @@ asyncTest( "minLength, exceed then drop below", function() { }, 50 ); }); -// TODO: figure out how to implement this test -// When fixing #7523, I couldn't figure out a test that would fail when -// calling .close() (instead of ._close()) from ._response(). -// Use the remote demo and type "je", delete, "a", you should get results for "ja" -// but if we call .close() from ._response() the results are ignored. -//asyncTest( "minLength, exceed then drop below", function() { -//}); +test( "minLength, exceed then drop below then exceed", function() { + expect( 3 ); + var _res = [], + element = $( "#autocomplete" ).autocomplete({ + minLength: 2, + source: function( req, res ) { + _res.push( res ); + } + }), + menu = element.autocomplete( "widget" ); + + // trigger a valid search + ok( menu.is( ":hidden" ), "menu is hidden before first search" ); + element.autocomplete( "search", "12" ); + + // trigger a search below the minLength, to turn on cancelSearch flag + ok( menu.is( ":hidden" ), "menu is hidden before second search" ); + element.autocomplete( "search", "1" ); + + // trigger a valid search + element.autocomplete( "search", "13" ); + // react as if the first search was cancelled (default ajax behavior) + _res[ 0 ]([]); + // react to second search + _res[ 1 ]([ "13" ]); + + ok( menu.is( ":visible" ), "menu is visible after searches" ); +}); test( "source, local string array", function() { expect( 1 ); -- cgit v1.2.3 From 3d9f6b5bc74d09a08f6a116b6b31d93d72971f6d Mon Sep 17 00:00:00 2001 From: Scott González Date: Thu, 16 Feb 2012 16:51:46 -0500 Subject: Accordion: Rewrote the animation code. Fixes #4178 - Accordion animation a bit jumpy in some browsers. Fixes #7371 - Accordion: Incorrect size when zoomed. --- tests/unit/accordion/accordion_defaults.js | 2 +- .../accordion/accordion_defaults_deprecated.js | 1 + tests/unit/accordion/accordion_test_helpers.js | 6 +- ui/jquery.ui.accordion.js | 267 +++++++++------------ 4 files changed, 112 insertions(+), 164 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/accordion/accordion_defaults.js b/tests/unit/accordion/accordion_defaults.js index 9aa58e650..9ad85bbce 100644 --- a/tests/unit/accordion/accordion_defaults.js +++ b/tests/unit/accordion/accordion_defaults.js @@ -1,7 +1,7 @@ commonWidgetTests( "accordion", { defaults: { active: 0, - animated: "slide", + animate: {}, collapsible: false, disabled: false, event: "click", diff --git a/tests/unit/accordion/accordion_defaults_deprecated.js b/tests/unit/accordion/accordion_defaults_deprecated.js index 3f45a1f10..99f5ac827 100644 --- a/tests/unit/accordion/accordion_defaults_deprecated.js +++ b/tests/unit/accordion/accordion_defaults_deprecated.js @@ -1,6 +1,7 @@ commonWidgetTests( "accordion", { defaults: { active: 0, + animate: null, animated: "slide", autoHeight: true, clearStyle: false, diff --git a/tests/unit/accordion/accordion_test_helpers.js b/tests/unit/accordion/accordion_test_helpers.js index 66d60a469..7b316e983 100644 --- a/tests/unit/accordion/accordion_test_helpers.js +++ b/tests/unit/accordion/accordion_test_helpers.js @@ -18,13 +18,13 @@ function accordion_equalHeights( accordion, min, max ) { } function accordion_setupTeardown() { - var animated = $.ui.accordion.prototype.options.animated; + var animate = $.ui.accordion.prototype.options.animate; return { setup: function() { - $.ui.accordion.prototype.options.animated = false; + $.ui.accordion.prototype.options.animate = false; }, teardown: function() { - $.ui.accordion.prototype.options.animated = animated; + $.ui.accordion.prototype.options.animate = animate; } }; } diff --git a/ui/jquery.ui.accordion.js b/ui/jquery.ui.accordion.js index c56f3cbbf..8731c17ca 100644 --- a/ui/jquery.ui.accordion.js +++ b/ui/jquery.ui.accordion.js @@ -17,7 +17,7 @@ $.widget( "ui.accordion", { version: "@VERSION", options: { active: 0, - animated: "slide", + animate: {}, collapsible: false, event: "click", header: "> li > :first-child,> :not(li):even", @@ -35,7 +35,7 @@ $.widget( "ui.accordion", { _create: function() { var options = this.options; - this.lastToggle = {}; + this.prevShow = this.prevHide = $(); this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ); this.headers = this.element.find( options.header ) @@ -62,6 +62,7 @@ $.widget( "ui.accordion", { this.active.next().addClass( "ui-accordion-content-active" ); this._createIcons(); + this.originalHeight = this.element[0].style.height; this.refresh(); // ARIA @@ -156,6 +157,7 @@ $.widget( "ui.accordion", { .removeAttr( "role" ) .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled" ); if ( this.options.heightStyle !== "content" ) { + this.element.css( "height", this.originalHeight ); contents.css( "height", "" ); } }, @@ -229,12 +231,12 @@ $.widget( "ui.accordion", { }, refresh: function() { - var options = this.options, + var heightStyle = this.options.heightStyle, parent = this.element.parent(), maxHeight, overflow; - if ( options.heightStyle === "fill" ) { + if ( heightStyle === "fill" ) { // IE 6 treats height like minHeight, so we need to turn off overflow // in order to get a reliable height // we use the minHeight support test because we assume that only @@ -267,7 +269,7 @@ $.widget( "ui.accordion", { $( this ).innerHeight() + $( this ).height() ) ); }) .css( "overflow", "auto" ); - } else if ( options.heightStyle === "auto" ) { + } else if ( heightStyle === "auto" ) { maxHeight = 0; this.headers.next() .each(function() { @@ -276,7 +278,9 @@ $.widget( "ui.accordion", { .height( maxHeight ); } - return this; + if ( heightStyle !== "content" ) { + this.element.height( this.element.height() ); + } }, _activate: function( index ) { @@ -361,41 +365,20 @@ $.widget( "ui.accordion", { }, _toggle: function( data ) { - var that = this, - options = this.options, - toShow = data.newContent, - toHide = data.oldContent; - - function complete() { - that._completed( data ); - } + var toShow = data.newContent, + toHide = this.prevShow.length ? this.prevShow : data.oldContent; - if ( options.animated ) { - var animations = $.ui.accordion.animations, - animation = options.animated, - additional; - - if ( !animations[ animation ] ) { - additional = { - easing: $.easing[ animation ] ? animation : "slide", - duration: 700 - }; - animation = "slide"; - } + // handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; - animations[ animation ]({ - widget: this, - toShow: toShow, - toHide: toHide, - prevShow: this.lastToggle.toShow, - prevHide: this.lastToggle.toHide, - complete: complete, - down: toShow.length && ( !toHide.length || ( toShow.index() < toHide.index() ) ) - }, additional ); + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); } else { toHide.hide(); toShow.show(); - complete(); + this._completed( data ); } // TODO assert that the blur and focus triggers are really necessary, remove otherwise @@ -415,17 +398,51 @@ $.widget( "ui.accordion", { .focus(); }, + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + toShow.removeData( "accordionHeight" ); + that._completed( data ); + }; + + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + + if ( !toHide.size() ) { + return toShow.animate( showProps, duration, easing, complete ); + } + if ( !toShow.size() ) { + return toHide.animate( hideProps, duration, easing, complete ); + } + + total = toShow.show().outerHeight(); + toHide.animate( hideProps, duration, easing ); + toShow + .hide() + .data( "accordionHeight", { + total: total, + toHide: toHide + }) + .animate( this.options.heightStyle === "content" ? showProps : showPropsAdjust, + duration, easing, complete ); + }, + _completed: function( data ) { var toShow = data.newContent, toHide = data.oldContent; - if ( this.options.heightStyle === "content" ) { - toShow.add( toHide ).css({ - height: "", - overflow: "" - }); - } - // other classes are removed before the animation; this one needs to stay until completed toHide.removeClass( "ui-accordion-content-active" ); // Work around for rendering bug in IE (#5421) @@ -437,123 +454,19 @@ $.widget( "ui.accordion", { } }); -$.extend( $.ui.accordion, { - animations: { - slide: function( options, additions ) { - if ( options.prevShow || options.prevHide ) { - options.prevHide.stop( true, true ); - options.toHide = options.prevShow; - } - - var showOverflow = options.toShow.css( "overflow" ), - showOverflowX = options.toHide.css( "overflowX" ), - showOverflowY = options.toHide.css( "overflowY" ), - hideOverflow = options.toHide.css( "overflow" ), - hideOverflowX = options.toHide.css( "overflowX" ), - hideOverflowY = options.toHide.css( "overflowY" ), - percentDone = 0, - showProps = {}, - hideProps = {}, - fxAttrs = [ "height", "paddingTop", "paddingBottom" ], - originalWidth; - options = $.extend({ - easing: "swing", - duration: 300 - }, options, additions ); - - options.widget.lastToggle = options; - - if ( !options.toHide.size() ) { - originalWidth = options.toShow[0].style.width; - options.toShow - .show() - .width( options.toShow.width() ) - .hide() - .animate({ - height: "show", - paddingTop: "show", - paddingBottom: "show" - }, { - duration: options.duration, - easing: options.easing, - complete: function() { - options.toShow.width( originalWidth ); - options.complete(); - } - }); - return; - } - if ( !options.toShow.size() ) { - options.toHide.animate({ - height: "hide", - paddingTop: "hide", - paddingBottom: "hide" - }, options ); - return; - } - // fix width before calculating height of hidden element - var s = options.toShow; - originalWidth = s[0].style.width; - s.width( s.parent().width() - - parseFloat( s.css( "paddingLeft" ) ) - - parseFloat( s.css( "paddingRight" ) ) - - ( parseFloat( s.css( "borderLeftWidth" ) ) || 0 ) - - ( parseFloat( s.css( "borderRightWidth" ) ) || 0 ) ); - - $.each( fxAttrs, function( i, prop ) { - hideProps[ prop ] = "hide"; - - var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ ), - // work around bug when a panel has no height - #7335 - propVal = prop === "height" && parts[ 1 ] === "0" ? 1 : parts[ 1 ]; - showProps[ prop ] = { - value: propVal, - unit: parts[ 2 ] || "px" - }; - }); - options.toShow.css({ height: 0, overflow: "hidden" }).show(); - options.toHide - .filter( ":hidden" ) - .each( options.complete ) - .end() - .filter( ":visible" ) - .animate( hideProps, { - step: function( now, settings ) { - if ( settings.prop == "height" || settings.prop == "paddingTop" || settings.prop == "paddingBottom" ) { - percentDone = ( settings.end - settings.start === 0 ) ? 0 : - ( settings.now - settings.start ) / ( settings.end - settings.start ); - } - - options.toShow[ 0 ].style[ settings.prop ] = - ( percentDone * showProps[ settings.prop ].value ) - + showProps[ settings.prop ].unit; - }, - duration: options.duration, - easing: options.easing, - complete: function() { - options.toShow.css({ - width: originalWidth, - overflow: showOverflow, - overflowX: showOverflowX, - overflowY: showOverflowY - }); - options.toHide.css({ - overflow: hideOverflow, - overflowX: hideOverflowX, - overflowY: hideOverflowY - }); - options.complete(); - } - }); - }, - bounceslide: function( options ) { - this.slide( options, { - easing: options.down ? "easeOutBounce" : "swing", - duration: options.down ? 1000 : 200 - }); - } - } -}); +$.fx.step.accordionHeight = function( fx ) { + var elem = $( fx.elem ), + data = elem.data( "accordionHeight" ); + elem.height( data.total - elem.outerHeight() - data.toHide.outerHeight() + elem.height() ); +}; +var hideProps = {}, + showProps = {}, + showPropsAdjust = {}; +hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = + hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; +showProps.height = showProps.paddingTop = showProps.paddingBottom = + showProps.borderTopWidth = showProps.borderBottomWidth = "show"; +$.extend( showPropsAdjust, showProps, { accordionHeight: "show" } ); @@ -697,6 +610,40 @@ if ( $.uiBackCompat !== false ) { return ret; }; }( jQuery, jQuery.ui.accordion.prototype ) ); + + // animated option + // NOTE: this only provides support for "slide", "bounceslide", and easings + // not the full $.ui.accordion.animations API + (function( $, prototype ) { + $.extend( prototype.options, { + animate: null, + animated: "slide" + }); + + var _create = prototype._create; + prototype._create = function() { + var options = this.options; + if ( options.animate === null ) { + if ( !options.animated ) { + options.animate = false; + } else if ( options.animated === "slide" ) { + options.animate = 300; + } else if ( options.animated === "bounceslide" ) { + options.animate = { + duration: 200, + down: { + easing: "easeOutBounce", + duration: 1000 + } + } + } else { + options.animate = options.animated; + } + } + + _create.call( this ); + }; + }( jQuery, jQuery.ui.accordion.prototype ) ); } })( jQuery ); -- cgit v1.2.3 From f5b52a89a735082d06d6f6ea950efbccff0a227f Mon Sep 17 00:00:00 2001 From: Scott González Date: Sat, 11 Feb 2012 15:43:38 -0500 Subject: Autocomplete: Removed the timeout for the change event. Fixes #7550 - Autocomplete change event not triggered in time. Thanks spekary for finding a workaround for IE. --- tests/unit/autocomplete/autocomplete_core.js | 39 -------------------------- tests/unit/autocomplete/autocomplete_events.js | 5 +++- ui/jquery.ui.autocomplete.js | 29 +++++++++++-------- 3 files changed, 21 insertions(+), 52 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/autocomplete/autocomplete_core.js b/tests/unit/autocomplete/autocomplete_core.js index bc61b9100..ef6ea58af 100644 --- a/tests/unit/autocomplete/autocomplete_core.js +++ b/tests/unit/autocomplete/autocomplete_core.js @@ -2,45 +2,6 @@ module( "autocomplete: core" ); -asyncTest( "close-on-blur is properly delayed", function() { - expect( 3 ); - var element = $( "#autocomplete" ) - .autocomplete({ - source: [ "java", "javascript" ] - }) - .val( "ja" ) - .autocomplete( "search" ), - menu = element.autocomplete( "widget" ); - - ok( menu.is( ":visible" ) ); - element.blur(); - ok( menu.is( ":visible" ) ); - setTimeout(function() { - ok( menu.is( ":hidden") ); - start(); - }, 200 ); -}); - -asyncTest( "close-on-blur is cancelled when starting a search", function() { - expect( 3 ); - var element = $( "#autocomplete" ) - .autocomplete({ - source: [ "java", "javascript" ] - }) - .val( "ja" ) - .autocomplete( "search" ), - menu = element.autocomplete( "widget" ); - - ok( menu.is( ":visible" ) ); - element.blur(); - ok( menu.is( ":visible" ) ); - element.autocomplete( "search" ); - setTimeout(function() { - ok( menu.is( ":visible" ) ); - start(); - }, 200 ); -}); - test( "prevent form submit on enter when menu is active", function() { expect( 2 ); var event, diff --git a/tests/unit/autocomplete/autocomplete_events.js b/tests/unit/autocomplete/autocomplete_events.js index 7b51ec4c0..1c7ff7462 100644 --- a/tests/unit/autocomplete/autocomplete_events.js +++ b/tests/unit/autocomplete/autocomplete_events.js @@ -68,7 +68,10 @@ $.each([ ok( menu.is( ":visible" ), "menu is visible after delay" ); element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); - element.simulate( "blur" ); + // blur must be async for IE to handle it properly + setTimeout(function() { + element.simulate( "blur" ); + }, 1 ); }, 50 ); }); }); diff --git a/ui/jquery.ui.autocomplete.js b/ui/jquery.ui.autocomplete.js index 5646eda7a..e261b9147 100644 --- a/ui/jquery.ui.autocomplete.js +++ b/ui/jquery.ui.autocomplete.js @@ -176,13 +176,14 @@ $.widget( "ui.autocomplete", { return; } + if ( self.cancelBlur ) { + delete self.cancelBlur; + return; + } + clearTimeout( self.searching ); - self.cancelSearch = true; - // clicks on the menu (or a button to trigger a search) will cause a blur event - self.closing = setTimeout(function() { - self.close( event ); - self._change( event ); - }, 150 ); + self.close( event ); + self._change( event ); }); this._initSource(); this.response = function() { @@ -193,6 +194,16 @@ $.widget( "ui.autocomplete", { .appendTo( this.document.find( this.options.appendTo || "body" )[0] ) // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown) .mousedown(function( event ) { + // prevent moving focus out of the text field + event.preventDefault(); + + // IE doesn't prevent moving focus even with event.preventDefault() + // so we set a flag to know when we should ignore the blur event + self.cancelBlur = true; + setTimeout(function() { + delete self.cancelBlur; + }, 1 ); + // clicking on the scrollbar causes focus to shift to the body // but we can't detect a mouseup or a click immediately afterward // so we have to track the next mousedown and close the menu if @@ -209,11 +220,6 @@ $.widget( "ui.autocomplete", { }); }, 1 ); } - - // use another timeout to make sure the blur-event-handler on the input was already triggered - setTimeout(function() { - clearTimeout( self.closing ); - }, 13); }) .menu({ // custom key handling for now @@ -358,7 +364,6 @@ $.widget( "ui.autocomplete", { return this.close( event ); } - clearTimeout( this.closing ); if ( this._trigger( "search", event ) === false ) { return; } -- cgit v1.2.3 From e2ca906141fc5556e06ceccd9c37d91e1116e1ca Mon Sep 17 00:00:00 2001 From: kborchers Date: Fri, 17 Feb 2012 16:05:12 -0600 Subject: Menu: Clean up tests to remove nested setTimeout calls --- tests/unit/menu/menu_events.js | 266 ++++++++++++++++++++++------------------- 1 file changed, 143 insertions(+), 123 deletions(-) (limited to 'tests/unit') diff --git a/tests/unit/menu/menu_events.js b/tests/unit/menu/menu_events.js index c7031b282..6b03efb3c 100644 --- a/tests/unit/menu/menu_events.js +++ b/tests/unit/menu/menu_events.js @@ -87,48 +87,55 @@ asyncTest( "handle submenu auto collapse: mouseleave", function() { var $menu = $( "#menu2" ).menu(); $menu.find( "li:nth-child(7)" ).trigger( "mouseover" ); - setTimeout(function() { + setTimeout( menumouseleave1, 350 ); + + function menumouseleave1() { equal( $menu.find( "ul[aria-expanded='true']" ).length, 1, "first submenu expanded" ); $menu.find( "li:nth-child(7) li:first" ).trigger( "mouseover" ); - setTimeout(function() { - equal( $menu.find( "ul[aria-expanded='true']" ).length, 2, "second submenu expanded" ); - $menu.find( "ul[aria-expanded='true']:first" ).trigger( "mouseleave" ); - setTimeout(function() { - equal( $menu.find( "ul[aria-expanded='true']" ).length, 1, "second submenu collapsed" ); - $menu.trigger( "mouseleave" ); - setTimeout(function() { - equal( $menu.find( "ul[aria-expanded='true']" ).length, 0, "first submenu collapsed" ); - start(); - }, 1400); - }, 1050); - }, 700); - }, 350); + setTimeout( menumouseleave2, 350 ); + } + function menumouseleave2() { + equal( $menu.find( "ul[aria-expanded='true']" ).length, 2, "second submenu expanded" ); + $menu.find( "ul[aria-expanded='true']:first" ).trigger( "mouseleave" ); + setTimeout( menumouseleave3, 350 ); + } + function menumouseleave3() { + equal( $menu.find( "ul[aria-expanded='true']" ).length, 1, "second submenu collapsed" ); + $menu.trigger( "mouseleave" ); + setTimeout( menumouseleave4, 350 ); + } + function menumouseleave4() { + equal( $menu.find( "ul[aria-expanded='true']" ).length, 0, "first submenu collapsed" ); + start(); + } }); -asyncTest( "handle custom menu item submenu auto collapse: mouseleave", function() { - expect( 5 ); +asyncTest( "handle submenu auto collapse: mouseleave", function() { + expect( 4 ); var $menu = $( "#menu5" ).menu( { menus: "div" } ); - $menu.children( ":nth-child(7)" ).trigger( "mouseover" ); - setTimeout(function() { + $menu.find( ":nth-child(7)" ).trigger( "mouseover" ); + setTimeout( menumouseleave1, 350 ); + + function menumouseleave1() { equal( $menu.find( "div[aria-expanded='true']" ).length, 1, "first submenu expanded" ); - $menu.children( ":nth-child(7)" ).find( "div:first" ).children( ":first" ).trigger( "mouseover" ); - setTimeout(function() { - equal( $menu.find( "div[aria-expanded='true']" ).length, 2, "second submenu expanded" ); - $menu.find( "div[aria-expanded='true']:first" ).trigger( "mouseleave" ); - setTimeout(function() { - equal( $menu.find( "div[aria-expanded='true']" ).length, 1, "second submenu collapsed" ); - $menu.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN }); - ok( $menu.find( ".ui-state-active" ).is( "#menu5 :nth-child(7) a" ), - "down keypress selected an item from the first submenu" ); - $menu.trigger( "mouseleave" ); - setTimeout(function() { - equal( $menu.find( "div[aria-expanded='true']" ).length, 0, "first submenu collapsed" ); - start(); - }, 1400); - }, 1050); - }, 700); - }, 350); + $menu.find( ":nth-child(7)" ).find( "div" ).eq( 0 ).children().eq( 0 ).trigger( "mouseover" ); + setTimeout( menumouseleave2, 350 ); + } + function menumouseleave2() { + equal( $menu.find( "div[aria-expanded='true']" ).length, 2, "second submenu expanded" ); + $menu.find( "div[aria-expanded='true']:first" ).trigger( "mouseleave" ); + setTimeout( menumouseleave3, 350 ); + } + function menumouseleave3() { + equal( $menu.find( "div[aria-expanded='true']" ).length, 1, "second submenu collapsed" ); + $menu.trigger( "mouseleave" ); + setTimeout( menumouseleave4, 350 ); + } + function menumouseleave4() { + equal( $menu.find( "div[aria-expanded='true']" ).length, 0, "first submenu collapsed" ); + start(); + } }); @@ -206,12 +213,15 @@ asyncTest("handle keyboard navigation on menu without scroll and with submenus", }); menu_log("keydown",true); + element.one( "menufocus", function( event, ui ) { + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + equals( $("#log").html(), "2,1,keydown,", "Keydown DOWN"); + setTimeout( menukeyboard1, 50 ); + }); element.focus(); - element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - equals( $("#log").html(), "2,1,0,keydown,", "Keydown DOWN"); - setTimeout(function() { + function menukeyboard1() { menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); @@ -231,59 +241,62 @@ asyncTest("handle keyboard navigation on menu without scroll and with submenus", setTimeout( function() { equals( $("#log").html(), "0,4,3,2,1,keydown,", "Keydown RIGHT (open submenu)"); }, 50); + setTimeout( menukeyboard2, 50 ); + } - setTimeout( function() { - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); - equals( $("#log").html(), "4,keydown,", "Keydown LEFT (close submenu)"); + function menukeyboard2() { + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); + equals( $("#log").html(), "4,keydown,", "Keydown LEFT (close submenu)"); - //re-open submenu - element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ); + //re-open submenu + element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ); + setTimeout( menukeyboard3, 50 ); + } - setTimeout( function() { - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); - equals( $("#log").html(), "2,keydown,", "Keydown PAGE_DOWN"); + function menukeyboard3() { + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + equals( $("#log").html(), "2,keydown,", "Keydown PAGE_DOWN"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); - equals( $("#log").html(), "keydown,", "Keydown PAGE_DOWN (no effect)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + equals( $("#log").html(), "keydown,", "Keydown PAGE_DOWN (no effect)"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); - equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); + equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); - equals( $("#log").html(), "keydown,", "Keydown PAGE_UP (no effect)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); + equals( $("#log").html(), "keydown,", "Keydown PAGE_UP (no effect)"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.END } ); - equals( $("#log").html(), "2,keydown,", "Keydown END"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.END } ); + equals( $("#log").html(), "2,keydown,", "Keydown END"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } ); - equals( $("#log").html(), "0,keydown,", "Keydown HOME"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } ); + equals( $("#log").html(), "0,keydown,", "Keydown HOME"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); - equals( $("#log").html(), "4,keydown,", "Keydown ESCAPE (close submenu)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + equals( $("#log").html(), "4,keydown,", "Keydown ESCAPE (close submenu)"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + setTimeout( menukeyboard4, 50 ); + } - setTimeout( function() { - equals( $("#log").html(), "0,keydown,", "Keydown ENTER (open submenu)"); + function menukeyboard4() { + equals( $("#log").html(), "0,keydown,", "Keydown ENTER (open submenu)"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); - equals( $("#log").html(), "Ada,keydown,", "Keydown ENTER (select item)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + equals( $("#log").html(), "Ada,keydown,", "Keydown ENTER (select item)"); - start(); - }, 200); - }, 150); - }, 100); - }, 50); + start(); + } }); test("handle keyboard navigation on menu with scroll and without submenus", function() { @@ -369,12 +382,16 @@ asyncTest("handle keyboard navigation on menu with scroll and with submenus", fu }); menu_log("keydown",true); + element.one( "menufocus", function( event, ui ) { + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); + equals( $("#log").html(), "2,1,keydown,", "Keydown DOWN"); + setTimeout( menukeyboard1, 50 ); + }); element.focus(); - element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - element.simulate( "keydown", { keyCode: $.ui.keyCode.DOWN } ); - equals( $("#log").html(), "2,1,0,keydown,", "Keydown DOWN"); + - setTimeout(function() { + function menukeyboard1() { menu_log("keydown",true); element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); element.simulate( "keydown", { keyCode: $.ui.keyCode.UP } ); @@ -391,59 +408,62 @@ asyncTest("handle keyboard navigation on menu with scroll and with submenus", fu setTimeout( function() { equals( $("#log").html(), "0,1,keydown,", "Keydown RIGHT (open submenu)"); }, 50); + setTimeout( menukeyboard2, 50 ); + } - setTimeout( function() { - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); - equals( $("#log").html(), "1,keydown,", "Keydown LEFT (close submenu)"); + function menukeyboard2() { + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.LEFT } ); + equals( $("#log").html(), "1,keydown,", "Keydown LEFT (close submenu)"); - //re-open submenu - element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ); + //re-open submenu + element.simulate( "keydown", { keyCode: $.ui.keyCode.RIGHT } ); + setTimeout( menukeyboard3, 50 ); + } - setTimeout( function() { - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); - equals( $("#log").html(), "10,keydown,", "Keydown PAGE_DOWN"); + function menukeyboard3() { + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + equals( $("#log").html(), "10,keydown,", "Keydown PAGE_DOWN"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); - equals( $("#log").html(), "20,keydown,", "Keydown PAGE_DOWN"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_DOWN } ); + equals( $("#log").html(), "20,keydown,", "Keydown PAGE_DOWN"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); - equals( $("#log").html(), "10,keydown,", "Keydown PAGE_UP"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); + equals( $("#log").html(), "10,keydown,", "Keydown PAGE_UP"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); - equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.PAGE_UP } ); + equals( $("#log").html(), "0,keydown,", "Keydown PAGE_UP"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.END } ); - equals( $("#log").html(), "27,keydown,", "Keydown END"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.END } ); + equals( $("#log").html(), "27,keydown,", "Keydown END"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } ); - equals( $("#log").html(), "0,keydown,", "Keydown HOME"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.HOME } ); + equals( $("#log").html(), "0,keydown,", "Keydown HOME"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); - equals( $("#log").html(), "1,keydown,", "Keydown ESCAPE (close submenu)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ESCAPE } ); + equals( $("#log").html(), "1,keydown,", "Keydown ESCAPE (close submenu)"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + setTimeout( menukeyboard4, 50 ); + } - setTimeout( function() { - equals( $("#log").html(), "0,keydown,", "Keydown ENTER (open submenu)"); + function menukeyboard4() { + equals( $("#log").html(), "0,keydown,", "Keydown ENTER (open submenu)"); - menu_log("keydown",true); - element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); - equals( $("#log").html(), "Aberdeen,keydown,", "Keydown ENTER (select item)"); + menu_log("keydown",true); + element.simulate( "keydown", { keyCode: $.ui.keyCode.ENTER } ); + equals( $("#log").html(), "Aberdeen,keydown,", "Keydown ENTER (select item)"); - start(); - }, 200); - }, 150); - }, 100); - }, 50); + start(); + } }); })(jQuery); -- cgit v1.2.3