PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/Client/MicrosoftAjax/Extensions/Sys/UI/DomEvent.js

#
JavaScript | 362 lines | 261 code | 13 blank | 88 comment | 79 complexity | 5721c99c609238543c0a36c3820ae2e8 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. $type = Sys.UI.DomEvent = function DomEvent(eventObject) {
  2. /// <summary locid="M:J#Sys.UI.DomEvent.#ctor">A cross-browser object that represents event properties.</summary>
  3. /// <param name="eventObject">The browser-specific event object (window.event for IE).</param>
  4. /// <field name="altKey" type="Boolean" locid="F:J#Sys.UI.DomEvent.altKey"></field>
  5. /// <field name="button" type="Sys.UI.MouseButton" locid="F:J#Sys.UI.DomEvent.button"></field>
  6. /// <field name="charCode" type="Number" integer="true" locid="F:J#Sys.UI.DomEvent.charCode">The character code for the pressed key.</field>
  7. /// <field name="clientX" type="Number" integer="true" locid="F:J#Sys.UI.DomEvent.clientX"></field>
  8. /// <field name="clientY" type="Number" integer="true" locid="F:J#Sys.UI.DomEvent.clientY"></field>
  9. /// <field name="ctrlKey" type="Boolean" locid="F:J#Sys.UI.DomEvent.ctrlKey"></field>
  10. /// <field name="keyCode" type="Number" integer="true" locid="F:J#Sys.UI.DomEvent.keyCode">The key code for the pressed key.</field>
  11. /// <field name="offsetX" type="Number" integer="true" locid="F:J#Sys.UI.DomEvent.offsetX"></field>
  12. /// <field name="offsetY" type="Number" integer="true" locid="F:J#Sys.UI.DomEvent.offsetY"></field>
  13. /// <field name="screenX" type="Number" integer="true" locid="F:J#Sys.UI.DomEvent.screenX"></field>
  14. /// <field name="screenY" type="Number" integer="true" locid="F:J#Sys.UI.DomEvent.screenY"></field>
  15. /// <field name="shiftKey" type="Boolean" locid="F:J#Sys.UI.DomEvent.shiftKey"></field>
  16. /// <field name="target" locid="F:J#Sys.UI.DomEvent.target"></field>
  17. /// <field name="type" type="String" locid="F:J#Sys.UI.DomEvent.type"></field>
  18. //#if DEBUG
  19. var e = Function._validateParams(arguments, [
  20. {name: "eventObject"}
  21. ]);
  22. if (e) throw e;
  23. //#endif
  24. var ev = eventObject;
  25. var etype = this.type = ev.type.toLowerCase();
  26. this.rawEvent = ev;
  27. this.altKey = ev.altKey;
  28. if (typeof(ev.button) !== 'undefined') {
  29. this.button = (typeof(ev.which) !== 'undefined') ? ev.button :
  30. (ev.button === 4) ? Sys.UI.MouseButton.middleButton :
  31. (ev.button === 2) ? Sys.UI.MouseButton.rightButton :
  32. Sys.UI.MouseButton.leftButton;
  33. }
  34. if (etype === 'keypress') {
  35. this.charCode = ev.charCode || ev.keyCode;
  36. }
  37. else if (ev.keyCode && (ev.keyCode === 46)) {
  38. this.keyCode = 127;
  39. }
  40. else {
  41. this.keyCode = ev.keyCode;
  42. }
  43. this.clientX = ev.clientX;
  44. this.clientY = ev.clientY;
  45. this.ctrlKey = ev.ctrlKey;
  46. this.target = ev.target || ev.srcElement;
  47. if (!etype.startsWith('key')) {
  48. if ((typeof(ev.offsetX) !== 'undefined') && (typeof(ev.offsetY) !== 'undefined')) {
  49. this.offsetX = ev.offsetX;
  50. this.offsetY = ev.offsetY;
  51. }
  52. else if (this.target && (this.target.nodeType !== 3) && (typeof(ev.clientX) === 'number')) {
  53. var loc = Sys.UI.DomElement.getLocation(this.target);
  54. var w = Sys.UI.DomElement._getWindow(this.target);
  55. this.offsetX = (w.pageXOffset || 0) + ev.clientX - loc.x;
  56. this.offsetY = (w.pageYOffset || 0) + ev.clientY - loc.y;
  57. }
  58. }
  59. this.screenX = ev.screenX;
  60. this.screenY = ev.screenY;
  61. this.shiftKey = ev.shiftKey;
  62. }
  63. $type.prototype = {
  64. preventDefault: function DomEvent$preventDefault() {
  65. /// <summary locid="M:J#Sys.UI.DomEvent.preventDefault">Prevents the default event action from happening. For example, a textbox keydown event, if suppressed, will prevent the character from being appended to the textbox.</summary>
  66. //#if DEBUG
  67. if (arguments.length !== 0) throw Error.parameterCount();
  68. //#endif
  69. var raw = this.rawEvent;
  70. if (raw.preventDefault) {
  71. raw.preventDefault();
  72. }
  73. else if (window.event) {
  74. raw.returnValue = false;
  75. }
  76. },
  77. stopPropagation: function DomEvent$stopPropagation() {
  78. /// <summary locid="M:J#Sys.UI.DomEvent.stopPropagation">Prevents the event from being propagated to parent elements.</summary>
  79. //#if DEBUG
  80. if (arguments.length !== 0) throw Error.parameterCount();
  81. //#endif
  82. var raw = this.rawEvent;
  83. if (raw.stopPropagation) {
  84. raw.stopPropagation();
  85. }
  86. else if (window.event) {
  87. raw.cancelBubble = true;
  88. }
  89. }
  90. }
  91. $type.registerClass('Sys.UI.DomEvent');
  92. $addHandler = $type.addHandler = function DomEvent$addHandler(elements, eventName, handler, autoRemove) {
  93. /// <summary locid="M:J#Sys.UI.DomEvent.addHandler">A cross-browser way to add a DOM event handler to an element.</summary>
  94. /// <param name="elements">The element or text node, or array of elements or text nodes, that exposes the event. You may also pass a DOM selector or array of DOM selectors.</param>
  95. /// <param name="eventName" type="String">The name of the event. Do not include the 'on' prefix, for example, 'click' instead of 'onclick'.</param>
  96. /// <param name="handler" type="Function">The event handler to add.</param>
  97. /// <param name="autoRemove" type="Boolean" optional="true" mayBeNull="true">Whether the handler should be removed automatically when the element is disposed of, such as when an UpdatePanel refreshes, or Sys.Application.disposeElement is called.</param>
  98. //#if DEBUG
  99. var e = Function._validateParams(arguments, [
  100. {name: "elements"},
  101. {name: "eventName", type: String},
  102. {name: "handler", type: Function},
  103. {name: "autoRemove", type: Boolean, mayBeNull: true, optional: true}
  104. ]);
  105. if (e) throw e;
  106. //#endif
  107. //#if DEBUG
  108. if (eventName === "error") throw Error.invalidOperation(Sys.Res.addHandlerCantBeUsedForError);
  109. //#endif
  110. Sys.query(elements).each(function() {
  111. var nodeType = this.nodeType;
  112. if (nodeType === 3 || nodeType === 2 || nodeType === 8) return;
  113. //#if DEBUG
  114. Sys.UI.DomEvent._ensureDomNode(this);
  115. //#endif
  116. if (!this._events) {
  117. this._events = {};
  118. }
  119. var eventCache = this._events[eventName];
  120. if (!eventCache) {
  121. this._events[eventName] = eventCache = [];
  122. }
  123. var element = this,
  124. browserHandler;
  125. if (this.addEventListener) {
  126. browserHandler = function(e) {
  127. return handler.call(element, new Sys.UI.DomEvent(e));
  128. }
  129. this.addEventListener(eventName, browserHandler, false);
  130. }
  131. else if (this.attachEvent) {
  132. browserHandler = function() {
  133. // window.event can be denied access in some rare circumstances (DevDiv 68929)
  134. var ex, ev = {};
  135. // We want to use the window for the event element, not the window for this script (DevDiv 63167)
  136. try {ev = Sys.UI.DomElement._getWindow(element).event} catch(ex) {}
  137. return handler.call(element, new Sys.UI.DomEvent(ev));
  138. }
  139. this.attachEvent('on' + eventName, browserHandler);
  140. }
  141. eventCache.push({handler: handler, browserHandler: browserHandler, autoRemove: autoRemove });
  142. if (autoRemove) {
  143. // element.dispose called when an updatepanel refreshes or disposeElement called.
  144. Sys.UI.DomElement._onDispose(this, Sys.UI.DomEvent._disposeHandlers);
  145. }
  146. });
  147. }
  148. Sys.registerPlugin({
  149. name: "addHandler",
  150. dom: true,
  151. //#if DEBUG
  152. returnType: "Sys.ElementSet",
  153. description: "A cross-browser way to add a DOM event handler to an element.",
  154. parameters: [
  155. {name: "eventName", type: "String", description: "The name of the event. Do not include the 'on' prefix, for example, 'click' instead of 'onclick'."},
  156. {name: "handler", type: "Function", description: "The event handler to add."},
  157. {name: "autoRemove", type: "Boolean", description: "Whether the handler should be removed automatically when the element is disposed of, such as when an UpdatePanel refreshes, or Sys.Application.disposeElement is called."}
  158. ],
  159. //#endif
  160. plugin: function (eventName, handler, autoRemove) {
  161. Sys.UI.DomEvent.addHandler(this.get(), eventName, handler, autoRemove);
  162. return this;
  163. }
  164. });
  165. $addHandlers = $type.addHandlers = function DomEvent$addHandlers(elements, events, handlerOwner, autoRemove) {
  166. /// <summary locid="M:J#Sys.UI.DomEvent.addHandlers">Adds a list of event handlers to an element. If a handlerOwner is specified, delegates are created with each of the handlers.</summary>
  167. /// <param name="elements">The element or text node, or array of element or text nodes, that exposes the event. You may also pass a DOM selector or array of DOM selectors.</param>
  168. /// <param name="events" type="Object">A dictionary of event handlers.</param>
  169. /// <param name="handlerOwner" optional="true" mayBeNull="true">The owner of the event handlers that will be the this pointer for the delegates that will be created from the handlers.</param>
  170. /// <param name="autoRemove" type="Boolean" optional="true" mayBeNull="true">Whether the handler should be removed automatically when the element is disposed of, such as when an UpdatePanel refreshes, or when Sys.Application.disposeElement is called.</param>
  171. //#if DEBUG
  172. var e = Function._validateParams(arguments, [
  173. {name: "elements"},
  174. {name: "events", type: Object},
  175. {name: "handlerOwner", mayBeNull: true, optional: true},
  176. {name: "autoRemove", type: Boolean, mayBeNull: true, optional: true}
  177. ]);
  178. if (e) throw e;
  179. //#endif
  180. Sys.query(elements).each(function() {
  181. var nodeType = this.nodeType;
  182. if (nodeType === 3 || nodeType === 2 || nodeType === 8) return;
  183. //#if DEBUG
  184. Sys.UI.DomEvent._ensureDomNode(this);
  185. //#endif
  186. for (var name in events) {
  187. var handler = events[name];
  188. //#if DEBUG
  189. if (typeof(handler) !== 'function') throw Error.invalidOperation(Sys.Res.cantAddNonFunctionhandler);
  190. //#endif
  191. if (handlerOwner) {
  192. handler = Function.createDelegate(handlerOwner, handler);
  193. }
  194. $addHandler(this, name, handler, autoRemove || false);
  195. }
  196. });
  197. }
  198. Sys.registerPlugin({
  199. name: "addHandlers",
  200. dom: true,
  201. //#if DEBUG
  202. returnType: "Sys.ElementSet",
  203. description: "Adds a list of event handlers to an element. If a handlerOwner is specified, delegates are created with each of the handlers.",
  204. parameters: [
  205. {name: "events", type: "Object", description: "A dictionary of event handlers."},
  206. {name: "handlerOwner", description: "The owner of the event handlers that will be the this pointer for the delegates that will be created from the handlers."},
  207. {name: "autoRemove", type: "Boolean", description: "Whether the handler should be removed automatically when the element is disposed of, such as when an UpdatePanel refreshes, or Sys.Application.disposeElement is called."}
  208. ],
  209. //#endif
  210. plugin: function (events, handlerOwner, autoRemove) {
  211. Sys.UI.DomEvent.addHandlers(this.get(), events, handlerOwner, autoRemove);
  212. return this;
  213. }
  214. });
  215. $clearHandlers = $type.clearHandlers = function DomEvent$clearHandlers(elements) {
  216. /// <summary locid="M:J#Sys.UI.DomEvent.clearHandlers">Clears all the event handlers that were added to the element or array of elements.</summary>
  217. /// <param name="elements">The element or text node, or an array of elements or text nodes. You may also pass a DOM selector or array of DOM selectors.</param>
  218. //#if DEBUG
  219. var e = Function._validateParams(arguments, [
  220. {name: "elements"}
  221. ]);
  222. if (e) throw e;
  223. //#endif
  224. Sys.query(elements).each(function() {
  225. var nodeType = this.nodeType;
  226. if (nodeType === 3 || nodeType === 2 || nodeType === 8) return;
  227. //#if DEBUG
  228. Sys.UI.DomEvent._ensureDomNode(this);
  229. //#endif
  230. Sys.UI.DomEvent._clearHandlers(this, false);
  231. });
  232. }
  233. Sys.registerPlugin({
  234. name: "clearHandlers",
  235. dom: true,
  236. //#if DEBUG
  237. returnType: "Sys.ElementSet",
  238. description: "Clears all the event handlers that were added to the element or array of elements.",
  239. //#endif
  240. plugin: function() {
  241. Sys.UI.DomEvent.clearHandlers(this.get());
  242. return this;
  243. }
  244. });
  245. $type._clearHandlers = function DomEvent$_clearHandlers(elements, autoRemoving) {
  246. Sys.query(elements).each(function() {
  247. var nodeType = this.nodeType;
  248. if (nodeType === 3 || nodeType === 2 || nodeType === 8) return;
  249. //#if DEBUG
  250. Sys.UI.DomEvent._ensureDomNode(this);
  251. //#endif
  252. var cache = this._events;
  253. if (cache) {
  254. for (var name in cache) {
  255. var handlers = cache[name];
  256. for (var i = handlers.length - 1; i >= 0; i--) {
  257. var entry = handlers[i];
  258. if (!autoRemoving || entry.autoRemove) {
  259. $removeHandler(this, name, entry.handler);
  260. }
  261. }
  262. }
  263. }
  264. });
  265. }
  266. $type._disposeHandlers = function DomEvent$_disposeHandlers() {
  267. Sys.UI.DomEvent._clearHandlers(this, true);
  268. }
  269. $removeHandler = $type.removeHandler = function DomEvent$removeHandler(elements, eventName, handler) {
  270. /// <summary locid="M:J#Sys.UI.DomEvent.removeHandler">A cross-browser way to remove a DOM event handler from an element.</summary>
  271. /// <param name="elements">The element or text node, or array of elements or text nodes, that exposes the event. You may also pass a DOM selector or array of DOM selectors.</param>
  272. /// <param name="eventName" type="String">The name of the event. Do not include the 'on' prefix, for example, 'click' instead of 'onclick'.</param>
  273. /// <param name="handler" type="Function">The event handler to remove.</param>
  274. //#if DEBUG
  275. var e = Function._validateParams(arguments, [
  276. {name: "elements"},
  277. {name: "eventName", type: String},
  278. {name: "handler", type: Function}
  279. ]);
  280. if (e) throw e;
  281. //#endif
  282. Sys.UI.DomEvent._removeHandler(elements, eventName, handler);
  283. }
  284. $type._removeHandler = function DomEvent$_removeHandler(elements, eventName, handler) {
  285. Sys.query(elements).each(function() {
  286. var nodeType = this.nodeType;
  287. if (nodeType === 3 || nodeType === 2 || nodeType === 8) return;
  288. //#if DEBUG
  289. Sys.UI.DomEvent._ensureDomNode(this);
  290. //#endif
  291. var browserHandler = null;
  292. //#if DEBUG
  293. if ((typeof(this._events) !== 'object') || !this._events) throw Error.invalidOperation(Sys.Res.eventHandlerInvalid);
  294. //#endif
  295. var cache = this._events[eventName];
  296. //#if DEBUG
  297. if (!(cache instanceof Array)) throw Error.invalidOperation(Sys.Res.eventHandlerInvalid);
  298. //#endif
  299. for (var i = 0, l = cache.length; i < l; i++) {
  300. if (cache[i].handler === handler) {
  301. browserHandler = cache[i].browserHandler;
  302. break;
  303. }
  304. }
  305. //#if DEBUG
  306. if (typeof(browserHandler) !== 'function') throw Error.invalidOperation(Sys.Res.eventHandlerInvalid);
  307. //#endif
  308. if (this.removeEventListener) {
  309. this.removeEventListener(eventName, browserHandler, false);
  310. }
  311. else if (this.detachEvent) {
  312. this.detachEvent('on' + eventName, browserHandler);
  313. }
  314. cache.splice(i, 1);
  315. });
  316. }
  317. Sys.registerPlugin({
  318. name: "removeHandler",
  319. dom: true,
  320. //#if DEBUG
  321. returnType: "Sys.ElementSet",
  322. description: "A cross-browser way to remove a DOM event handler from an element.",
  323. parameters: [
  324. {name: "eventName", type: "String", description: "The name of the event. Do not include the 'on' prefix, for example, 'click' instead of 'onclick'."},
  325. {name: "handler", type: "Function", description: "The event handler to remove."}
  326. ],
  327. //#endif
  328. plugin: function (eventName, handler) {
  329. Sys.UI.DomEvent.removeHandler(this.get(), eventName, handler);
  330. return this;
  331. }
  332. });
  333. //#if DEBUG
  334. $type._ensureDomNode = function DomEvent$_ensureDomNode(element) {
  335. // DevDiv Bugs 100697: Accessing element.document causes dynamic script nodes to load prematurely.
  336. // DevDiv Bugs 124696: Firefox warns on undefined property element.tagName, added first part of IF
  337. // DevDiv Bugs 146697: tagName needs to be case insensitive to work with xhtml content type
  338. if (element && element.tagName && (element.tagName.toUpperCase() === "SCRIPT")) return;
  339. var doc = element ? (element.ownerDocument || element.document || element) : null;
  340. // Can't use _getWindow here and compare to the element to check if it's a window
  341. // because the object Safari exposes as document.defaultView is not the window (DevDiv 100229)
  342. // Looking at the document property instead to include window in DOM nodes, then comparing to the
  343. // document for this element and finally look for the nodeType property.
  344. if (!element ||
  345. ((typeof(element.document) !== 'object') && (element != doc) && (typeof(element.nodeType) !== 'number'))) {
  346. throw Error.argument("element", Sys.Res.argumentDomNode);
  347. }
  348. }
  349. //#endif