You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

712 lines
19KB

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