From: Aeron Glemann Date: Fri, 10 Aug 2012 22:48:37 +0000 (-0600) Subject: https://github.com/fnagel/jquery-ui/issues/241 X-Git-Tag: selectmenu_v1.2.2~4^2~1 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=3a751b70826e3388e14595204492a3a4c1c89b05;p=jquery-ui.git https://github.com/fnagel/jquery-ui/issues/241 Updated jquery.simulate.js to latest Fixed broken path in tests/jquery.js Updated test to not use jquery.simulate for keypress (simulate was failing, not the test) Fixed #241 in jquery.ui.selectmenu.js Added the option object as optional parameter to formatText --- diff --git a/tests/jquery.js b/tests/jquery.js index 2c8d8c25c..f60383855 100644 --- a/tests/jquery.js +++ b/tests/jquery.js @@ -18,7 +18,7 @@ for ( ; i < length; i++ ) { if ( version === "git" ) { url = "http://code.jquery.com/jquery-git.js"; } else { - url = "../../jquery-" + ( version || "1.7.2" ) + ".js"; + url = "../../../jquery-" + ( version || "1.7.2" ) + ".js"; } document.write( "" ); diff --git a/tests/jquery.simulate.js b/tests/jquery.simulate.js index 93ac47b38..b978a6f6b 100644 --- a/tests/jquery.simulate.js +++ b/tests/jquery.simulate.js @@ -1,60 +1,64 @@ /* * jquery.simulate - simulate browser mouse and keyboard events + * http://jqueryui.com * - * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT or GPL Version 2 licenses. + * Copyright 2012 jQuery Foundation and other contributors + * Released under the MIT license. * http://jquery.org/license - * */ ;(function( $ ) { -$.fn.extend({ - simulate: function( type, options ) { - return this.each(function() { - var opt = $.extend( {}, $.simulate.defaults, options ); - new $.simulate( this, type, opt ); - }); - } -}); +var rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|contextmenu)|click/; -$.simulate = function( el, type, options ) { - this.target = el; +$.fn.simulate = function( type, options ) { + return this.each(function() { + new $.simulate( this, type, options ); + }); +}; + +$.simulate = function( elem, type, options ) { + var method = $.camelCase( "simulate-" + type ); + + this.target = elem; this.options = options; - if ( type === "drag" ) { - this[ type ].apply( this, [ this.target, options ] ); - } else if ( type === "focus" || type === "blur" ) { - this[ type ](); + if ( this[ method ] ) { + this[ method ](); } else { - this.simulateEvent( el, type, options ); + this.simulateEvent( elem, type, options ); } }; $.extend( $.simulate.prototype, { - simulateEvent: function( el, type, options ) { - var evt = this.createEvent( type, options ); - this.dispatchEvent( el, type, evt, options ); - return evt; + simulateEvent: function( elem, type, options ) { + var event = this.createEvent( type, options ); + this.dispatchEvent( elem, type, event, options ); }, + createEvent: function( type, options ) { - if ( /^mouse(over|out|down|up|move)|(dbl)?click$/.test( type ) ) { + if ( rkeyEvent.test( type ) ) { + return this.keyEvent( type, options ); + } + + if ( rmouseEvent.test( type ) ) { return this.mouseEvent( type, options ); - } else if ( /^key(up|down|press)$/.test( type ) ) { - return this.keyboardEvent( type, options ); } }, + mouseEvent: function( type, options ) { - var evt, eventDoc, doc, body; - var e = $.extend({ + var event, eventDoc, doc, body; + options = $.extend({ bubbles: true, cancelable: (type !== "mousemove"), view: window, detail: 0, screenX: 0, screenY: 0, - clientX: 0, - clientY: 0, + // TODO: default clientX/Y to a position within the target element + clientX: 1, + clientY: 1, ctrlKey: false, altKey: false, shiftKey: false, @@ -63,49 +67,50 @@ $.extend( $.simulate.prototype, { relatedTarget: undefined }, options ); - var relatedTarget = $( e.relatedTarget )[0]; + if ( document.createEvent ) { + event = document.createEvent( "MouseEvents" ); + event.initMouseEvent( type, options.bubbles, options.cancelable, + options.view, options.detail, + options.screenX, options.screenY, options.clientX, options.clientY, + options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, + options.button, options.relatedTarget || document.body.parentNode ); - if ( $.isFunction( document.createEvent ) ) { - evt = document.createEvent( "MouseEvents" ); - evt.initMouseEvent( type, e.bubbles, e.cancelable, e.view, e.detail, - e.screenX, e.screenY, e.clientX, e.clientY, - e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, - e.button, e.relatedTarget || document.body.parentNode ); - // IE 9+ creates events with pageX and pageY set to 0. // Trying to modify the properties throws an error, // so we define getters to return the correct values. - if ( evt.pageX === 0 && evt.pageY === 0 && Object.defineProperty ) { - eventDoc = evt.relatedTarget.ownerDocument || document; + if ( event.pageX === 0 && event.pageY === 0 && Object.defineProperty ) { + eventDoc = event.relatedTarget.ownerDocument || document; doc = eventDoc.documentElement; body = eventDoc.body; - Object.defineProperty( evt, "pageX", { + Object.defineProperty( event, "pageX", { get: function() { - return e.clientX + + return options.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); } }); - Object.defineProperty( evt, "pageY", { + Object.defineProperty( event, "pageY", { get: function() { - return e.clientY + + return options.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); } }); } } else if ( document.createEventObject ) { - evt = document.createEventObject(); - $.extend( evt, e ); - evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button; + event = document.createEventObject(); + $.extend( event, options ); + // TODO: what is this mapping for? + event.button = { 0:1, 1:4, 2:2 }[ event.button ] || event.button; } - return evt; + + return event; }, - keyboardEvent: function( type, options ) { - var evt; - var e = $.extend({ + keyEvent: function( type, options ) { + var event; + options = $.extend({ bubbles: true, cancelable: true, view: window, @@ -117,75 +122,51 @@ $.extend( $.simulate.prototype, { charCode: undefined }, options ); - if ( $.isFunction( document.createEvent ) ) { + if ( document.createEvent ) { try { - evt = document.createEvent( "KeyEvents" ); - evt.initKeyEvent( type, e.bubbles, e.cancelable, e.view, - e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, - e.keyCode, e.charCode ); + event = document.createEvent( "KeyEvents" ); + event.initKeyEvent( type, options.bubbles, options.cancelable, options.view, + options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, + options.keyCode, options.charCode ); + // TODO: what is this supporting? } catch( err ) { - evt = document.createEvent( "Events" ); - evt.initEvent( type, e.bubbles, e.cancelable ); - $.extend(evt, { - view: e.view, - ctrlKey: e.ctrlKey, - altKey: e.altKey, - shiftKey: e.shiftKey, - metaKey: e.metaKey, - keyCode: e.keyCode, - charCode: e.charCode + event = document.createEvent( "Events" ); + event.initEvent( type, options.bubbles, options.cancelable ); + $.extend( event, { + view: options.view, + ctrlKey: options.ctrlKey, + altKey: options.altKey, + shiftKey: options.shiftKey, + metaKey: options.metaKey, + keyCode: options.keyCode, + charCode: options.charCode }); } } else if ( document.createEventObject ) { - evt = document.createEventObject(); - $.extend( evt, e ); + event = document.createEventObject(); + $.extend( event, options ); } + + // TODO: can we hook into core's logic? if ( $.browser.msie || $.browser.opera ) { - evt.keyCode = (e.charCode > 0) ? e.charCode : e.keyCode; - evt.charCode = undefined; + // TODO: is charCode ever <0 ? Can we just use charCode || keyCode? + event.keyCode = (options.charCode > 0) ? options.charCode : options.keyCode; + event.charCode = undefined; } - return evt; - }, - dispatchEvent: function( el, type, evt ) { - if ( el.dispatchEvent ) { - el.dispatchEvent( evt ); - } else if ( el.fireEvent ) { - el.fireEvent( "on" + type, evt ); - } - return evt; + return event; }, - drag: function( el ) { - var self = this, - center = this.findCenter(this.target), - options = this.options, - x = Math.floor( center.x ), - y = Math.floor( center.y ), - dx = options.dx || 0, - dy = options.dy || 0, - target = this.target, - coord = { clientX: x, clientY: y }; - this.simulateEvent( target, "mousedown", coord ); - coord = { clientX: x + 1, clientY: y + 1 }; - this.simulateEvent( document, "mousemove", coord ); - coord = { clientX: x + dx, clientY: y + dy }; - this.simulateEvent( document, "mousemove", coord ); - this.simulateEvent( document, "mousemove", coord ); - this.simulateEvent( target, "mouseup", coord ); - this.simulateEvent( target, "click", coord ); - }, - findCenter: function( el ) { - var el = $( this.target ), - o = el.offset(), - d = $( document ); - return { - x: o.left + el.outerWidth() / 2 - d.scrollLeft(), - y: o.top + el.outerHeight() / 2 - d.scrollTop() - }; + // TODO: does this need type? Can't we just check event.type? + dispatchEvent: function( elem, type, event ) { + if ( elem.dispatchEvent ) { + elem.dispatchEvent( event ); + } else if ( elem.fireEvent ) { + elem.fireEvent( "on" + type, event ); + } }, - focus: function() { + simulateFocus: function() { var focusinEvent, triggered = false, element = $( this.target ); @@ -206,7 +187,7 @@ $.extend( $.simulate.prototype, { element.unbind( "focus", trigger ); }, - blur: function() { + simulateBlur: function() { var focusoutEvent, triggered = false, element = $( this.target ); @@ -238,21 +219,41 @@ $.extend( $.simulate.prototype, { } }); -$.extend( $.simulate, { - defaults: { - speed: "sync" - }, - VK_TAB: 9, - VK_ENTER: 13, - VK_ESC: 27, - VK_PGUP: 33, - VK_PGDN: 34, - VK_END: 35, - VK_HOME: 36, - VK_LEFT: 37, - VK_UP: 38, - VK_RIGHT: 39, - VK_DOWN: 40 + + +/** complex events **/ + +function findCenter( elem ) { + var offset, + document = $( elem.ownerDocument ); + elem = $( elem ); + offset = elem.offset(); + + return { + x: offset.left + elem.outerWidth() / 2 - document.scrollLeft(), + y: offset.top + elem.outerHeight() / 2 - document.scrollTop() + }; +} + +$.extend( $.simulate.prototype, { + simulateDrag: function() { + var target = this.target, + options = this.options, + center = findCenter( target ), + x = Math.floor( center.x ), + y = Math.floor( center.y ), + dx = options.dx || 0, + dy = options.dy || 0, + coord = { clientX: x, clientY: y }; + this.simulateEvent( target, "mousedown", coord ); + coord = { clientX: x + 1, clientY: y + 1 }; + this.simulateEvent( document, "mousemove", coord ); + coord = { clientX: x + dx, clientY: y + dy }; + this.simulateEvent( document, "mousemove", coord ); + this.simulateEvent( document, "mousemove", coord ); + this.simulateEvent( target, "mouseup", coord ); + this.simulateEvent( target, "click", coord ); + } }); -})( jQuery ); +})( jQuery ); \ No newline at end of file diff --git a/tests/unit/selectmenu/selectmenu_tickets.js b/tests/unit/selectmenu/selectmenu_tickets.js index 83032befc..8bf644ea8 100644 --- a/tests/unit/selectmenu/selectmenu_tickets.js +++ b/tests/unit/selectmenu/selectmenu_tickets.js @@ -17,8 +17,10 @@ test('#241 - "focus" doesn\'t bubble', function() { $('.ui-selectmenu-menu-dropdown').simulate('keydown', { keyCode: $.ui.keyCode.DOWN }); ok($('.ui-selectmenu-menu li:eq(1)').hasClass('ui-selectmenu-item-focus'), 'after down arrow press, second item should have focus'); - - $('.ui-selectmenu-menu-dropdown').simulate('keypress', { keyCode: 'a'.charCodeAt(0) }); + + // simulate('keypress') not working consistently in all browsers + var e = new $.Event('keypress', { which: 'a'.charCodeAt(0) }); + $('.ui-selectmenu-menu-dropdown').trigger(e); ok($('.ui-selectmenu-menu li:eq(2)').hasClass('ui-selectmenu-item-focus'), 'after "a" key press, third item should have focus'); }); diff --git a/ui/jquery.ui.selectmenu.js b/ui/jquery.ui.selectmenu.js index ae0a953fc..809dd2118 100644 --- a/ui/jquery.ui.selectmenu.js +++ b/ui/jquery.ui.selectmenu.js @@ -280,7 +280,7 @@ $.widget("ui.selectmenu", { var opt = $(this); selectOptionData.push({ value: opt.attr('value'), - text: self._formatText(opt.text()), + text: self._formatText(opt.text(), opt), selected: opt.attr('selected'), disabled: opt.attr('disabled'), classes: opt.attr('class'), @@ -308,12 +308,7 @@ $.widget("ui.selectmenu", { href : '#nogo', tabindex : -1, role : 'option', - 'aria-selected' : false, - focus: function() { - // bubble the focus event - // TODO: this isnt a clean solution, see #241 - $(this).parent().focus(); - } + 'aria-selected' : false }; if ( selectOptionData[ i ].disabled ) { thisAAttr[ 'aria-disabled' ] = selectOptionData[ i ].disabled; @@ -321,7 +316,13 @@ $.widget("ui.selectmenu", { if ( selectOptionData[ i ].typeahead ) { thisAAttr[ 'typeahead' ] = selectOptionData[ i ].typeahead; } - var thisA = $('', thisAAttr); + var thisA = $('', thisAAttr) + .bind('focus.selectmenu', function(e) { + $(this).parent().mouseover(); + }) + .bind('blur.selectmenu', function() { + $(this).parent().mouseout(); + }); var thisLi = $('
  • ', thisLiAttr) .append(thisA) .data('index', i) @@ -342,15 +343,15 @@ $.widget("ui.selectmenu", { .bind("click.selectmenu", function() { return false; }) - .bind('mouseover.selectmenu focus.selectmenu', function(e) { + .bind('mouseover.selectmenu', function(e) { // no hover if diabled - if (!$(e.currentTarget).hasClass(self.namespace + '-state-disabled') && !$(e.currentTarget).parent("ul").parent("li").hasClass(self.namespace + '-state-disabled')) { + if (!$(this).hasClass(self.namespace + '-state-disabled') && !$(this).parent("ul").parent("li").hasClass(self.namespace + '-state-disabled')) { self._selectedOptionLi().addClass(activeClass); self._focusedOptionLi().removeClass(self.widgetBaseClass + '-item-focus ui-state-hover'); $(this).removeClass('ui-state-active').addClass(self.widgetBaseClass + '-item-focus ui-state-hover'); } }) - .bind('mouseout.selectmenu blur.selectmenu', function() { + .bind('mouseout.selectmenu', function() { if ($(this).is(self._selectedOptionLi().selector)) { $(this).addClass(activeClass); } @@ -628,9 +629,9 @@ $.widget("ui.selectmenu", { } }, - _formatText: function(text) { + _formatText: function(text, opt) { if (this.options.format) { - text = this.options.format(text); + text = this.options.format(text, opt); } else if (this.options.escapeHtml) { text = $('
    ').text(text).html(); } @@ -758,7 +759,6 @@ $.widget("ui.selectmenu", { return $(elem).hasClass( this.namespace + '-state-disabled' ); }, - _disableOption: function(index) { var optionElem = this._optionLis.eq(index); if (optionElem) {