Permalink
Browse files

Event: Separate trigger/simulate into its own module

Fixes gh-1864
Closes gh-2692

This also pulls the focusin/out special event into its own module, since that
depends on simulate(). NB: The ajax module triggers events pretty heavily.
  • Loading branch information...
dmethvin committed Nov 5, 2015
1 parent 1da1448 commit c9935b6d2db9e1be4bed12f7419e98cdca45763e
Showing with 261 additions and 226 deletions.
  1. +2 −0 README.md
  2. +2 −0 src/ajax.js
  3. +1 −225 src/event.js
  4. +3 −1 src/event/alias.js
  5. +53 −0 src/event/focusin.js
  6. +199 −0 src/event/trigger.js
  7. +1 −0 src/jquery.js
View
@@ -88,6 +88,8 @@ Some example modules that can be excluded are:
- **effects**: The `.animate()` method and its shorthands such as `.slideUp()` or `.hide("slow")`.
- **event**: The `.on()` and `.off()` methods and all event functionality. Also removes `event/alias`.
- **event/alias**: All event attaching/triggering shorthands like `.click()` or `.mouseover()`.
- **event/focusin**: Cross-browser support for the focusin and focusout events.
- **event/trigger**: The `.trigger()` and `.triggerHandler()` methods. Used by **alias** and **focusin** modules.
- **offset**: The `.offset()`, `.position()`, `.offsetParent()`, `.scrollLeft()`, and `.scrollTop()` methods.
- **wrap**: The `.wrap()`, `.wrapAll()`, `.wrapInner()`, and `.unwrap()` methods.
- **core/ready**: Exclude the ready module if you place your scripts at the end of the body. Any ready callbacks bound with `jQuery()` will simply be called immediately. However, `jQuery(document).ready()` will not be a function and `.on("ready", ...)` or similar will not be triggered.
View
@@ -5,9 +5,11 @@ define( [
"./ajax/var/location",
"./ajax/var/nonce",
"./ajax/var/rquery",
"./core/init",
"./ajax/parseJSON",
"./ajax/parseXML",
"./event/trigger",
"./deferred"
], function( jQuery, document, rnotwhite, location, nonce, rquery ) {
View
@@ -2,20 +2,16 @@ define( [
"./core",
"./var/document",
"./var/rnotwhite",
"./var/hasOwn",
"./var/slice",
"./event/support",
"./data/var/dataPriv",
"./data/var/acceptData",
"./core/init",
"./selector"
], function( jQuery, document, rnotwhite, hasOwn, slice, support, dataPriv, acceptData ) {
], function( jQuery, document, rnotwhite, slice, dataPriv ) {
var
rkeyEvent = /^key/,
rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
function returnTrue() {
@@ -283,141 +279,6 @@ jQuery.event = {
}
},
trigger: function( event, data, elem, onlyHandlers ) {
var i, cur, tmp, bubbleType, ontype, handle, special,
eventPath = [ elem || document ],
type = hasOwn.call( event, "type" ) ? event.type : event,
namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
cur = tmp = elem = elem || document;
// Don't do events on text and comment nodes
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
// focus/blur morphs to focusin/out; ensure we're not firing them right now
if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
return;
}
if ( type.indexOf( "." ) > -1 ) {
// Namespaced trigger; create a regexp to match event type in handle()
namespaces = type.split( "." );
type = namespaces.shift();
namespaces.sort();
}
ontype = type.indexOf( ":" ) < 0 && "on" + type;
// Caller can pass in a jQuery.Event object, Object, or just an event type string
event = event[ jQuery.expando ] ?
event :
new jQuery.Event( type, typeof event === "object" && event );
// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
event.isTrigger = onlyHandlers ? 2 : 3;
event.namespace = namespaces.join( "." );
event.rnamespace = event.namespace ?
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
null;
// Clean up the event in case it is being reused
event.result = undefined;
if ( !event.target ) {
event.target = elem;
}
// Clone any incoming data and prepend the event, creating the handler arg list
data = data == null ?
[ event ] :
jQuery.makeArray( data, [ event ] );
// Allow special events to draw outside the lines
special = jQuery.event.special[ type ] || {};
if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
return;
}
// Determine event propagation path in advance, per W3C events spec (#9951)
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
bubbleType = special.delegateType || type;
if ( !rfocusMorph.test( bubbleType + type ) ) {
cur = cur.parentNode;
}
for ( ; cur; cur = cur.parentNode ) {
eventPath.push( cur );
tmp = cur;
}
// Only add window if we got to document (e.g., not plain obj or detached DOM)
if ( tmp === ( elem.ownerDocument || document ) ) {
eventPath.push( tmp.defaultView || tmp.parentWindow || window );
}
}
// Fire handlers on the event path
i = 0;
while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
event.type = i > 1 ?
bubbleType :
special.bindType || type;
// jQuery handler
handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
dataPriv.get( cur, "handle" );
if ( handle ) {
handle.apply( cur, data );
}
// Native handler
handle = ontype && cur[ ontype ];
if ( handle && handle.apply && acceptData( cur ) ) {
event.result = handle.apply( cur, data );
if ( event.result === false ) {
event.preventDefault();
}
}
}
event.type = type;
// If nobody prevented the default action, do it now
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
if ( ( !special._default ||
special._default.apply( eventPath.pop(), data ) === false ) &&
acceptData( elem ) ) {
// Call a native DOM method on the target with the same name name as the event.
// Don't do default actions on window, that's where global variables be (#6170)
if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
// Don't re-trigger an onFOO event when we call its FOO() method
tmp = elem[ ontype ];
if ( tmp ) {
elem[ ontype ] = null;
}
// Prevent re-triggering of the same event, since we already bubbled it above
jQuery.event.triggered = type;
elem[ type ]();
jQuery.event.triggered = undefined;
if ( tmp ) {
elem[ ontype ] = tmp;
}
}
}
}
return event.result;
},
dispatch: function( event ) {
// Make a writable jQuery.Event from the native event object
@@ -667,37 +528,6 @@ jQuery.event = {
}
}
}
},
// Piggyback on a donor event to simulate a different one
simulate: function( type, elem, event ) {
var e = jQuery.extend(
new jQuery.Event(),
event,
{
type: type,
isSimulated: true
// Previously, `originalEvent: {}` was set here, so stopPropagation call
// would not be triggered on donor event, since in our own
// jQuery.event.stopPropagation function we had a check for existence of
// originalEvent.stopPropagation method, so, consequently it would be a noop.
//
// But now, this "simulate" function is used only for events
// for which stopPropagation() is noop, so there is no need for that anymore.
//
// For the compat branch though, guard for "click" and "submit"
// events is still used, but was moved to jQuery.event.stopPropagation function
// because `originalEvent` should point to the original event for the constancy
// with other events and for more focused logic
}
);
jQuery.event.trigger( e, null, elem );
if ( e.isDefaultPrevented() ) {
event.preventDefault();
}
}
};
@@ -823,48 +653,6 @@ jQuery.each( {
};
} );
// Support: Firefox
// Firefox doesn't have focus(in | out) events
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
//
// Support: Chrome, Safari
// focus(in | out) events fire after focus & blur events,
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857
if ( !support.focusin ) {
jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
// Attach a single capturing handler on the document while someone wants focusin/focusout
var handler = function( event ) {
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
};
jQuery.event.special[ fix ] = {
setup: function() {
var doc = this.ownerDocument || this,
attaches = dataPriv.access( doc, fix );
if ( !attaches ) {
doc.addEventListener( orig, handler, true );
}
dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
},
teardown: function() {
var doc = this.ownerDocument || this,
attaches = dataPriv.access( doc, fix ) - 1;
if ( !attaches ) {
doc.removeEventListener( orig, handler, true );
dataPriv.remove( doc, fix );
} else {
dataPriv.access( doc, fix, attaches );
}
}
};
} );
}
jQuery.fn.extend( {
on: function( types, selector, data, fn ) {
@@ -908,18 +696,6 @@ jQuery.fn.extend( {
return this.each( function() {
jQuery.event.remove( this, types, fn, selector );
} );
},
trigger: function( type, data ) {
return this.each( function() {
jQuery.event.trigger( type, data, this );
} );
},
triggerHandler: function( type, data ) {
var elem = this[ 0 ];
if ( elem ) {
return jQuery.event.trigger( type, data, elem, true );
}
}
} );
View
@@ -1,6 +1,8 @@
define( [
"../core",
"../event"
"../event",
"./trigger"
], function( jQuery ) {
jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
View
@@ -0,0 +1,53 @@
define( [
"../core",
"../data/var/dataPriv",
"./support",
"../event",
"./trigger"
], function( jQuery, dataPriv, support ) {
// Support: Firefox
// Firefox doesn't have focus(in | out) events
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
//
// Support: Chrome, Safari
// focus(in | out) events fire after focus & blur events,
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857
if ( !support.focusin ) {
jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
// Attach a single capturing handler on the document while someone wants focusin/focusout
var handler = function( event ) {
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
};
jQuery.event.special[ fix ] = {
setup: function() {
var doc = this.ownerDocument || this,
attaches = dataPriv.access( doc, fix );
if ( !attaches ) {
doc.addEventListener( orig, handler, true );
}
dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
},
teardown: function() {
var doc = this.ownerDocument || this,
attaches = dataPriv.access( doc, fix ) - 1;
if ( !attaches ) {
doc.removeEventListener( orig, handler, true );
dataPriv.remove( doc, fix );
} else {
dataPriv.access( doc, fix, attaches );
}
}
};
} );
}
return jQuery;
} );
Oops, something went wrong.

0 comments on commit c9935b6

Please sign in to comment.