2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
8 YUI.add('event-simulate', function(Y) {
12 * Synthetic DOM events
13 * @module event-simulate
20 isFunction = L.isFunction,
21 isString = L.isString,
22 isBoolean = L.isBoolean,
23 isObject = L.isObject,
24 isNumber = L.isNumber,
27 //mouse events supported
38 //key events supported
46 * Note: Intentionally not for YUIDoc generation.
47 * Simulates a key event using the given event information to populate
48 * the generated event object. This method does browser-equalizing
49 * calculations to account for differences in the DOM and IE event models
50 * as well as different browser quirks. Note: keydown causes Safari 2.x to
52 * @method simulateKeyEvent
55 * @param {HTMLElement} target The target of the given event.
56 * @param {String} type The type of event to fire. This can be any one of
57 * the following: keyup, keydown, and keypress.
58 * @param {Boolean} bubbles (Optional) Indicates if the event can be
59 * bubbled up. DOM Level 3 specifies that all key events bubble by
60 * default. The default is true.
61 * @param {Boolean} cancelable (Optional) Indicates if the event can be
62 * canceled using preventDefault(). DOM Level 3 specifies that all
63 * key events can be cancelled. The default
65 * @param {Window} view (Optional) The view containing the target. This is
66 * typically the window object. The default is window.
67 * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys
68 * is pressed while the event is firing. The default is false.
69 * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys
70 * is pressed while the event is firing. The default is false.
71 * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys
72 * is pressed while the event is firing. The default is false.
73 * @param {Boolean} metaKey (Optional) Indicates if one of the META keys
74 * is pressed while the event is firing. The default is false.
75 * @param {int} keyCode (Optional) The code for the key that is in use.
77 * @param {int} charCode (Optional) The Unicode code for the character
78 * associated with the key being used. The default is 0.
80 function simulateKeyEvent(target /*:HTMLElement*/, type /*:String*/,
81 bubbles /*:Boolean*/, cancelable /*:Boolean*/,
83 ctrlKey /*:Boolean*/, altKey /*:Boolean*/,
84 shiftKey /*:Boolean*/, metaKey /*:Boolean*/,
85 keyCode /*:int*/, charCode /*:int*/) /*:Void*/
89 Y.error("simulateKeyEvent(): Invalid target.");
94 type = type.toLowerCase();
96 case "textevent": //DOM Level 3
104 Y.error("simulateKeyEvent(): Event type '" + type + "' not supported.");
107 Y.error("simulateKeyEvent(): Event type must be a string.");
110 //setup default values
111 if (!isBoolean(bubbles)){
112 bubbles = true; //all key events bubble
114 if (!isBoolean(cancelable)){
115 cancelable = true; //all key events can be cancelled
117 if (!isObject(view)){
118 view = window; //view is typically window
120 if (!isBoolean(ctrlKey)){
123 if (!isBoolean(altKey)){
126 if (!isBoolean(shiftKey)){
129 if (!isBoolean(metaKey)){
132 if (!isNumber(keyCode)){
135 if (!isNumber(charCode)){
139 //try to create a mouse event
140 var customEvent /*:MouseEvent*/ = null;
142 //check for DOM-compliant browsers first
143 if (isFunction(doc.createEvent)){
147 //try to create key event
148 customEvent = doc.createEvent("KeyEvents");
151 * Interesting problem: Firefox implemented a non-standard
152 * version of initKeyEvent() based on DOM Level 2 specs.
153 * Key event was removed from DOM Level 2 and re-introduced
154 * in DOM Level 3 with a different interface. Firefox is the
155 * only browser with any implementation of Key Events, so for
156 * now, assume it's Firefox if the above line doesn't error.
158 // @TODO: Decipher between Firefox's implementation and a correct one.
159 customEvent.initKeyEvent(type, bubbles, cancelable, view, ctrlKey,
160 altKey, shiftKey, metaKey, keyCode, charCode);
162 } catch (ex /*:Error*/){
165 * If it got here, that means key events aren't officially supported.
166 * Safari/WebKit is a real problem now. WebKit 522 won't let you
167 * set keyCode, charCode, or other properties if you use a
168 * UIEvent, so we first must try to create a generic event. The
169 * fun part is that this will throw an error on Safari 2.x. The
170 * end result is that we need another try...catch statement just to
171 * deal with this mess.
175 //try to create generic event - will fail in Safari 2.x
176 customEvent = doc.createEvent("Events");
178 } catch (uierror /*:Error*/){
180 //the above failed, so create a UIEvent for Safari 2.x
181 customEvent = doc.createEvent("UIEvents");
185 customEvent.initEvent(type, bubbles, cancelable);
188 customEvent.view = view;
189 customEvent.altKey = altKey;
190 customEvent.ctrlKey = ctrlKey;
191 customEvent.shiftKey = shiftKey;
192 customEvent.metaKey = metaKey;
193 customEvent.keyCode = keyCode;
194 customEvent.charCode = charCode;
201 target.dispatchEvent(customEvent);
203 } else if (isObject(doc.createEventObject)){ //IE
205 //create an IE event object
206 customEvent = doc.createEventObject();
208 //assign available properties
209 customEvent.bubbles = bubbles;
210 customEvent.cancelable = cancelable;
211 customEvent.view = view;
212 customEvent.ctrlKey = ctrlKey;
213 customEvent.altKey = altKey;
214 customEvent.shiftKey = shiftKey;
215 customEvent.metaKey = metaKey;
218 * IE doesn't support charCode explicitly. CharCode should
219 * take precedence over any keyCode value for accurate
222 customEvent.keyCode = (charCode > 0) ? charCode : keyCode;
225 target.fireEvent("on" + type, customEvent);
228 Y.error("simulateKeyEvent(): No event simulation framework present.");
233 * Note: Intentionally not for YUIDoc generation.
234 * Simulates a mouse event using the given event information to populate
235 * the generated event object. This method does browser-equalizing
236 * calculations to account for differences in the DOM and IE event models
237 * as well as different browser quirks.
238 * @method simulateMouseEvent
241 * @param {HTMLElement} target The target of the given event.
242 * @param {String} type The type of event to fire. This can be any one of
243 * the following: click, dblclick, mousedown, mouseup, mouseout,
244 * mouseover, and mousemove.
245 * @param {Boolean} bubbles (Optional) Indicates if the event can be
246 * bubbled up. DOM Level 2 specifies that all mouse events bubble by
247 * default. The default is true.
248 * @param {Boolean} cancelable (Optional) Indicates if the event can be
249 * canceled using preventDefault(). DOM Level 2 specifies that all
250 * mouse events except mousemove can be cancelled. The default
251 * is true for all events except mousemove, for which the default
253 * @param {Window} view (Optional) The view containing the target. This is
254 * typically the window object. The default is window.
255 * @param {int} detail (Optional) The number of times the mouse button has
256 * been used. The default value is 1.
257 * @param {int} screenX (Optional) The x-coordinate on the screen at which
258 * point the event occured. The default is 0.
259 * @param {int} screenY (Optional) The y-coordinate on the screen at which
260 * point the event occured. The default is 0.
261 * @param {int} clientX (Optional) The x-coordinate on the client at which
262 * point the event occured. The default is 0.
263 * @param {int} clientY (Optional) The y-coordinate on the client at which
264 * point the event occured. The default is 0.
265 * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys
266 * is pressed while the event is firing. The default is false.
267 * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys
268 * is pressed while the event is firing. The default is false.
269 * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys
270 * is pressed while the event is firing. The default is false.
271 * @param {Boolean} metaKey (Optional) Indicates if one of the META keys
272 * is pressed while the event is firing. The default is false.
273 * @param {int} button (Optional) The button being pressed while the event
274 * is executing. The value should be 0 for the primary mouse button
275 * (typically the left button), 1 for the terciary mouse button
276 * (typically the middle button), and 2 for the secondary mouse button
277 * (typically the right button). The default is 0.
278 * @param {HTMLElement} relatedTarget (Optional) For mouseout events,
279 * this is the element that the mouse has moved to. For mouseover
280 * events, this is the element that the mouse has moved from. This
281 * argument is ignored for all other events. The default is null.
283 function simulateMouseEvent(target /*:HTMLElement*/, type /*:String*/,
284 bubbles /*:Boolean*/, cancelable /*:Boolean*/,
285 view /*:Window*/, detail /*:int*/,
286 screenX /*:int*/, screenY /*:int*/,
287 clientX /*:int*/, clientY /*:int*/,
288 ctrlKey /*:Boolean*/, altKey /*:Boolean*/,
289 shiftKey /*:Boolean*/, metaKey /*:Boolean*/,
290 button /*:int*/, relatedTarget /*:HTMLElement*/) /*:Void*/
295 Y.error("simulateMouseEvent(): Invalid target.");
300 type = type.toLowerCase();
302 //make sure it's a supported mouse event
303 if (!mouseEvents[type]){
304 Y.error("simulateMouseEvent(): Event type '" + type + "' not supported.");
307 Y.error("simulateMouseEvent(): Event type must be a string.");
310 //setup default values
311 if (!isBoolean(bubbles)){
312 bubbles = true; //all mouse events bubble
314 if (!isBoolean(cancelable)){
315 cancelable = (type != "mousemove"); //mousemove is the only one that can't be cancelled
317 if (!isObject(view)){
318 view = window; //view is typically window
320 if (!isNumber(detail)){
321 detail = 1; //number of mouse clicks must be at least one
323 if (!isNumber(screenX)){
326 if (!isNumber(screenY)){
329 if (!isNumber(clientX)){
332 if (!isNumber(clientY)){
335 if (!isBoolean(ctrlKey)){
338 if (!isBoolean(altKey)){
341 if (!isBoolean(shiftKey)){
344 if (!isBoolean(metaKey)){
347 if (!isNumber(button)){
351 //try to create a mouse event
352 var customEvent /*:MouseEvent*/ = null;
354 //check for DOM-compliant browsers first
355 if (isFunction(doc.createEvent)){
357 customEvent = doc.createEvent("MouseEvents");
359 //Safari 2.x (WebKit 418) still doesn't implement initMouseEvent()
360 if (customEvent.initMouseEvent){
361 customEvent.initMouseEvent(type, bubbles, cancelable, view, detail,
362 screenX, screenY, clientX, clientY,
363 ctrlKey, altKey, shiftKey, metaKey,
364 button, relatedTarget);
367 //the closest thing available in Safari 2.x is UIEvents
368 customEvent = doc.createEvent("UIEvents");
369 customEvent.initEvent(type, bubbles, cancelable);
370 customEvent.view = view;
371 customEvent.detail = detail;
372 customEvent.screenX = screenX;
373 customEvent.screenY = screenY;
374 customEvent.clientX = clientX;
375 customEvent.clientY = clientY;
376 customEvent.ctrlKey = ctrlKey;
377 customEvent.altKey = altKey;
378 customEvent.metaKey = metaKey;
379 customEvent.shiftKey = shiftKey;
380 customEvent.button = button;
381 customEvent.relatedTarget = relatedTarget;
385 * Check to see if relatedTarget has been assigned. Firefox
386 * versions less than 2.0 don't allow it to be assigned via
387 * initMouseEvent() and the property is readonly after event
388 * creation, so in order to keep YAHOO.util.getRelatedTarget()
389 * working, assign to the IE proprietary toElement property
390 * for mouseout event and fromElement property for mouseover
393 if (relatedTarget && !customEvent.relatedTarget){
394 if (type == "mouseout"){
395 customEvent.toElement = relatedTarget;
396 } else if (type == "mouseover"){
397 customEvent.fromElement = relatedTarget;
402 target.dispatchEvent(customEvent);
404 } else if (isObject(doc.createEventObject)){ //IE
406 //create an IE event object
407 customEvent = doc.createEventObject();
409 //assign available properties
410 customEvent.bubbles = bubbles;
411 customEvent.cancelable = cancelable;
412 customEvent.view = view;
413 customEvent.detail = detail;
414 customEvent.screenX = screenX;
415 customEvent.screenY = screenY;
416 customEvent.clientX = clientX;
417 customEvent.clientY = clientY;
418 customEvent.ctrlKey = ctrlKey;
419 customEvent.altKey = altKey;
420 customEvent.metaKey = metaKey;
421 customEvent.shiftKey = shiftKey;
423 //fix button property for IE's wacky implementation
426 customEvent.button = 1;
429 customEvent.button = 4;
435 customEvent.button = 0;
439 * Have to use relatedTarget because IE won't allow assignment
440 * to toElement or fromElement on generic events. This keeps
441 * YAHOO.util.customEvent.getRelatedTarget() functional.
443 customEvent.relatedTarget = relatedTarget;
446 target.fireEvent("on" + type, customEvent);
449 Y.error("simulateMouseEvent(): No event simulation framework present.");
455 * Simulates the event with the given name on a target.
456 * @param {HTMLElement} target The DOM element that's the target of the event.
457 * @param {String} type The type of event to simulate (i.e., "click").
458 * @param {Object} options (Optional) Extra options to copy onto the event object.
463 Y.Event.simulate = function(target, type, options){
465 options = options || {};
467 if (mouseEvents[type]){
468 simulateMouseEvent(target, type, options.bubbles,
469 options.cancelable, options.view, options.detail, options.screenX,
470 options.screenY, options.clientX, options.clientY, options.ctrlKey,
471 options.altKey, options.shiftKey, options.metaKey, options.button,
472 options.relatedTarget);
473 } else if (keyEvents[type]){
474 simulateKeyEvent(target, type, options.bubbles,
475 options.cancelable, options.view, options.ctrlKey,
476 options.altKey, options.shiftKey, options.metaKey,
477 options.keyCode, options.charCode);
479 Y.error("simulate(): Event '" + type + "' can't be simulated.");
484 * @TODO: focus(), blur(), submit()
490 }, '3.0.0' ,{requires:['event']});