event.js 19 KB

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