# Yahoo! UI Library

### yuitest 2.5.0

Yahoo! UI Library > yuitest > UserAction.js (source view)

Show Private Show Protected

    YAHOO.namespace("util");

    /**
     * The UserAction object provides functions that simulate events occurring in
     * the browser. Since these are simulated events, they do not behave exactly
     * as regular, user-initiated events do, but can be used to test simple
     * user interactions safely.
     *
     * @namespace YAHOO.util
     * @class UserAction
     * @static
     */
    YAHOO.util.UserAction = {

        //--------------------------------------------------------------------------
        // Generic event methods
        //--------------------------------------------------------------------------

        /**
         * Simulates a key event using the given event information to populate
         * the generated event object. This method does browser-equalizing
         * calculations to account for differences in the DOM and IE event models
         * as well as different browser quirks. Note: keydown causes Safari 2.x to
         * crash.
         * @method simulateKeyEvent
         * @private
         * @static
         * @param {HTMLElement} target The target of the given event.
         * @param {String} type The type of event to fire. This can be any one of
         *      the following: keyup, keydown, and keypress.
         * @param {Boolean} bubbles (Optional) Indicates if the event can be
         *      bubbled up. DOM Level 3 specifies that all key events bubble by
         *      default. The default is true.
         * @param {Boolean} cancelable (Optional) Indicates if the event can be
         *      canceled using preventDefault(). DOM Level 3 specifies that all
         *      key events can be cancelled. The default
         *      is true.
         * @param {Window} view (Optional) The view containing the target. This is
         *      typically the window object. The default is window.
         * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys
         *      is pressed while the event is firing. The default is false.
         * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys
         *      is pressed while the event is firing. The default is false.
         * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys
         *      is pressed while the event is firing. The default is false.
         * @param {Boolean} metaKey (Optional) Indicates if one of the META keys
         *      is pressed while the event is firing. The default is false.
         * @param {int} keyCode (Optional) The code for the key that is in use.
         *      The default is 0.
         * @param {int} charCode (Optional) The Unicode code for the character
         *      associated with the key being used. The default is 0.
         */
        simulateKeyEvent : function (target /*:HTMLElement*/, type /*:String*/,
                                     bubbles /*:Boolean*/,  cancelable /*:Boolean*/,
                                     view /*:Window*/,
                                     ctrlKey /*:Boolean*/,    altKey /*:Boolean*/,
                                     shiftKey /*:Boolean*/,   metaKey /*:Boolean*/,
                                     keyCode /*:int*/,        charCode /*:int*/) /*:Void*/
        {
            //check target
            target = YAHOO.util.Dom.get(target);
            if (!target){
                throw new Error("simulateKeyEvent(): Invalid target.");
            }

            //check event type
            if (YAHOO.lang.isString(type)){
                type = type.toLowerCase();
                switch(type){
                    case "keyup":
                    case "keydown":
                    case "keypress":
                        break;
                    case "textevent": //DOM Level 3
                        type = "keypress";
                        break;
                        // @TODO was the fallthrough intentional, if so throw error
                    default:
                        throw new Error("simulateKeyEvent(): Event type '" + type + "' not supported.");
                }
            } else {
                throw new Error("simulateKeyEvent(): Event type must be a string.");
            }

            //setup default values
            if (!YAHOO.lang.isBoolean(bubbles)){
                bubbles = true; //all key events bubble
            }
            if (!YAHOO.lang.isBoolean(cancelable)){
                cancelable = true; //all key events can be cancelled
            }
            if (!YAHOO.lang.isObject(view)){
                view = window; //view is typically window
            }
            if (!YAHOO.lang.isBoolean(ctrlKey)){
                ctrlKey = false;
            }
            if (!YAHOO.lang.isBoolean(altKey)){
                altKey = false;
            }
            if (!YAHOO.lang.isBoolean(shiftKey)){
                shiftKey = false;
            }
            if (!YAHOO.lang.isBoolean(metaKey)){
                metaKey = false;
            }
            if (!YAHOO.lang.isNumber(keyCode)){
                keyCode = 0;
            }
            if (!YAHOO.lang.isNumber(charCode)){
                charCode = 0;
            }

            //try to create a mouse event
            var customEvent /*:MouseEvent*/ = null;

            //check for DOM-compliant browsers first
            if (YAHOO.lang.isFunction(document.createEvent)){

                try {

                    //try to create key event
                    customEvent = document.createEvent("KeyEvents");

                    /*
                     * Interesting problem: Firefox implemented a non-standard
                     * version of initKeyEvent() based on DOM Level 2 specs.
                     * Key event was removed from DOM Level 2 and re-introduced
                     * in DOM Level 3 with a different interface. Firefox is the
                     * only browser with any implementation of Key Events, so for
                     * now, assume it's Firefox if the above line doesn't error.
                     */
                    //TODO: Decipher between Firefox's implementation and a correct one.
                    customEvent.initKeyEvent(type, bubbles, cancelable, view, ctrlKey,
                        altKey, shiftKey, metaKey, keyCode, charCode);

                } catch (ex /*:Error*/){

                    /*
                     * If it got here, that means key events aren't officially supported.
                     * Safari/WebKit is a real problem now. WebKit 522 won't let you
                     * set keyCode, charCode, or other properties if you use a
                     * UIEvent, so we first must try to create a generic event. The
                     * fun part is that this will throw an error on Safari 2.x. The
                     * end result is that we need another try...catch statement just to
                     * deal with this mess.
                     */
                    try {

                        //try to create generic event - will fail in Safari 2.x
                        customEvent = document.createEvent("Events");

                    } catch (uierror /*:Error*/){

                        //the above failed, so create a UIEvent for Safari 2.x
                        customEvent = document.createEvent("UIEvents");

                    } finally {

                        customEvent.initEvent(type, bubbles, cancelable);

                        //initialize
                        customEvent.view = view;
                        customEvent.altKey = altKey;
                        customEvent.ctrlKey = ctrlKey;
                        customEvent.shiftKey = shiftKey;
                        customEvent.metaKey = metaKey;
                        customEvent.keyCode = keyCode;
                        customEvent.charCode = charCode;

                    }

                }

                //fire the event
                target.dispatchEvent(customEvent);

            } else if (YAHOO.lang.isObject(document.createEventObject)){ //IE

                //create an IE event object
                customEvent = document.createEventObject();

                //assign available properties
                customEvent.bubbles = bubbles;
                customEvent.cancelable = cancelable;
                customEvent.view = view;
                customEvent.ctrlKey = ctrlKey;
                customEvent.altKey = altKey;
                customEvent.shiftKey = shiftKey;
                customEvent.metaKey = metaKey;

                /*
                 * IE doesn't support charCode explicitly. CharCode should
                 * take precedence over any keyCode value for accurate
                 * representation.
                 */
                customEvent.keyCode = (charCode > 0) ? charCode : keyCode;

                //fire the event
                target.fireEvent("on" + type, customEvent);

            } else {
                throw new Error("simulateKeyEvent(): No event simulation framework present.");
            }
        },

        /**
         * Simulates a mouse event using the given event information to populate
         * the generated event object. This method does browser-equalizing
         * calculations to account for differences in the DOM and IE event models
         * as well as different browser quirks.
         * @method simulateMouseEvent
         * @private
         * @static
         * @param {HTMLElement} target The target of the given event.
         * @param {String} type The type of event to fire. This can be any one of
         *      the following: click, dblclick, mousedown, mouseup, mouseout,
         *      mouseover, and mousemove.
         * @param {Boolean} bubbles (Optional) Indicates if the event can be
         *      bubbled up. DOM Level 2 specifies that all mouse events bubble by
         *      default. The default is true.
         * @param {Boolean} cancelable (Optional) Indicates if the event can be
         *      canceled using preventDefault(). DOM Level 2 specifies that all
         *      mouse events except mousemove can be cancelled. The default
         *      is true for all events except mousemove, for which the default
         *      is false.
         * @param {Window} view (Optional) The view containing the target. This is
         *      typically the window object. The default is window.
         * @param {int} detail (Optional) The number of times the mouse button has
         *      been used. The default value is 1.
         * @param {int} screenX (Optional) The x-coordinate on the screen at which
         *      point the event occured. The default is 0.
         * @param {int} screenY (Optional) The y-coordinate on the screen at which
         *      point the event occured. The default is 0.
         * @param {int} clientX (Optional) The x-coordinate on the client at which
         *      point the event occured. The default is 0.
         * @param {int} clientY (Optional) The y-coordinate on the client at which
         *      point the event occured. The default is 0.
         * @param {Boolean} ctrlKey (Optional) Indicates if one of the CTRL keys
         *      is pressed while the event is firing. The default is false.
         * @param {Boolean} altKey (Optional) Indicates if one of the ALT keys
         *      is pressed while the event is firing. The default is false.
         * @param {Boolean} shiftKey (Optional) Indicates if one of the SHIFT keys
         *      is pressed while the event is firing. The default is false.
         * @param {Boolean} metaKey (Optional) Indicates if one of the META keys
         *      is pressed while the event is firing. The default is false.
         * @param {int} button (Optional) The button being pressed while the event
         *      is executing. The value should be 0 for the primary mouse button
         *      (typically the left button), 1 for the terciary mouse button
         *      (typically the middle button), and 2 for the secondary mouse button
         *      (typically the right button). The default is 0.
         * @param {HTMLElement} relatedTarget (Optional) For mouseout events,
         *      this is the element that the mouse has moved to. For mouseover
         *      events, this is the element that the mouse has moved from. This
         *      argument is ignored for all other events. The default is null.
         */
        simulateMouseEvent : function (target /*:HTMLElement*/, type /*:String*/,
                                       bubbles /*:Boolean*/,  cancelable /*:Boolean*/,
                                       view /*:Window*/,        detail /*:int*/,
                                       screenX /*:int*/,        screenY /*:int*/,
                                       clientX /*:int*/,        clientY /*:int*/,
                                       ctrlKey /*:Boolean*/,    altKey /*:Boolean*/,
                                       shiftKey /*:Boolean*/,   metaKey /*:Boolean*/,
                                       button /*:int*/,         relatedTarget /*:HTMLElement*/) /*:Void*/
        {

            //check target
            target = YAHOO.util.Dom.get(target);
            if (!target){
                throw new Error("simulateMouseEvent(): Invalid target.");
            }

            //check event type
            if (YAHOO.lang.isString(type)){
                type = type.toLowerCase();
                switch(type){
                    case "mouseover":
                    case "mouseout":
                    case "mousedown":
                    case "mouseup":
                    case "click":
                    case "dblclick":
                    case "mousemove":
                        break;
                    default:
                        throw new Error("simulateMouseEvent(): Event type '" + type + "' not supported.");
                }
            } else {
                throw new Error("simulateMouseEvent(): Event type must be a string.");
            }

            //setup default values
            if (!YAHOO.lang.isBoolean(bubbles)){
                bubbles = true; //all mouse events bubble
            }
            if (!YAHOO.lang.isBoolean(cancelable)){
                cancelable = (type != "mousemove"); //mousemove is the only one that can't be cancelled
            }
            if (!YAHOO.lang.isObject(view)){
                view = window; //view is typically window
            }
            if (!YAHOO.lang.isNumber(detail)){
                detail = 1;  //number of mouse clicks must be at least one
            }
            if (!YAHOO.lang.isNumber(screenX)){
                screenX = 0;
            }
            if (!YAHOO.lang.isNumber(screenY)){
                screenY = 0;
            }
            if (!YAHOO.lang.isNumber(clientX)){
                clientX = 0;
            }
            if (!YAHOO.lang.isNumber(clientY)){
                clientY = 0;
            }
            if (!YAHOO.lang.isBoolean(ctrlKey)){
                ctrlKey = false;
            }
            if (!YAHOO.lang.isBoolean(altKey)){
                altKey = false;
            }
            if (!YAHOO.lang.isBoolean(shiftKey)){
                shiftKey = false;
            }
            if (!YAHOO.lang.isBoolean(metaKey)){
                metaKey = false;
            }
            if (!YAHOO.lang.isNumber(button)){
                button = 0;
            }

            //try to create a mouse event
            var customEvent /*:MouseEvent*/ = null;

            //check for DOM-compliant browsers first
            if (YAHOO.lang.isFunction(document.createEvent)){

                customEvent = document.createEvent("MouseEvents");

                //Safari 2.x (WebKit 418) still doesn't implement initMouseEvent()
                if (customEvent.initMouseEvent){
                    customEvent.initMouseEvent(type, bubbles, cancelable, view, detail,
                                         screenX, screenY, clientX, clientY,
                                         ctrlKey, altKey, shiftKey, metaKey,
                                         button, relatedTarget);
                } else { //Safari

                    //the closest thing available in Safari 2.x is UIEvents
                    customEvent = document.createEvent("UIEvents");
                    customEvent.initEvent(type, bubbles, cancelable);
                    customEvent.view = view;
                    customEvent.detail = detail;
                    customEvent.screenX = screenX;
                    customEvent.screenY = screenY;
                    customEvent.clientX = clientX;
                    customEvent.clientY = clientY;
                    customEvent.ctrlKey = ctrlKey;
                    customEvent.altKey = altKey;
                    customEvent.metaKey = metaKey;
                    customEvent.shiftKey = shiftKey;
                    customEvent.button = button;
                    customEvent.relatedTarget = relatedTarget;
                }

                /*
                 * Check to see if relatedTarget has been assigned. Firefox
                 * versions less than 2.0 don't allow it to be assigned via
                 * initMouseEvent() and the property is readonly after event
                 * creation, so in order to keep YAHOO.util.getRelatedTarget()
                 * working, assign to the IE proprietary toElement property
                 * for mouseout event and fromElement property for mouseover
                 * event.
                 */
                if (relatedTarget && !customEvent.relatedTarget){
                    if (type == "mouseout"){
                        customEvent.toElement = relatedTarget;
                    } else if (type == "mouseover"){
                        customEvent.fromElement = relatedTarget;
                    }
                }

                //fire the event
                target.dispatchEvent(customEvent);

            } else if (YAHOO.lang.isObject(document.createEventObject)){ //IE

                //create an IE event object
                customEvent = document.createEventObject();

                //assign available properties
                customEvent.bubbles = bubbles;
                customEvent.cancelable = cancelable;
                customEvent.view = view;
                customEvent.detail = detail;
                customEvent.screenX = screenX;
                customEvent.screenY = screenY;
                customEvent.clientX = clientX;
                customEvent.clientY = clientY;
                customEvent.ctrlKey = ctrlKey;
                customEvent.altKey = altKey;
                customEvent.metaKey = metaKey;
                customEvent.shiftKey = shiftKey;

                //fix button property for IE's wacky implementation
                switch(button){
                    case 0:
                        customEvent.button = 1;
                        break;
                    case 1:
                        customEvent.button = 4;
                        break;
                    case 2:
                        //leave as is
                        break;
                    default:
                        customEvent.button = 0;
                }

                /*
                 * Have to use relatedTarget because IE won't allow assignment
                 * to toElement or fromElement on generic events. This keeps
                 * YAHOO.util.customEvent.getRelatedTarget() functional.
                 */
                customEvent.relatedTarget = relatedTarget;

                //fire the event
                target.fireEvent("on" + type, customEvent);

            } else {
                throw new Error("simulateMouseEvent(): No event simulation framework present.");
            }
        },

        //--------------------------------------------------------------------------
        // Mouse events
        //--------------------------------------------------------------------------

        /**
         * Simulates a mouse event on a particular element.
         * @param {HTMLElement} target The element to click on.
         * @param {String} type The type of event to fire. This can be any one of
         *      the following: click, dblclick, mousedown, mouseup, mouseout,
         *      mouseover, and mousemove.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method mouseEvent
         * @static
         */
        fireMouseEvent : function (target /*:HTMLElement*/, type /*:String*/,
                               options /*:Object*/) /*:Void*/
        {
            options = options || {};
            this.simulateMouseEvent(target, 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);
        },

        /**
         * Simulates a click on a particular element.
         * @param {HTMLElement} target The element to click on.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method click
         * @static
         */
        click : function (target /*:HTMLElement*/, options /*:Object*/) /*:Void*/ {
            this.fireMouseEvent(target, "click", options);
        },

        /**
         * Simulates a double click on a particular element.
         * @param {HTMLElement} target The element to double click on.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method dblclick
         * @static
         */
        dblclick : function (target /*:HTMLElement*/, options /*:Object*/) /*:Void*/ {
            this.fireMouseEvent( target, "dblclick", options);
        },

        /**
         * Simulates a mousedown on a particular element.
         * @param {HTMLElement} target The element to act on.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method mousedown
         * @static
         */
        mousedown : function (target /*:HTMLElement*/, options /*Object*/) /*:Void*/ {
            this.fireMouseEvent(target, "mousedown", options);
        },

        /**
         * Simulates a mousemove on a particular element.
         * @param {HTMLElement} target The element to act on.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method mousemove
         * @static
         */
        mousemove : function (target /*:HTMLElement*/, options /*Object*/) /*:Void*/ {
            this.fireMouseEvent(target, "mousemove", options);
        },

        /**
         * Simulates a mouseout event on a particular element. Use "relatedTarget"
         * on the options object to specify where the mouse moved to.
         * Quirks: Firefox less than 2.0 doesn't set relatedTarget properly, so
         * toElement is assigned in its place. IE doesn't allow toElement to be
         * be assigned, so relatedTarget is assigned in its place. Both of these
         * concessions allow YAHOO.util.Event.getRelatedTarget() to work correctly
         * in both browsers.
         * @param {HTMLElement} target The element to act on.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method mouseout
         * @static
         */
        mouseout : function (target /*:HTMLElement*/, options /*Object*/) /*:Void*/ {
            this.fireMouseEvent(target, "mouseout", options);
        },

        /**
         * Simulates a mouseover event on a particular element. Use "relatedTarget"
         * on the options object to specify where the mouse moved from.
         * Quirks: Firefox less than 2.0 doesn't set relatedTarget properly, so
         * fromElement is assigned in its place. IE doesn't allow fromElement to be
         * be assigned, so relatedTarget is assigned in its place. Both of these
         * concessions allow YAHOO.util.Event.getRelatedTarget() to work correctly
         * in both browsers.
         * @param {HTMLElement} target The element to act on.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method mouseover
         * @static
         */
        mouseover : function (target /*:HTMLElement*/, options /*Object*/) /*:Void*/ {
            this.fireMouseEvent(target, "mouseover", options);
        },

        /**
         * Simulates a mouseup on a particular element.
         * @param {HTMLElement} target The element to act on.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method mouseup
         * @static
         */
        mouseup : function (target /*:HTMLElement*/, options /*Object*/) /*:Void*/ {
            this.fireMouseEvent(target, "mouseup", options);
        },

        //--------------------------------------------------------------------------
        // Key events
        //--------------------------------------------------------------------------

        /**
         * Fires an event that normally would be fired by the keyboard (keyup,
         * keydown, keypress). Make sure to specify either keyCode or charCode as
         * an option.
         * @private
         * @param {String} type The type of event ("keyup", "keydown" or "keypress").
         * @param {HTMLElement} target The target of the event.
         * @param {Object} options Options for the event. Either keyCode or charCode
         *                         are required.
         * @method fireKeyEvent
         * @static
         */
        fireKeyEvent : function (type /*:String*/, target /*:HTMLElement*/,
                                 options /*:Object*/) /*:Void*/
        {
            options = options || {};
            this.simulateKeyEvent(target, type, options.bubbles,
                options.cancelable, options.view, options.ctrlKey,
                options.altKey, options.shiftKey, options.metaKey,
                options.keyCode, options.charCode);
        },

        /**
         * Simulates a keydown event on a particular element.
         * @param {HTMLElement} target The element to act on.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method keydown
         * @static
         */
        keydown : function (target /*:HTMLElement*/, options /*:Object*/) /*:Void*/ {
            this.fireKeyEvent("keydown", target, options);
        },

        /**
         * Simulates a keypress on a particular element.
         * @param {HTMLElement} target The element to act on.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method keypress
         * @static
         */
        keypress : function (target /*:HTMLElement*/, options /*:Object*/) /*:Void*/ {
            this.fireKeyEvent("keypress", target, options);
        },

        /**
         * Simulates a keyup event on a particular element.
         * @param {HTMLElement} target The element to act on.
         * @param {Object} options Additional event options (use DOM standard names).
         * @method keyup
         * @static
         */
        keyup : function (target /*:HTMLElement*/, options /*Object*/) /*:Void*/ {
            this.fireKeyEvent("keyup", target, options);
        }

    };

Copyright © 2007 Yahoo! Inc. All rights reserved.