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