Skip to content

Commit c9935b6

Browse files
committed
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.
1 parent 1da1448 commit c9935b6

File tree

7 files changed

+261
-226
lines changed

7 files changed

+261
-226
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ Some example modules that can be excluded are:
8888
- **effects**: The `.animate()` method and its shorthands such as `.slideUp()` or `.hide("slow")`.
8989
- **event**: The `.on()` and `.off()` methods and all event functionality. Also removes `event/alias`.
9090
- **event/alias**: All event attaching/triggering shorthands like `.click()` or `.mouseover()`.
91+
- **event/focusin**: Cross-browser support for the focusin and focusout events.
92+
- **event/trigger**: The `.trigger()` and `.triggerHandler()` methods. Used by **alias** and **focusin** modules.
9193
- **offset**: The `.offset()`, `.position()`, `.offsetParent()`, `.scrollLeft()`, and `.scrollTop()` methods.
9294
- **wrap**: The `.wrap()`, `.wrapAll()`, `.wrapInner()`, and `.unwrap()` methods.
9395
- **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.

src/ajax.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ define( [
55
"./ajax/var/location",
66
"./ajax/var/nonce",
77
"./ajax/var/rquery",
8+
89
"./core/init",
910
"./ajax/parseJSON",
1011
"./ajax/parseXML",
12+
"./event/trigger",
1113
"./deferred"
1214
], function( jQuery, document, rnotwhite, location, nonce, rquery ) {
1315

src/event.js

Lines changed: 1 addition & 225 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,16 @@ define( [
22
"./core",
33
"./var/document",
44
"./var/rnotwhite",
5-
"./var/hasOwn",
65
"./var/slice",
7-
"./event/support",
86
"./data/var/dataPriv",
9-
"./data/var/acceptData",
107

118
"./core/init",
129
"./selector"
13-
], function( jQuery, document, rnotwhite, hasOwn, slice, support, dataPriv, acceptData ) {
10+
], function( jQuery, document, rnotwhite, slice, dataPriv ) {
1411

1512
var
1613
rkeyEvent = /^key/,
1714
rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
18-
rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
1915
rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
2016

2117
function returnTrue() {
@@ -283,141 +279,6 @@ jQuery.event = {
283279
}
284280
},
285281

286-
trigger: function( event, data, elem, onlyHandlers ) {
287-
288-
var i, cur, tmp, bubbleType, ontype, handle, special,
289-
eventPath = [ elem || document ],
290-
type = hasOwn.call( event, "type" ) ? event.type : event,
291-
namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
292-
293-
cur = tmp = elem = elem || document;
294-
295-
// Don't do events on text and comment nodes
296-
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
297-
return;
298-
}
299-
300-
// focus/blur morphs to focusin/out; ensure we're not firing them right now
301-
if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
302-
return;
303-
}
304-
305-
if ( type.indexOf( "." ) > -1 ) {
306-
307-
// Namespaced trigger; create a regexp to match event type in handle()
308-
namespaces = type.split( "." );
309-
type = namespaces.shift();
310-
namespaces.sort();
311-
}
312-
ontype = type.indexOf( ":" ) < 0 && "on" + type;
313-
314-
// Caller can pass in a jQuery.Event object, Object, or just an event type string
315-
event = event[ jQuery.expando ] ?
316-
event :
317-
new jQuery.Event( type, typeof event === "object" && event );
318-
319-
// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
320-
event.isTrigger = onlyHandlers ? 2 : 3;
321-
event.namespace = namespaces.join( "." );
322-
event.rnamespace = event.namespace ?
323-
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
324-
null;
325-
326-
// Clean up the event in case it is being reused
327-
event.result = undefined;
328-
if ( !event.target ) {
329-
event.target = elem;
330-
}
331-
332-
// Clone any incoming data and prepend the event, creating the handler arg list
333-
data = data == null ?
334-
[ event ] :
335-
jQuery.makeArray( data, [ event ] );
336-
337-
// Allow special events to draw outside the lines
338-
special = jQuery.event.special[ type ] || {};
339-
if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
340-
return;
341-
}
342-
343-
// Determine event propagation path in advance, per W3C events spec (#9951)
344-
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
345-
if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
346-
347-
bubbleType = special.delegateType || type;
348-
if ( !rfocusMorph.test( bubbleType + type ) ) {
349-
cur = cur.parentNode;
350-
}
351-
for ( ; cur; cur = cur.parentNode ) {
352-
eventPath.push( cur );
353-
tmp = cur;
354-
}
355-
356-
// Only add window if we got to document (e.g., not plain obj or detached DOM)
357-
if ( tmp === ( elem.ownerDocument || document ) ) {
358-
eventPath.push( tmp.defaultView || tmp.parentWindow || window );
359-
}
360-
}
361-
362-
// Fire handlers on the event path
363-
i = 0;
364-
while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
365-
366-
event.type = i > 1 ?
367-
bubbleType :
368-
special.bindType || type;
369-
370-
// jQuery handler
371-
handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
372-
dataPriv.get( cur, "handle" );
373-
if ( handle ) {
374-
handle.apply( cur, data );
375-
}
376-
377-
// Native handler
378-
handle = ontype && cur[ ontype ];
379-
if ( handle && handle.apply && acceptData( cur ) ) {
380-
event.result = handle.apply( cur, data );
381-
if ( event.result === false ) {
382-
event.preventDefault();
383-
}
384-
}
385-
}
386-
event.type = type;
387-
388-
// If nobody prevented the default action, do it now
389-
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
390-
391-
if ( ( !special._default ||
392-
special._default.apply( eventPath.pop(), data ) === false ) &&
393-
acceptData( elem ) ) {
394-
395-
// Call a native DOM method on the target with the same name name as the event.
396-
// Don't do default actions on window, that's where global variables be (#6170)
397-
if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
398-
399-
// Don't re-trigger an onFOO event when we call its FOO() method
400-
tmp = elem[ ontype ];
401-
402-
if ( tmp ) {
403-
elem[ ontype ] = null;
404-
}
405-
406-
// Prevent re-triggering of the same event, since we already bubbled it above
407-
jQuery.event.triggered = type;
408-
elem[ type ]();
409-
jQuery.event.triggered = undefined;
410-
411-
if ( tmp ) {
412-
elem[ ontype ] = tmp;
413-
}
414-
}
415-
}
416-
}
417-
418-
return event.result;
419-
},
420-
421282
dispatch: function( event ) {
422283

423284
// Make a writable jQuery.Event from the native event object
@@ -667,37 +528,6 @@ jQuery.event = {
667528
}
668529
}
669530
}
670-
},
671-
672-
// Piggyback on a donor event to simulate a different one
673-
simulate: function( type, elem, event ) {
674-
var e = jQuery.extend(
675-
new jQuery.Event(),
676-
event,
677-
{
678-
type: type,
679-
isSimulated: true
680-
681-
// Previously, `originalEvent: {}` was set here, so stopPropagation call
682-
// would not be triggered on donor event, since in our own
683-
// jQuery.event.stopPropagation function we had a check for existence of
684-
// originalEvent.stopPropagation method, so, consequently it would be a noop.
685-
//
686-
// But now, this "simulate" function is used only for events
687-
// for which stopPropagation() is noop, so there is no need for that anymore.
688-
//
689-
// For the compat branch though, guard for "click" and "submit"
690-
// events is still used, but was moved to jQuery.event.stopPropagation function
691-
// because `originalEvent` should point to the original event for the constancy
692-
// with other events and for more focused logic
693-
}
694-
);
695-
696-
jQuery.event.trigger( e, null, elem );
697-
698-
if ( e.isDefaultPrevented() ) {
699-
event.preventDefault();
700-
}
701531
}
702532
};
703533

