/src/event/object.js

https://github.com/timeflows/kissy · JavaScript · 182 lines · 101 code · 31 blank · 50 comment · 41 complexity · 23b16c93843824da4746d4f0d066a684 MD5 · raw file

  1. /**
  2. * @module EventObject
  3. * @author lifesinger@gmail.com
  4. */
  5. KISSY.add('event/object', function(S, undefined) {
  6. var doc = document,
  7. props = ('altKey attrChange attrName bubbles button cancelable ' +
  8. 'charCode clientX clientY ctrlKey currentTarget data detail ' +
  9. 'eventPhase fromElement handler keyCode layerX layerY metaKey ' +
  10. 'newValue offsetX offsetY originalTarget pageX pageY prevValue ' +
  11. 'relatedNode relatedTarget screenX screenY shiftKey srcElement ' +
  12. 'target toElement view wheelDelta which').split(' ');
  13. /**
  14. * KISSY's event system normalizes the event object according to
  15. * W3C standards. The event object is guaranteed to be passed to
  16. * the event handler. Most properties from the original event are
  17. * copied over and normalized to the new event object.
  18. */
  19. function EventObject(currentTarget, domEvent, type) {
  20. var self = this;
  21. self.currentTarget = currentTarget;
  22. self.originalEvent = domEvent || { };
  23. if (domEvent) { // html element
  24. self.type = domEvent.type;
  25. self._fix();
  26. }
  27. else { // custom
  28. self.type = type;
  29. self.target = currentTarget;
  30. }
  31. // bug fix: in _fix() method, ie maybe reset currentTarget to undefined.
  32. self.currentTarget = currentTarget;
  33. self.fixed = true;
  34. }
  35. S.augment(EventObject, {
  36. _fix: function() {
  37. var self = this,
  38. originalEvent = self.originalEvent,
  39. l = props.length, prop,
  40. ct = self.currentTarget,
  41. ownerDoc = (ct.nodeType === 9) ? ct : (ct.ownerDocument || doc); // support iframe
  42. // clone properties of the original event object
  43. while (l) {
  44. prop = props[--l];
  45. self[prop] = originalEvent[prop];
  46. }
  47. // fix target property, if necessary
  48. if (!self.target) {
  49. self.target = self.srcElement || doc; // srcElement might not be defined either
  50. }
  51. // check if target is a textnode (safari)
  52. if (self.target.nodeType === 3) {
  53. self.target = self.target.parentNode;
  54. }
  55. // add relatedTarget, if necessary
  56. if (!self.relatedTarget && self.fromElement) {
  57. self.relatedTarget = (self.fromElement === self.target) ? self.toElement : self.fromElement;
  58. }
  59. // calculate pageX/Y if missing and clientX/Y available
  60. if (self.pageX === undefined && self.clientX !== undefined) {
  61. var docEl = ownerDoc.documentElement, bd = ownerDoc.body;
  62. self.pageX = self.clientX + (docEl && docEl.scrollLeft || bd && bd.scrollLeft || 0) - (docEl && docEl.clientLeft || bd && bd.clientLeft || 0);
  63. self.pageY = self.clientY + (docEl && docEl.scrollTop || bd && bd.scrollTop || 0) - (docEl && docEl.clientTop || bd && bd.clientTop || 0);
  64. }
  65. // add which for key events
  66. if (self.which === undefined) {
  67. self.which = (self.charCode === undefined) ? self.keyCode : self.charCode;
  68. }
  69. // add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
  70. if (self.metaKey === undefined) {
  71. self.metaKey = self.ctrlKey;
  72. }
  73. // add which for click: 1 === left; 2 === middle; 3 === right
  74. // Note: button is not normalized, so don't use it
  75. if (!self.which && self.button !== undefined) {
  76. self.which = (self.button & 1 ? 1 : (self.button & 2 ? 3 : ( self.button & 4 ? 2 : 0)));
  77. }
  78. },
  79. /**
  80. * Prevents the event's default behavior
  81. */
  82. preventDefault: function() {
  83. var e = this.originalEvent;
  84. // if preventDefault exists run it on the original event
  85. if (e.preventDefault) {
  86. e.preventDefault();
  87. }
  88. // otherwise set the returnValue property of the original event to false (IE)
  89. else {
  90. e.returnValue = false;
  91. }
  92. this.isDefaultPrevented = true;
  93. },
  94. /**
  95. * Stops the propagation to the next bubble target
  96. */
  97. stopPropagation: function() {
  98. var e = this.originalEvent;
  99. // if stopPropagation exists run it on the original event
  100. if (e.stopPropagation) {
  101. e.stopPropagation();
  102. }
  103. // otherwise set the cancelBubble property of the original event to true (IE)
  104. else {
  105. e.cancelBubble = true;
  106. }
  107. this.isPropagationStopped = true;
  108. },
  109. /**
  110. * Stops the propagation to the next bubble target and
  111. * prevents any additional listeners from being exectued
  112. * on the current target.
  113. */
  114. stopImmediatePropagation: function() {
  115. var e = this.originalEvent;
  116. if (e.stopImmediatePropagation) {
  117. e.stopImmediatePropagation();
  118. } else {
  119. this.stopPropagation();
  120. }
  121. this.isImmediatePropagationStopped = true;
  122. },
  123. /**
  124. * Stops the event propagation and prevents the default
  125. * event behavior.
  126. * @param immediate {boolean} if true additional listeners
  127. * on the current target will not be executed
  128. */
  129. halt: function(immediate) {
  130. if (immediate) {
  131. this.stopImmediatePropagation();
  132. } else {
  133. this.stopPropagation();
  134. }
  135. this.preventDefault();
  136. }
  137. });
  138. if (1 > 2) {
  139. alert(S.cancelBubble);
  140. }
  141. return EventObject;
  142. });
  143. /**
  144. * NOTES:
  145. *
  146. * 2010.04
  147. * - http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
  148. *
  149. * TODO:
  150. * - pageX, clientX, scrollLeft, clientLeft 的详细测试
  151. */