// Copyright 2005 Google Inc.
// All Rights Reserved
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
/**
* @fileoverview A patched, standardized event object for browser events.
*
*
* The patched event object contains the following members:
* - type {String} Event type, e.g. 'click'
* - timestamp {Date} A date object for when the event was fired
* - target {Object} The element that actually triggered the event
* - currentTarget {Object} The element the listener is attached to
* - relatedTarget {Object} For mouseover and mouseout, the previous object
* - offsetX {Number} X-coordinate relative to target
* - offsetY {Number} Y-coordinate relative to target
* - clientX {Number} X-coordinate relative to viewport
* - clientY {Number} Y-coordinate relative to viewport
* - screenX {Number} X-coordinate relative to the edge of the screen
* - screenY {Number} Y-coordinate relative to the edge of the screen
* - button {Number} Mouse button. Use isButton() to test.
* - keyCode {Number} Key-code
* - ctrlKey {Boolean} Was ctrl key depressed
* - altKey {Boolean} Was alt key depressed
* - shiftKey {Boolean} Was shift key depressed
* - metaKey {Boolean} Was meta key depressed
*
* NOTE: The keyCode member contains the raw browser keyCode. For normalized
* key and character code use {@link goog.events.KeyHandler}.
*
*
*/
goog.provide('goog.events.BrowserEvent');
goog.provide('goog.events.BrowserEvent.MouseButton');
goog.require('goog.events.Event');
goog.require('goog.userAgent');
/**
* Accepts a browser event object and creates a patched, cross browser event
* object.
* The content of this object will not be initialized if no event object is
* provided. If this is the case, init() needs to be invoked separately.
* @param {Event} opt_e Browser event object.
* @param {Node} opt_currentTarget Current target for event.
* @constructor
* @extends {goog.events.Event}
*/
goog.events.BrowserEvent = function(opt_e, opt_currentTarget) {
if (opt_e) {
this.init(opt_e, opt_currentTarget);
}
};
goog.inherits(goog.events.BrowserEvent, goog.events.Event);
/**
* Normalized button constants for the mouse.
* @enum {number}
*/
goog.events.BrowserEvent.MouseButton = {
LEFT: 0,
MIDDLE: 1,
RIGHT: 2
};
/**
* Static data for mapping mouse buttons.
* @type {Array.}
* @private
*/
goog.events.BrowserEvent.IEButtonMap_ = [
1, // LEFT
4, // MIDDLE
2 // RIGHT
];
/**
* Event type
* @type {string?}
*/
goog.events.BrowserEvent.prototype.type = null;
/**
* Target that fired the event
* @type {Node?}
*/
goog.events.BrowserEvent.prototype.target = null;
/**
* Node that had the listener attached
* @type {Node|null|undefined}
*/
goog.events.BrowserEvent.prototype.currentTarget;
/**
* For mouseover and mouseout events, the related object for the event
* @type {Node?}
*/
goog.events.BrowserEvent.prototype.relatedTarget = null;
/**
* X-coordinate relative to target
* @type {number}
*/
goog.events.BrowserEvent.prototype.offsetX = 0;
/**
* Y-coordinate relative to target
* @type {number}
*/
goog.events.BrowserEvent.prototype.offsetY = 0;
/**
* X-coordinate relative to the window
* @type {number}
*/
goog.events.BrowserEvent.prototype.clientX = 0;
/**
* Y-coordinate relative to the window
* @type {number}
*/
goog.events.BrowserEvent.prototype.clientY = 0;
/**
* X-coordinate relative to the monitor
* @type {number}
*/
goog.events.BrowserEvent.prototype.screenX = 0;
/**
* Y-coordinate relative to the monitor
* @type {number}
*/
goog.events.BrowserEvent.prototype.screenY = 0;
/**
* Which mouse button was pressed
* @type {number}
*/
goog.events.BrowserEvent.prototype.button = 0;
/**
* Keycode of key press
* @type {number}
*/
goog.events.BrowserEvent.prototype.keyCode = 0;
/**
* Keycode of key press
* @type {number}
*/
goog.events.BrowserEvent.prototype.charCode = 0;
/**
* Whether control was pressed at time of event
* @type {boolean}
*/
goog.events.BrowserEvent.prototype.ctrlKey = false;
/**
* Whether alt was pressed at time of event
* @type {boolean}
*/
goog.events.BrowserEvent.prototype.altKey = false;
/**
* Whether shift was pressed at time of event
* @type {boolean}
*/
goog.events.BrowserEvent.prototype.shiftKey = false;
/**
* Whether the meta key was pressed at time of event
* @type {boolean}
*/
goog.events.BrowserEvent.prototype.metaKey = false;
/**
* The browser event object
* @type {Event}
* @private
*/
goog.events.BrowserEvent.prototype.event_ = null;
/**
* Accepts a browser event object and creates a patched, cross browser event
* object.
* @param {Event} e Browser event object.
* @param {Node} opt_currentTarget Current target for event.
*/
goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) {
this.type = e.type;
this.target = e.target || e.srcElement;
this.currentTarget = opt_currentTarget;
if (e.relatedTarget) {
this.relatedTarget = /** @type {Node} */ (e.relatedTarget);
} else if (this.type == goog.events.EventType.MOUSEOVER) {
this.relatedTarget = e.fromElement;
} else if (this.type == goog.events.EventType.MOUSEOUT) {
this.relatedTarget = e.toElement;
} else {
this.relatedTarget = null;
}
this.offsetX = typeof e.layerX == 'number' ? e.layerX : e.offsetX;
this.offsetY = typeof e.layerY == 'number' ? e.layerY : e.offsetY;
this.clientX = typeof e.clientX == 'number' ? e.clientX : e.pageX;
this.clientY = typeof e.clientY == 'number' ? e.clientY : e.pageY;
this.screenX = e.screenX || 0;
this.screenY = e.screenY || 0;
this.button = e.button;
this.keyCode = e.keyCode || 0;
this.charCode = e.charCode ||
(this.type == goog.events.EventType.KEYPRESS ? e.keyCode : 0);
this.ctrlKey = e.ctrlKey;
this.altKey = e.altKey;
this.shiftKey = e.shiftKey;
this.metaKey = e.metaKey;
this.event_ = e;
delete this.returnValue_;
delete this.propagationStopped_;
};
/**
* Tests to see which button was pressed during the event. This is really only
* useful in IE and Gecko browsers. And in IE, it's only useful for
* mousedown/mouseup events, because click only fires for the left mouse button.
*
* Safari 2 only reports the left button being clicked, and uses the value '1'
* instead of 0. Opera only reports a mousedown event for the middle button, and
* no mouse events for the right button. Opera has default behavior for left and
* middle click that can only be overridden via a configuration setting.
*
* There's a nice table of this mess at http://www.unixpapa.com/js/mouse.html.
*
* @param {goog.events.BrowserEvent.MouseButton} button The button
* to test for.
* @return {boolean} True if button was pressed.
*/
goog.events.BrowserEvent.prototype.isButton = function(button) {
if (goog.userAgent.IE) {
if (this.type == goog.events.EventType.CLICK) {
return button == goog.events.BrowserEvent.MouseButton.LEFT;
} else {
return !!(this.event_.button &
goog.events.BrowserEvent.IEButtonMap_[button]);
}
} else if (goog.userAgent.WEBKIT && !goog.userAgent.isVersion('420')) {
// Safari 2 only reports mouse events for the left button.
return this.event_.button == 1 &&
button == goog.events.BrowserEvent.MouseButton.LEFT;
} else {
return this.event_.button == button;
}
};
/**
* Override the stop propogation method and give it access to the original
* event
*/
goog.events.BrowserEvent.prototype.stopPropagation = function() {
this.propagationStopped_ = true;
if (this.event_.stopPropagation) {
this.event_.stopPropagation();
} else {
this.event_.cancelBubble = true;
}
};
/**
* Override preventDefault and allow access to the original event through a
* closure
*/
goog.events.BrowserEvent.prototype.preventDefault = function() {
this.returnValue_ = false;
if (!this.event_.preventDefault) {
this.event_.returnValue = false;
/** @preserveTry */
try {
this.event_.keyCode = -1;
} catch (ex) {
// IE 7 throws an 'access denied' exception when trying to change
// keyCode in some situations (e.g. srcElement is input[type=file],
// or srcElement is an anchor tag rewritten by parent's innerHTML).
// Do nothing in this case.
}
} else {
this.event_.preventDefault();
}
};
/**
* @return {Event} The underlying browser event object.
*/
goog.events.BrowserEvent.prototype.getBrowserEvent = function() {
return this.event_;
};
/**
* Disposes of the event.
*/
goog.events.BrowserEvent.prototype.disposeInternal = function() {
goog.events.BrowserEvent.superClass_.disposeInternal.call(this);
this.event_ = null;
};