trigger.js (5438B)
1 define( [ 2 "../core", 3 "../var/document", 4 "../data/var/dataPriv", 5 "../data/var/acceptData", 6 "../var/hasOwn", 7 "../var/isFunction", 8 "../var/isWindow", 9 "../event" 10 ], function( jQuery, document, dataPriv, acceptData, hasOwn, isFunction, isWindow ) { 11 12 "use strict"; 13 14 var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, 15 stopPropagationCallback = function( e ) { 16 e.stopPropagation(); 17 }; 18 19 jQuery.extend( jQuery.event, { 20 21 trigger: function( event, data, elem, onlyHandlers ) { 22 23 var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, 24 eventPath = [ elem || document ], 25 type = hasOwn.call( event, "type" ) ? event.type : event, 26 namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; 27 28 cur = lastElement = tmp = elem = elem || document; 29 30 // Don't do events on text and comment nodes 31 if ( elem.nodeType === 3 || elem.nodeType === 8 ) { 32 return; 33 } 34 35 // focus/blur morphs to focusin/out; ensure we're not firing them right now 36 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { 37 return; 38 } 39 40 if ( type.indexOf( "." ) > -1 ) { 41 42 // Namespaced trigger; create a regexp to match event type in handle() 43 namespaces = type.split( "." ); 44 type = namespaces.shift(); 45 namespaces.sort(); 46 } 47 ontype = type.indexOf( ":" ) < 0 && "on" + type; 48 49 // Caller can pass in a jQuery.Event object, Object, or just an event type string 50 event = event[ jQuery.expando ] ? 51 event : 52 new jQuery.Event( type, typeof event === "object" && event ); 53 54 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) 55 event.isTrigger = onlyHandlers ? 2 : 3; 56 event.namespace = namespaces.join( "." ); 57 event.rnamespace = event.namespace ? 58 new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : 59 null; 60 61 // Clean up the event in case it is being reused 62 event.result = undefined; 63 if ( !event.target ) { 64 event.target = elem; 65 } 66 67 // Clone any incoming data and prepend the event, creating the handler arg list 68 data = data == null ? 69 [ event ] : 70 jQuery.makeArray( data, [ event ] ); 71 72 // Allow special events to draw outside the lines 73 special = jQuery.event.special[ type ] || {}; 74 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { 75 return; 76 } 77 78 // Determine event propagation path in advance, per W3C events spec (trac-9951) 79 // Bubble up to document, then to window; watch for a global ownerDocument var (trac-9724) 80 if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { 81 82 bubbleType = special.delegateType || type; 83 if ( !rfocusMorph.test( bubbleType + type ) ) { 84 cur = cur.parentNode; 85 } 86 for ( ; cur; cur = cur.parentNode ) { 87 eventPath.push( cur ); 88 tmp = cur; 89 } 90 91 // Only add window if we got to document (e.g., not plain obj or detached DOM) 92 if ( tmp === ( elem.ownerDocument || document ) ) { 93 eventPath.push( tmp.defaultView || tmp.parentWindow || window ); 94 } 95 } 96 97 // Fire handlers on the event path 98 i = 0; 99 while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { 100 lastElement = cur; 101 event.type = i > 1 ? 102 bubbleType : 103 special.bindType || type; 104 105 // jQuery handler 106 handle = ( dataPriv.get( cur, "events" ) || Object.create( null ) )[ event.type ] && 107 dataPriv.get( cur, "handle" ); 108 if ( handle ) { 109 handle.apply( cur, data ); 110 } 111 112 // Native handler 113 handle = ontype && cur[ ontype ]; 114 if ( handle && handle.apply && acceptData( cur ) ) { 115 event.result = handle.apply( cur, data ); 116 if ( event.result === false ) { 117 event.preventDefault(); 118 } 119 } 120 } 121 event.type = type; 122 123 // If nobody prevented the default action, do it now 124 if ( !onlyHandlers && !event.isDefaultPrevented() ) { 125 126 if ( ( !special._default || 127 special._default.apply( eventPath.pop(), data ) === false ) && 128 acceptData( elem ) ) { 129 130 // Call a native DOM method on the target with the same name as the event. 131 // Don't do default actions on window, that's where global variables be (trac-6170) 132 if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { 133 134 // Don't re-trigger an onFOO event when we call its FOO() method 135 tmp = elem[ ontype ]; 136 137 if ( tmp ) { 138 elem[ ontype ] = null; 139 } 140 141 // Prevent re-triggering of the same event, since we already bubbled it above 142 jQuery.event.triggered = type; 143 144 if ( event.isPropagationStopped() ) { 145 lastElement.addEventListener( type, stopPropagationCallback ); 146 } 147 148 elem[ type ](); 149 150 if ( event.isPropagationStopped() ) { 151 lastElement.removeEventListener( type, stopPropagationCallback ); 152 } 153 154 jQuery.event.triggered = undefined; 155 156 if ( tmp ) { 157 elem[ ontype ] = tmp; 158 } 159 } 160 } 161 } 162 163 return event.result; 164 }, 165 166 // Piggyback on a donor event to simulate a different one 167 // Used only for `focus(in | out)` events 168 simulate: function( type, elem, event ) { 169 var e = jQuery.extend( 170 new jQuery.Event(), 171 event, 172 { 173 type: type, 174 isSimulated: true 175 } 176 ); 177 178 jQuery.event.trigger( e, null, elem ); 179 } 180 181 } ); 182 183 jQuery.fn.extend( { 184 185 trigger: function( type, data ) { 186 return this.each( function() { 187 jQuery.event.trigger( type, data, this ); 188 } ); 189 }, 190 triggerHandler: function( type, data ) { 191 var elem = this[ 0 ]; 192 if ( elem ) { 193 return jQuery.event.trigger( type, data, elem, true ); 194 } 195 } 196 } ); 197 198 return jQuery; 199 } );