]> source.dussan.org Git - jquery-ui.git/commitdiff
https://github.com/fnagel/jquery-ui/issues/241
authorAeron Glemann <aglemann@backcountry.com>
Fri, 10 Aug 2012 22:48:37 +0000 (16:48 -0600)
committerAeron Glemann <aglemann@backcountry.com>
Fri, 10 Aug 2012 22:48:37 +0000 (16:48 -0600)
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

tests/jquery.js
tests/jquery.simulate.js
tests/unit/selectmenu/selectmenu_tickets.js
ui/jquery.ui.selectmenu.js

index 2c8d8c25cbc27b2749a405f348337b0d8e10a892..f60383855319ef9f9bbfd550d299b910dec6e0d0 100644 (file)
@@ -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( "<script src='" + url + "'></script>" );
index 93ac47b388e7eff6cf3e12366a5fcda3dd9bc0d5..b978a6f6be4cc78187308b6570b2e90a27d8ee70 100644 (file)
@@ -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
index 83032befce304cf240efbbc3a33a5345cb2452e8..8bf644ea81d3f083d8bf84e17200613dcedfcc24 100644 (file)
@@ -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');
 });
 
index ae0a953fc10675a856e3c86378c4defe74579b47..809dd211862350ac75cf5a957a767e0c662c7fde 100644 (file)
@@ -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 = $('<a/>', thisAAttr);
+                               var thisA = $('<a/>', thisAAttr)
+                                   .bind('focus.selectmenu', function(e) {
+                                               $(this).parent().mouseover();
+                                       })
+                                       .bind('blur.selectmenu', function() {
+                                               $(this).parent().mouseout();
+                                       });                                     
                                var thisLi = $('<li/>', 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 = $('<div />').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) {