event.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. define( [
  2. "./core",
  3. "./var/document",
  4. "./var/documentElement",
  5. "./var/rnotwhite",
  6. "./var/slice",
  7. "./data/var/dataPriv",
  8. "./core/init",
  9. "./selector"
  10. ], function( jQuery, document, documentElement, rnotwhite, slice, dataPriv ) {
  11. "use strict";
  12. var
  13. rkeyEvent = /^key/,
  14. rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
  15. rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
  16. function returnTrue() {
  17. return true;
  18. }
  19. function returnFalse() {
  20. return false;
  21. }
  22. // Support: IE <=9 only
  23. // See #13393 for more info
  24. function safeActiveElement() {
  25. try {
  26. return document.activeElement;
  27. } catch ( err ) { }
  28. }
  29. function on( elem, types, selector, data, fn, one ) {
  30. var origFn, type;
  31. // Types can be a map of types/handlers
  32. if ( typeof types === "object" ) {
  33. // ( types-Object, selector, data )
  34. if ( typeof selector !== "string" ) {
  35. // ( types-Object, data )
  36. data = data || selector;
  37. selector = undefined;
  38. }
  39. for ( type in types ) {
  40. on( elem, type, selector, data, types[ type ], one );
  41. }
  42. return elem;
  43. }
  44. if ( data == null && fn == null ) {
  45. // ( types, fn )
  46. fn = selector;
  47. data = selector = undefined;
  48. } else if ( fn == null ) {
  49. if ( typeof selector === "string" ) {
  50. // ( types, selector, fn )
  51. fn = data;
  52. data = undefined;
  53. } else {
  54. // ( types, data, fn )
  55. fn = data;
  56. data = selector;
  57. selector = undefined;
  58. }
  59. }
  60. if ( fn === false ) {
  61. fn = returnFalse;
  62. } else if ( !fn ) {
  63. return elem;
  64. }
  65. if ( one === 1 ) {
  66. origFn = fn;
  67. fn = function( event ) {
  68. // Can use an empty set, since event contains the info
  69. jQuery().off( event );
  70. return origFn.apply( this, arguments );
  71. };
  72. // Use same guid so caller can remove using origFn
  73. fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
  74. }
  75. return elem.each( function() {
  76. jQuery.event.add( this, types, fn, data, selector );
  77. } );
  78. }
  79. /*
  80. * Helper functions for managing events -- not part of the public interface.
  81. * Props to Dean Edwards' addEvent library for many of the ideas.
  82. */
  83. jQuery.event = {
  84. global: {},
  85. add: function( elem, types, handler, data, selector ) {
  86. var handleObjIn, eventHandle, tmp,
  87. events, t, handleObj,
  88. special, handlers, type, namespaces, origType,
  89. elemData = dataPriv.get( elem );
  90. // Don't attach events to noData or text/comment nodes (but allow plain objects)
  91. if ( !elemData ) {
  92. return;
  93. }
  94. // Caller can pass in an object of custom data in lieu of the handler
  95. if ( handler.handler ) {
  96. handleObjIn = handler;
  97. handler = handleObjIn.handler;
  98. selector = handleObjIn.selector;
  99. }
  100. // Ensure that invalid selectors throw exceptions at attach time
  101. // Evaluate against documentElement in case elem is a non-element node (e.g., document)
  102. if ( selector ) {
  103. jQuery.find.matchesSelector( documentElement, selector );
  104. }
  105. // Make sure that the handler has a unique ID, used to find/remove it later
  106. if ( !handler.guid ) {
  107. handler.guid = jQuery.guid++;
  108. }
  109. // Init the element's event structure and main handler, if this is the first
  110. if ( !( events = elemData.events ) ) {
  111. events = elemData.events = {};
  112. }
  113. if ( !( eventHandle = elemData.handle ) ) {
  114. eventHandle = elemData.handle = function( e ) {
  115. // Discard the second event of a jQuery.event.trigger() and
  116. // when an event is called after a page has unloaded
  117. return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
  118. jQuery.event.dispatch.apply( elem, arguments ) : undefined;
  119. };
  120. }
  121. // Handle multiple events separated by a space
  122. types = ( types || "" ).match( rnotwhite ) || [ "" ];
  123. t = types.length;
  124. while ( t-- ) {
  125. tmp = rtypenamespace.exec( types[ t ] ) || [];
  126. type = origType = tmp[ 1 ];
  127. namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
  128. // There *must* be a type, no attaching namespace-only handlers
  129. if ( !type ) {
  130. continue;
  131. }
  132. // If event changes its type, use the special event handlers for the changed type
  133. special = jQuery.event.special[ type ] || {};
  134. // If selector defined, determine special event api type, otherwise given type
  135. type = ( selector ? special.delegateType : special.bindType ) || type;
  136. // Update special based on newly reset type
  137. special = jQuery.event.special[ type ] || {};
  138. // handleObj is passed to all event handlers
  139. handleObj = jQuery.extend( {
  140. type: type,
  141. origType: origType,
  142. data: data,
  143. handler: handler,
  144. guid: handler.guid,
  145. selector: selector,
  146. needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
  147. namespace: namespaces.join( "." )
  148. }, handleObjIn );
  149. // Init the event handler queue if we're the first
  150. if ( !( handlers = events[ type ] ) ) {
  151. handlers = events[ type ] = [];
  152. handlers.delegateCount = 0;
  153. // Only use addEventListener if the special events handler returns false
  154. if ( !special.setup ||
  155. special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
  156. if ( elem.addEventListener ) {
  157. elem.addEventListener( type, eventHandle );
  158. }
  159. }
  160. }
  161. if ( special.add ) {
  162. special.add.call( elem, handleObj );
  163. if ( !handleObj.handler.guid ) {
  164. handleObj.handler.guid = handler.guid;
  165. }
  166. }
  167. // Add to the element's handler list, delegates in front
  168. if ( selector ) {
  169. handlers.splice( handlers.delegateCount++, 0, handleObj );
  170. } else {
  171. handlers.push( handleObj );
  172. }
  173. // Keep track of which events have ever been used, for event optimization
  174. jQuery.event.global[ type ] = true;
  175. }
  176. },
  177. // Detach an event or set of events from an element
  178. remove: function( elem, types, handler, selector, mappedTypes ) {
  179. var j, origCount, tmp,
  180. events, t, handleObj,
  181. special, handlers, type, namespaces, origType,
  182. elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
  183. if ( !elemData || !( events = elemData.events ) ) {
  184. return;
  185. }
  186. // Once for each type.namespace in types; type may be omitted
  187. types = ( types || "" ).match( rnotwhite ) || [ "" ];
  188. t = types.length;
  189. while ( t-- ) {
  190. tmp = rtypenamespace.exec( types[ t ] ) || [];
  191. type = origType = tmp[ 1 ];
  192. namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
  193. // Unbind all events (on this namespace, if provided) for the element
  194. if ( !type ) {
  195. for ( type in events ) {
  196. jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
  197. }
  198. continue;
  199. }
  200. special = jQuery.event.special[ type ] || {};
  201. type = ( selector ? special.delegateType : special.bindType ) || type;
  202. handlers = events[ type ] || [];
  203. tmp = tmp[ 2 ] &&
  204. new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
  205. // Remove matching events
  206. origCount = j = handlers.length;
  207. while ( j-- ) {
  208. handleObj = handlers[ j ];
  209. if ( ( mappedTypes || origType === handleObj.origType ) &&
  210. ( !handler || handler.guid === handleObj.guid ) &&
  211. ( !tmp || tmp.test( handleObj.namespace ) ) &&
  212. ( !selector || selector === handleObj.selector ||
  213. selector === "**" && handleObj.selector ) ) {
  214. handlers.splice( j, 1 );
  215. if ( handleObj.selector ) {
  216. handlers.delegateCount--;
  217. }
  218. if ( special.remove ) {
  219. special.remove.call( elem, handleObj );
  220. }
  221. }
  222. }
  223. // Remove generic event handler if we removed something and no more handlers exist
  224. // (avoids potential for endless recursion during removal of special event handlers)
  225. if ( origCount && !handlers.length ) {
  226. if ( !special.teardown ||
  227. special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
  228. jQuery.removeEvent( elem, type, elemData.handle );
  229. }
  230. delete events[ type ];
  231. }
  232. }
  233. // Remove data and the expando if it's no longer used
  234. if ( jQuery.isEmptyObject( events ) ) {
  235. dataPriv.remove( elem, "handle events" );
  236. }
  237. },
  238. dispatch: function( nativeEvent ) {
  239. // Make a writable jQuery.Event from the native event object
  240. var event = jQuery.event.fix( nativeEvent );
  241. var i, j, ret, matched, handleObj, handlerQueue,
  242. args = new Array( arguments.length ),
  243. handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
  244. special = jQuery.event.special[ event.type ] || {};
  245. // Use the fix-ed jQuery.Event rather than the (read-only) native event
  246. args[ 0 ] = event;
  247. for ( i = 1; i < arguments.length; i++ ) {
  248. args[ i ] = arguments[ i ];
  249. }
  250. event.delegateTarget = this;
  251. // Call the preDispatch hook for the mapped type, and let it bail if desired
  252. if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
  253. return;
  254. }
  255. // Determine handlers
  256. handlerQueue = jQuery.event.handlers.call( this, event, handlers );
  257. // Run delegates first; they may want to stop propagation beneath us
  258. i = 0;
  259. while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
  260. event.currentTarget = matched.elem;
  261. j = 0;
  262. while ( ( handleObj = matched.handlers[ j++ ] ) &&
  263. !event.isImmediatePropagationStopped() ) {
  264. // Triggered event must either 1) have no namespace, or 2) have namespace(s)
  265. // a subset or equal to those in the bound event (both can have no namespace).
  266. if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
  267. event.handleObj = handleObj;
  268. event.data = handleObj.data;
  269. ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
  270. handleObj.handler ).apply( matched.elem, args );
  271. if ( ret !== undefined ) {
  272. if ( ( event.result = ret ) === false ) {
  273. event.preventDefault();
  274. event.stopPropagation();
  275. }
  276. }
  277. }
  278. }
  279. }
  280. // Call the postDispatch hook for the mapped type
  281. if ( special.postDispatch ) {
  282. special.postDispatch.call( this, event );
  283. }
  284. return event.result;
  285. },
  286. handlers: function( event, handlers ) {
  287. var i, matches, sel, handleObj,
  288. handlerQueue = [],
  289. delegateCount = handlers.delegateCount,
  290. cur = event.target;
  291. // Support: IE <=9
  292. // Find delegate handlers
  293. // Black-hole SVG <use> instance trees (#13180)
  294. //
  295. // Support: Firefox <=42
  296. // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343)
  297. if ( delegateCount && cur.nodeType &&
  298. ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) {
  299. for ( ; cur !== this; cur = cur.parentNode || this ) {
  300. // Don't check non-elements (#13208)
  301. // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
  302. if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) {
  303. matches = [];
  304. for ( i = 0; i < delegateCount; i++ ) {
  305. handleObj = handlers[ i ];
  306. // Don't conflict with Object.prototype properties (#13203)
  307. sel = handleObj.selector + " ";
  308. if ( matches[ sel ] === undefined ) {
  309. matches[ sel ] = handleObj.needsContext ?
  310. jQuery( sel, this ).index( cur ) > -1 :
  311. jQuery.find( sel, this, null, [ cur ] ).length;
  312. }
  313. if ( matches[ sel ] ) {
  314. matches.push( handleObj );
  315. }
  316. }
  317. if ( matches.length ) {
  318. handlerQueue.push( { elem: cur, handlers: matches } );
  319. }
  320. }
  321. }
  322. }
  323. // Add the remaining (directly-bound) handlers
  324. if ( delegateCount < handlers.length ) {
  325. handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } );
  326. }
  327. return handlerQueue;
  328. },
  329. addProp: function( name, hook ) {
  330. Object.defineProperty( jQuery.Event.prototype, name, {
  331. enumerable: true,
  332. configurable: true,
  333. get: jQuery.isFunction( hook ) ?
  334. function() {
  335. if ( this.originalEvent ) {
  336. return hook( this.originalEvent );
  337. }
  338. } :
  339. function() {
  340. if ( this.originalEvent ) {
  341. return this.originalEvent[ name ];
  342. }
  343. },
  344. set: function( value ) {
  345. Object.defineProperty( this, name, {
  346. enumerable: true,
  347. configurable: true,
  348. writable: true,
  349. value: value
  350. } );
  351. }
  352. } );
  353. },
  354. fix: function( originalEvent ) {
  355. return originalEvent[ jQuery.expando ] ?
  356. originalEvent :
  357. new jQuery.Event( originalEvent );
  358. },
  359. special: {
  360. load: {
  361. // Prevent triggered image.load events from bubbling to window.load
  362. noBubble: true
  363. },
  364. focus: {
  365. // Fire native event if possible so blur/focus sequence is correct
  366. trigger: function() {
  367. if ( this !== safeActiveElement() && this.focus ) {
  368. this.focus();
  369. return false;
  370. }
  371. },
  372. delegateType: "focusin"
  373. },
  374. blur: {
  375. trigger: function() {
  376. if ( this === safeActiveElement() && this.blur ) {
  377. this.blur();
  378. return false;
  379. }
  380. },
  381. delegateType: "focusout"
  382. },
  383. click: {
  384. // For checkbox, fire native event so checked state will be right
  385. trigger: function() {
  386. if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
  387. this.click();
  388. return false;
  389. }
  390. },
  391. // For cross-browser consistency, don't fire native .click() on links
  392. _default: function( event ) {
  393. return jQuery.nodeName( event.target, "a" );
  394. }
  395. },
  396. beforeunload: {
  397. postDispatch: function( event ) {
  398. // Support: Firefox 20+
  399. // Firefox doesn't alert if the returnValue field is not set.
  400. if ( event.result !== undefined && event.originalEvent ) {
  401. event.originalEvent.returnValue = event.result;
  402. }
  403. }
  404. }
  405. }
  406. };
  407. jQuery.removeEvent = function( elem, type, handle ) {
  408. // This "if" is needed for plain objects
  409. if ( elem.removeEventListener ) {
  410. elem.removeEventListener( type, handle );
  411. }
  412. };
  413. jQuery.Event = function( src, props ) {
  414. // Allow instantiation without the 'new' keyword
  415. if ( !( this instanceof jQuery.Event ) ) {
  416. return new jQuery.Event( src, props );
  417. }
  418. // Event object
  419. if ( src && src.type ) {
  420. this.originalEvent = src;
  421. this.type = src.type;
  422. // Events bubbling up the document may have been marked as prevented
  423. // by a handler lower down the tree; reflect the correct value.
  424. this.isDefaultPrevented = src.defaultPrevented ||
  425. src.defaultPrevented === undefined &&
  426. // Support: Android <=2.3 only
  427. src.returnValue === false ?
  428. returnTrue :
  429. returnFalse;
  430. // Create target properties
  431. // Support: Safari <=6 - 7 only
  432. // Target should not be a text node (#504, #13143)
  433. this.target = ( src.target && src.target.nodeType === 3 ) ?
  434. src.target.parentNode :
  435. src.target;
  436. this.currentTarget = src.currentTarget;
  437. this.relatedTarget = src.relatedTarget;
  438. // Event type
  439. } else {
  440. this.type = src;
  441. }
  442. // Put explicitly provided properties onto the event object
  443. if ( props ) {
  444. jQuery.extend( this, props );
  445. }
  446. // Create a timestamp if incoming event doesn't have one
  447. this.timeStamp = src && src.timeStamp || jQuery.now();
  448. // Mark it as fixed
  449. this[ jQuery.expando ] = true;
  450. };
  451. // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
  452. // https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
  453. jQuery.Event.prototype = {
  454. constructor: jQuery.Event,
  455. isDefaultPrevented: returnFalse,
  456. isPropagationStopped: returnFalse,
  457. isImmediatePropagationStopped: returnFalse,
  458. isSimulated: false,
  459. preventDefault: function() {
  460. var e = this.originalEvent;
  461. this.isDefaultPrevented = returnTrue;
  462. if ( e && !this.isSimulated ) {
  463. e.preventDefault();
  464. }
  465. },
  466. stopPropagation: function() {
  467. var e = this.originalEvent;
  468. this.isPropagationStopped = returnTrue;
  469. if ( e && !this.isSimulated ) {
  470. e.stopPropagation();
  471. }
  472. },
  473. stopImmediatePropagation: function() {
  474. var e = this.originalEvent;
  475. this.isImmediatePropagationStopped = returnTrue;
  476. if ( e && !this.isSimulated ) {
  477. e.stopImmediatePropagation();
  478. }
  479. this.stopPropagation();
  480. }
  481. };
  482. // Includes all common event props including KeyEvent and MouseEvent specific props
  483. jQuery.each( {
  484. altKey: true,
  485. bubbles: true,
  486. cancelable: true,
  487. changedTouches: true,
  488. ctrlKey: true,
  489. detail: true,
  490. eventPhase: true,
  491. metaKey: true,
  492. pageX: true,
  493. pageY: true,
  494. shiftKey: true,
  495. view: true,
  496. "char": true,
  497. charCode: true,
  498. key: true,
  499. keyCode: true,
  500. button: true,
  501. buttons: true,
  502. clientX: true,
  503. clientY: true,
  504. offsetX: true,
  505. offsetY: true,
  506. pointerId: true,
  507. pointerType: true,
  508. screenX: true,
  509. screenY: true,
  510. targetTouches: true,
  511. toElement: true,
  512. touches: true,
  513. which: function( event ) {
  514. var button = event.button;
  515. // Add which for key events
  516. if ( event.which == null && rkeyEvent.test( event.type ) ) {
  517. return event.charCode != null ? event.charCode : event.keyCode;
  518. }
  519. // Add which for click: 1 === left; 2 === middle; 3 === right
  520. if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
  521. return ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
  522. }
  523. return event.which;
  524. }
  525. }, jQuery.event.addProp );
  526. // Create mouseenter/leave events using mouseover/out and event-time checks
  527. // so that event delegation works in jQuery.
  528. // Do the same for pointerenter/pointerleave and pointerover/pointerout
  529. //
  530. // Support: Safari 7 only
  531. // Safari sends mouseenter too often; see:
  532. // https://bugs.chromium.org/p/chromium/issues/detail?id=470258
  533. // for the description of the bug (it existed in older Chrome versions as well).
  534. jQuery.each( {
  535. mouseenter: "mouseover",
  536. mouseleave: "mouseout",
  537. pointerenter: "pointerover",
  538. pointerleave: "pointerout"
  539. }, function( orig, fix ) {
  540. jQuery.event.special[ orig ] = {
  541. delegateType: fix,
  542. bindType: fix,
  543. handle: function( event ) {
  544. var ret,
  545. target = this,
  546. related = event.relatedTarget,
  547. handleObj = event.handleObj;
  548. // For mouseenter/leave call the handler if related is outside the target.
  549. // NB: No relatedTarget if the mouse left/entered the browser window
  550. if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
  551. event.type = handleObj.origType;
  552. ret = handleObj.handler.apply( this, arguments );
  553. event.type = fix;
  554. }
  555. return ret;
  556. }
  557. };
  558. } );
  559. jQuery.fn.extend( {
  560. on: function( types, selector, data, fn ) {
  561. return on( this, types, selector, data, fn );
  562. },
  563. one: function( types, selector, data, fn ) {
  564. return on( this, types, selector, data, fn, 1 );
  565. },
  566. off: function( types, selector, fn ) {
  567. var handleObj, type;
  568. if ( types && types.preventDefault && types.handleObj ) {
  569. // ( event ) dispatched jQuery.Event
  570. handleObj = types.handleObj;
  571. jQuery( types.delegateTarget ).off(
  572. handleObj.namespace ?
  573. handleObj.origType + "." + handleObj.namespace :
  574. handleObj.origType,
  575. handleObj.selector,
  576. handleObj.handler
  577. );
  578. return this;
  579. }
  580. if ( typeof types === "object" ) {
  581. // ( types-object [, selector] )
  582. for ( type in types ) {
  583. this.off( type, selector, types[ type ] );
  584. }
  585. return this;
  586. }
  587. if ( selector === false || typeof selector === "function" ) {
  588. // ( types [, fn] )
  589. fn = selector;
  590. selector = undefined;
  591. }
  592. if ( fn === false ) {
  593. fn = returnFalse;
  594. }
  595. return this.each( function() {
  596. jQuery.event.remove( this, types, fn, selector );
  597. } );
  598. }
  599. } );
  600. return jQuery;
  601. } );