@@ -823,48 +653,6 @@ jQuery.each( {
823653
};
824654
} );
825655

826-
// Support: Firefox
827-
// Firefox doesn't have focus(in | out) events
828-
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
829-
//
830-
// Support: Chrome, Safari
831-
// focus(in | out) events fire after focus & blur events,
832-
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
833-
// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857
834-
if ( !support.focusin ) {
835-
jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
836-
837-
// Attach a single capturing handler on the document while someone wants focusin/focusout
838-
var handler = function( event ) {
839-
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
840-
};
841-
842-
jQuery.event.special[ fix ] = {
843-
setup: function() {
844-
var doc = this.ownerDocument || this,
845-
attaches = dataPriv.access( doc, fix );
846-
847-
if ( !attaches ) {
848-
doc.addEventListener( orig, handler, true );
849-
}
850-
dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
851-
},
852-
teardown: function() {
853-
var doc = this.ownerDocument || this,
854-
attaches = dataPriv.access( doc, fix ) - 1;
855-
856-
if ( !attaches ) {
857-
doc.removeEventListener( orig, handler, true );
858-
dataPriv.remove( doc, fix );
859-
860-
} else {
861-
dataPriv.access( doc, fix, attaches );
862-
}
863-
}
864-
};
865-
} );
866-
}
867-
868656
jQuery.fn.extend( {
869657

870658
on: function( types, selector, data, fn ) {
@@ -908,18 +696,6 @@ jQuery.fn.extend( {
908696
return this.each( function() {
909697
jQuery.event.remove( this, types, fn, selector );
910698
} );
911-
},
912-
913-
trigger: function( type, data ) {
914-
return this.each( function() {
915-
jQuery.event.trigger( type, data, this );
916-
} );
917-
},
918-
triggerHandler: function( type, data ) {
919-
var elem = this[ 0 ];
920-
if ( elem ) {
921-
return jQuery.event.trigger( type, data, elem, true );
922-
}
923699
}
924700
} );
925701

src/event/alias.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
define( [
22
"../core",
3-
"../event"
3+
4+
"../event",
5+
"./trigger"
46
], function( jQuery ) {
57

68
jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +

src/event/focusin.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
define( [
2+
"../core",
3+
"../data/var/dataPriv",
4+
"./support",
5+
6+
"../event",
7+
"./trigger"
8+
], function( jQuery, dataPriv, support ) {
9+
10+
// Support: Firefox
11+
// Firefox doesn't have focus(in | out) events
12+
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
13+
//
14+
// Support: Chrome, Safari
15+
// focus(in | out) events fire after focus & blur events,
16+
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
17+
// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857
18+
if ( !support.focusin ) {
19+
jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
20+
21+
// Attach a single capturing handler on the document while someone wants focusin/focusout
22+
var handler = function( event ) {
23+
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
24+
};
25+
26+
jQuery.event.special[ fix ] = {
27+
setup: function() {
28+
var doc = this.ownerDocument || this,
29+
attaches = dataPriv.access( doc, fix );
30+
31+
if ( !attaches ) {
32+
doc.addEventListener( orig, handler, true );
33+
}
34+
dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
35+
},
36+
teardown: function() {
37+
var doc = this.ownerDocument || this,
38+
attaches = dataPriv.access( doc, fix ) - 1;
39+
40+
if ( !attaches ) {
41+
doc.removeEventListener( orig, handler, true );
42+
dataPriv.remove( doc, fix );
43+
44+
} else {
45+
dataPriv.access( doc, fix, attaches );
46+
}
47+
}
48+
};
49+
} );
50+
}
51+
52+
return jQuery;
53+
} );

0 commit comments

Comments
 (0)