event.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. define( [
  2. "./core",
  3. "./var/document",
  4. "./var/documentElement",
  5. "./var/rnothtmlwhite",
  6. "./var/slice",
  7. "./data/var/dataPriv",
  8. "./core/init",
  9. "./selector"
  10. ], function( jQuery, document, documentElement, rnothtmlwhite, 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( rnothtmlwhite ) || [ "" ];
  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( rnothtmlwhite ) || [ "" ];
  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, handleObj, sel, matchedHandlers, matchedSelectors,
  288. handlerQueue = [],
  289. delegateCount = handlers.delegateCount,
  290. cur = event.target;
  291. // Find delegate handlers
  292. if ( delegateCount &&
  293. // Support: IE <=9
  294. // Black-hole SVG <use> instance trees (trac-13180)
  295. cur.nodeType &&
  296. // Support: Firefox <=42
  297. // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
  298. // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
  299. // Support: IE 11 only
  300. // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
  301. !( event.type === "click" && event.button >= 1 ) ) {
  302. for ( ; cur !== this; cur = cur.parentNode || this ) {
  303. // Don't check non-elements (#13208)
  304. // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
  305. if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
  306. matchedHandlers = [];
  307. matchedSelectors = {};
  308. for ( i = 0; i < delegateCount; i++ ) {
  309. handleObj = handlers[ i ];
  310. // Don't conflict with Object.prototype properties (#13203)
  311. sel = handleObj.selector + " ";
  312. if ( matchedSelectors[ sel ] === undefined ) {
  313. matchedSelectors[ sel ] = handleObj.needsContext ?
  314. jQuery( sel, this ).index( cur ) > -1 :
  315. jQuery.find( sel, this, null, [ cur ] ).length;
  316. }
  317. if ( matchedSelectors[ sel ] ) {
  318. matchedHandlers.push( handleObj );
  319. }
  320. }
  321. if ( matchedHandlers.length ) {
  322. handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
  323. }
  324. }
  325. }
  326. }
  327. // Add the remaining (directly-bound) handlers
  328. cur = this;
  329. if ( delegateCount < handlers.length ) {
  330. handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
  331. }
  332. return handlerQueue;
  333. },
  334. addProp: function( name, hook ) {
  335. Object.defineProperty( jQuery.Event.prototype, name, {
  336. enumerable: true,
  337. configurable: true,
  338. get: jQuery.isFunction( hook ) ?
  339. function() {
  340. if ( this.originalEvent ) {
  341. return hook( this.originalEvent );
  342. }
  343. } :
  344. function() {
  345. if ( this.originalEvent ) {
  346. return this.originalEvent[ name ];
  347. }
  348. },
  349. set: function( value ) {
  350. Object.defineProperty( this, name, {
  351. enumerable: true,
  352. configurable: true,
  353. writable: true,
  354. value: value
  355. } );
  356. }
  357. } );
  358. },
  359. fix: function( originalEvent ) {
  360. return originalEvent[ jQuery.expando ] ?
  361. originalEvent :
  362. new jQuery.Event( originalEvent );
  363. },
  364. special: {
  365. load: {
  366. // Prevent triggered image.load events from bubbling to window.load
  367. noBubble: true
  368. },
  369. focus: {
  370. // Fire native event if possible so blur/focus sequence is correct
  371. trigger: function() {
  372. if ( this !== safeActiveElement() && this.focus ) {
  373. this.focus();
  374. return false;
  375. }
  376. },
  377. delegateType: "focusin"
  378. },
  379. blur: {
  380. trigger: function() {
  381. if ( this === safeActiveElement() && this.blur ) {
  382. this.blur();
  383. return false;
  384. }
  385. },
  386. delegateType: "focusout"
  387. },
  388. click: {
  389. // For checkbox, fire native event so checked state will be right
  390. trigger: function() {
  391. if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
  392. this.click();
  393. return false;
  394. }
  395. },
  396. // For cross-browser consistency, don't fire native .click() on links
  397. _default: function( event ) {
  398. return jQuery.nodeName( event.target, "a" );
  399. }
  400. },
  401. beforeunload: {
  402. postDispatch: function( event ) {
  403. // Support: Firefox 20+
  404. // Firefox doesn't alert if the returnValue field is not set.
  405. if ( event.result !== undefined && event.originalEvent ) {
  406. event.originalEvent.returnValue = event.result;
  407. }
  408. }
  409. }
  410. }
  411. };
  412. jQuery.removeEvent = function( elem, type, handle ) {
  413. // This "if" is needed for plain objects
  414. if ( elem.removeEventListener ) {
  415. elem.removeEventListener( type, handle );
  416. }
  417. };
  418. jQuery.Event = function( src, props ) {
  419. // Allow instantiation without the 'new' keyword
  420. if ( !( this instanceof jQuery.Event ) ) {
  421. return new jQuery.Event( src, props );
  422. }
  423. // Event object
  424. if ( src && src.type ) {
  425. this.originalEvent = src;
  426. this.type = src.type;
  427. // Events bubbling up the document may have been marked as prevented
  428. // by a handler lower down the tree; reflect the correct value.
  429. this.isDefaultPrevented = src.defaultPrevented ||
  430. src.defaultPrevented === undefined &&
  431. // Support: Android <=2.3 only
  432. src.returnValue === false ?
  433. returnTrue :
  434. returnFalse;
  435. // Create target properties
  436. // Support: Safari <=6 - 7 only
  437. // Target should not be a text node (#504, #13143)
  438. this.target = ( src.target && src.target.nodeType === 3 ) ?
  439. src.target.parentNode :
  440. src.target;
  441. this.currentTarget = src.currentTarget;
  442. this.relatedTarget = src.relatedTarget;
  443. // Event type
  444. } else {
  445. this.type = src;
  446. }
  447. // Put explicitly provided properties onto the event object
  448. if ( props ) {
  449. jQuery.extend( this, props );
  450. }
  451. // Create a timestamp if incoming event doesn't have one
  452. this.timeStamp = src && src.timeStamp || jQuery.now();
  453. // Mark it as fixed
  454. this[ jQuery.expando ] = true;
  455. };
  456. // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
  457. // https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
  458. jQuery.Event.prototype = {
  459. constructor: jQuery.Event,
  460. isDefaultPrevented: returnFalse,
  461. isPropagationStopped: returnFalse,
  462. isImmediatePropagationStopped: returnFalse,
  463. isSimulated: false,
  464. preventDefault: function() {
  465. var e = this.originalEvent;
  466. this.isDefaultPrevented = returnTrue;
  467. if ( e && !this.isSimulated ) {
  468. e.preventDefault();
  469. }
  470. },
  471. stopPropagation: function() {
  472. var e = this.originalEvent;
  473. this.isPropagationStopped = returnTrue;
  474. if ( e && !this.isSimulated ) {
  475. e.stopPropagation();
  476. }
  477. },
  478. stopImmediatePropagation: function() {
  479. var e = this.originalEvent;
  480. this.isImmediatePropagationStopped = returnTrue;
  481. if ( e && !this.isSimulated ) {
  482. e.stopImmediatePropagation();
  483. }
  484. this.stopPropagation();
  485. }
  486. };
  487. // Includes all common event props including KeyEvent and MouseEvent specific props
  488. jQuery.each( {
  489. altKey: true,
  490. bubbles: true,
  491. cancelable: true,
  492. changedTouches: true,
  493. ctrlKey: true,
  494. detail: true,
  495. eventPhase: true,
  496. metaKey: true,
  497. pageX: true,
  498. pageY: true,
  499. shiftKey: true,
  500. view: true,
  501. "char": true,
  502. charCode: true,
  503. key: true,
  504. keyCode: true,
  505. button: true,
  506. buttons: true,
  507. clientX: true,
  508. clientY: true,
  509. offsetX: true,
  510. offsetY: true,
  511. pointerId: true,
  512. pointerType: true,
  513. screenX: true,
  514. screenY: true,
  515. targetTouches: true,
  516. toElement: true,
  517. touches: true,
  518. which: function( event ) {
  519. var button = event.button;
  520. // Add which for key events
  521. if ( event.which == null && rkeyEvent.test( event.type ) ) {
  522. return event.charCode != null ? event.charCode : event.keyCode;
  523. }
  524. // Add which for click: 1 === left; 2 === middle; 3 === right
  525. if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
  526. if ( button & 1 ) {
  527. return 1;
  528. }
  529. if ( button & 2 ) {
  530. return 3;
  531. }
  532. if ( button & 4 ) {
  533. return 2;
  534. }
  535. return 0;
  536. }
  537. return event.which;
  538. }
  539. }, jQuery.event.addProp );
  540. // Create mouseenter/leave events using mouseover/out and event-time checks
  541. // so that event delegation works in jQuery.
  542. // Do the same for pointerenter/pointerleave and pointerover/pointerout
  543. //
  544. // Support: Safari 7 only
  545. // Safari sends mouseenter too often; see:
  546. // https://bugs.chromium.org/p/chromium/issues/detail?id=470258
  547. // for the description of the bug (it existed in older Chrome versions as well).
  548. jQuery.each( {
  549. mouseenter: "mouseover",
  550. mouseleave: "mouseout",
  551. pointerenter: "pointerover",
  552. pointerleave: "pointerout"
  553. }, function( orig, fix ) {
  554. jQuery.event.special[ orig ] = {
  555. delegateType: fix,
  556. bindType: fix,
  557. handle: function( event ) {
  558. var ret,
  559. target = this,
  560. related = event.relatedTarget,
  561. handleObj = event.handleObj;
  562. // For mouseenter/leave call the handler if related is outside the target.
  563. // NB: No relatedTarget if the mouse left/entered the browser window
  564. if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
  565. event.type = handleObj.origType;
  566. ret = handleObj.handler.apply( this, arguments );
  567. event.type = fix;
  568. }
  569. return ret;
  570. }
  571. };
  572. } );
  573. jQuery.fn.extend( {
  574. on: function( types, selector, data, fn ) {
  575. return on( this, types, selector, data, fn );
  576. },
  577. one: function( types, selector, data, fn ) {
  578. return on( this, types, selector, data, fn, 1 );
  579. },
  580. off: function( types, selector, fn ) {
  581. var handleObj, type;
  582. if ( types && types.preventDefault && types.handleObj ) {
  583. // ( event ) dispatched jQuery.Event
  584. handleObj = types.handleObj;
  585. jQuery( types.delegateTarget ).off(
  586. handleObj.namespace ?
  587. handleObj.origType + "." + handleObj.namespace :
  588. handleObj.origType,
  589. handleObj.selector,
  590. handleObj.handler
  591. );
  592. return this;
  593. }
  594. if ( typeof types === "object" ) {
  595. // ( types-object [, selector] )
  596. for ( type in types ) {
  597. this.off( type, selector, types[ type ] );
  598. }
  599. return this;
  600. }
  601. if ( selector === false || typeof selector === "function" ) {
  602. // ( types [, fn] )
  603. fn = selector;
  604. selector = undefined;
  605. }
  606. if ( fn === false ) {
  607. fn = returnFalse;
  608. }
  609. return this.each( function() {
  610. jQuery.event.remove( this, types, fn, selector );
  611. } );
  612. }
  613. } );
  614. return jQuery;
  615. } );