jquery.simulate.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*!
  2. * jQuery Simulate v@VERSION - simulate browser mouse and keyboard events
  3. * https://github.com/jquery/jquery-simulate
  4. *
  5. * Copyright 2012 jQuery Foundation and other contributors
  6. * Released under the MIT license.
  7. * http://jquery.org/license
  8. *
  9. * Date: @DATE
  10. */
  11. ;(function ($, undefined) {
  12. var rkeyEvent = /^key/,
  13. rmouseEvent = /^(?:mouse|contextmenu)|click/;
  14. $.fn.simulate = function (type, options) {
  15. return this.each(function () {
  16. new $.simulate(this, type, options);
  17. });
  18. };
  19. $.simulate = function (elem, type, options) {
  20. var method = $.camelCase("simulate-" + type);
  21. this.target = elem;
  22. this.options = options;
  23. if (this[method]) {
  24. this[method]();
  25. } else {
  26. this.simulateEvent(elem, type, options);
  27. }
  28. };
  29. $.extend($.simulate, {
  30. keyCode: {
  31. BACKSPACE: 8,
  32. COMMA: 188,
  33. DELETE: 46,
  34. DOWN: 40,
  35. END: 35,
  36. ENTER: 13,
  37. ESCAPE: 27,
  38. HOME: 36,
  39. LEFT: 37,
  40. NUMPAD_ADD: 107,
  41. NUMPAD_DECIMAL: 110,
  42. NUMPAD_DIVIDE: 111,
  43. NUMPAD_ENTER: 108,
  44. NUMPAD_MULTIPLY: 106,
  45. NUMPAD_SUBTRACT: 109,
  46. PAGE_DOWN: 34,
  47. PAGE_UP: 33,
  48. PERIOD: 190,
  49. RIGHT: 39,
  50. SPACE: 32,
  51. TAB: 9,
  52. UP: 38
  53. },
  54. buttonCode: {
  55. LEFT: 0,
  56. MIDDLE: 1,
  57. RIGHT: 2
  58. }
  59. });
  60. $.extend($.simulate.prototype, {
  61. simulateEvent: function simulateEvent(elem, type, options) {
  62. var event = this.createEvent(type, options);
  63. this.dispatchEvent(elem, type, event, options);
  64. },
  65. createEvent: function createEvent(type, options) {
  66. if (rkeyEvent.test(type)) {
  67. return this.keyEvent(type, options);
  68. }
  69. if (rmouseEvent.test(type)) {
  70. return this.mouseEvent(type, options);
  71. }
  72. },
  73. mouseEvent: function mouseEvent(type, options) {
  74. var event, eventDoc, doc, body;
  75. options = $.extend({
  76. bubbles: true,
  77. cancelable: type !== "mousemove",
  78. view: window,
  79. detail: 0,
  80. screenX: 0,
  81. screenY: 0,
  82. clientX: 1,
  83. clientY: 1,
  84. ctrlKey: false,
  85. altKey: false,
  86. shiftKey: false,
  87. metaKey: false,
  88. button: 0,
  89. relatedTarget: undefined
  90. }, options);
  91. if (document.createEvent) {
  92. event = document.createEvent("MouseEvents");
  93. event.initMouseEvent(type, options.bubbles, options.cancelable, options.view, options.detail, options.screenX, options.screenY, options.clientX, options.clientY, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, options.relatedTarget || document.body.parentNode);
  94. // IE 9+ creates events with pageX and pageY set to 0.
  95. // Trying to modify the properties throws an error,
  96. // so we define getters to return the correct values.
  97. if (event.pageX === 0 && event.pageY === 0 && Object.defineProperty) {
  98. eventDoc = event.relatedTarget.ownerDocument || document;
  99. doc = eventDoc.documentElement;
  100. body = eventDoc.body;
  101. Object.defineProperty(event, "pageX", {
  102. get: function get() {
  103. return options.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
  104. }
  105. });
  106. Object.defineProperty(event, "pageY", {
  107. get: function get() {
  108. return options.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
  109. }
  110. });
  111. }
  112. } else if (document.createEventObject) {
  113. try {
  114. event = document.createEventObject(options);
  115. } catch (e) {
  116. event = document.createEventObject();
  117. $.extend(event, options);
  118. }
  119. // standards event.button uses constants defined here: http://msdn.microsoft.com/en-us/library/ie/ff974877(v=vs.85).aspx
  120. // old IE event.button uses constants defined here: http://msdn.microsoft.com/en-us/library/ie/ms533544(v=vs.85).aspx
  121. // so we actually need to map the standard back to oldIE
  122. event.button = {
  123. 0: 1,
  124. 1: 4,
  125. 2: 2
  126. }[event.button] || (event.button === -1 ? 0 : event.button);
  127. }
  128. return event;
  129. },
  130. keyEvent: function keyEvent(type, options) {
  131. var event;
  132. options = $.extend({
  133. bubbles: true,
  134. cancelable: true,
  135. view: window,
  136. ctrlKey: false,
  137. altKey: false,
  138. shiftKey: false,
  139. metaKey: false,
  140. keyCode: 0,
  141. charCode: undefined
  142. }, options);
  143. if (document.createEvent) {
  144. try {
  145. event = document.createEvent("KeyEvents");
  146. event.initKeyEvent(type, options.bubbles, options.cancelable, options.view, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.keyCode, options.charCode);
  147. // initKeyEvent throws an exception in WebKit
  148. // see: http://stackoverflow.com/questions/6406784/initkeyevent-keypress-only-works-in-firefox-need-a-cross-browser-solution
  149. // and also https://bugs.webkit.org/show_bug.cgi?id=13368
  150. // fall back to a generic event until we decide to implement initKeyboardEvent
  151. } catch (err) {
  152. event = document.createEvent("Events");
  153. event.initEvent(type, options.bubbles, options.cancelable);
  154. $.extend(event, {
  155. view: options.view,
  156. ctrlKey: options.ctrlKey,
  157. altKey: options.altKey,
  158. shiftKey: options.shiftKey,
  159. metaKey: options.metaKey,
  160. keyCode: options.keyCode,
  161. charCode: options.charCode
  162. });
  163. }
  164. } else if (document.createEventObject) {
  165. event = document.createEventObject();
  166. $.extend(event, options);
  167. }
  168. if (!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()) || {}.toString.call(window.opera) === "[object Opera]") {
  169. event.keyCode = options.charCode > 0 ? options.charCode : options.keyCode;
  170. event.charCode = undefined;
  171. }
  172. return event;
  173. },
  174. dispatchEvent: function dispatchEvent(elem, type, event) {
  175. if (elem[type]) {
  176. elem[type]();
  177. } else if (elem.dispatchEvent) {
  178. elem.dispatchEvent(event);
  179. } else if (elem.fireEvent) {
  180. elem.fireEvent("on" + type, event);
  181. }
  182. },
  183. simulateFocus: function simulateFocus() {
  184. var focusinEvent,
  185. triggered = false,
  186. element = $(this.target);
  187. function trigger() {
  188. triggered = true;
  189. }
  190. element.bind("focus", trigger);
  191. element[0].focus();
  192. if (!triggered) {
  193. focusinEvent = $.Event("focusin");
  194. focusinEvent.preventDefault();
  195. element.trigger(focusinEvent);
  196. element.triggerHandler("focus");
  197. }
  198. element.unbind("focus", trigger);
  199. },
  200. simulateBlur: function simulateBlur() {
  201. var focusoutEvent,
  202. triggered = false,
  203. element = $(this.target);
  204. function trigger() {
  205. triggered = true;
  206. }
  207. element.bind("blur", trigger);
  208. element[0].blur();
  209. // blur events are async in IE
  210. setTimeout(function () {
  211. // IE won't let the blur occur if the window is inactive
  212. if (element[0].ownerDocument.activeElement === element[0]) {
  213. element[0].ownerDocument.body.focus();
  214. }
  215. // Firefox won't trigger events if the window is inactive
  216. // IE doesn't trigger events if we had to manually focus the body
  217. if (!triggered) {
  218. focusoutEvent = $.Event("focusout");
  219. focusoutEvent.preventDefault();
  220. element.trigger(focusoutEvent);
  221. element.triggerHandler("blur");
  222. }
  223. element.unbind("blur", trigger);
  224. }, 1);
  225. }
  226. });
  227. /** complex events **/
  228. function findCenter(elem) {
  229. var offset,
  230. document = $(elem.ownerDocument);
  231. elem = $(elem);
  232. offset = elem.offset();
  233. return {
  234. x: offset.left + elem.outerWidth() / 2 - document.scrollLeft(),
  235. y: offset.top + elem.outerHeight() / 2 - document.scrollTop()
  236. };
  237. }
  238. function findCorner(elem) {
  239. var offset,
  240. document = $(elem.ownerDocument);
  241. elem = $(elem);
  242. offset = elem.offset();
  243. return {
  244. x: offset.left - document.scrollLeft(),
  245. y: offset.top - document.scrollTop()
  246. };
  247. }
  248. $.extend($.simulate.prototype, {
  249. simulateDrag: function simulateDrag() {
  250. var i = 0,
  251. target = this.target,
  252. options = this.options,
  253. center = options.handle === "corner" ? findCorner(target) : findCenter(target),
  254. x = Math.floor(center.x),
  255. y = Math.floor(center.y),
  256. coord = { clientX: x, clientY: y },
  257. dx = options.dx || (options.x !== undefined ? options.x - x : 0),
  258. dy = options.dy || (options.y !== undefined ? options.y - y : 0),
  259. moves = options.moves || 3;
  260. this.simulateEvent(target, "mousedown", coord);
  261. for (; i < moves; i++) {
  262. x += dx / moves;
  263. y += dy / moves;
  264. coord = {
  265. clientX: Math.round(x),
  266. clientY: Math.round(y)
  267. };
  268. this.simulateEvent(target.ownerDocument, "mousemove", coord);
  269. }
  270. if ($.contains(document, target)) {
  271. this.simulateEvent(target, "mouseup", coord);
  272. this.simulateEvent(target, "click", coord);
  273. } else {
  274. this.simulateEvent(document, "mouseup", coord);
  275. }
  276. }
  277. });
  278. })(jQuery);