jquery.simulate.js 9.4 KB

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