goog.provide('bot.Mouse');
goog.provide('bot.Mouse.Button');
goog.require('bot');
goog.require('bot.Device');
goog.require('bot.Error');
goog.require('bot.ErrorCode');
goog.require('bot.dom');
goog.require('bot.events');
goog.require('bot.userAgent');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.math.Coordinate');
goog.require('goog.userAgent');
goog.require('goog.utils');
bot.Mouse = function (opt_state, opt_modifiersState, opt_eventEmitter) {
bot.Device.call(this, opt_modifiersState, opt_eventEmitter);
this.buttonPressed_ = null;
this.elementPressed_ = null;
this.clientXY_ = new goog.math.Coordinate(0, 0);
this.nextClickIsDoubleClick_ = false;
this.hasEverInteracted_ = false;
if (opt_state) {
if (typeof opt_state['buttonPressed'] === 'number') {
this.buttonPressed_ = opt_state['buttonPressed'];
}
try {
if (bot.dom.isElement(opt_state['elementPressed'])) {
this.elementPressed_ = opt_state['elementPressed'];
}
} catch (ignored) {
this.buttonPressed_ = null;
}
this.clientXY_ = new goog.math.Coordinate(
opt_state['clientXY']['x'],
opt_state['clientXY']['y']);
this.nextClickIsDoubleClick_ = !!opt_state['nextClickIsDoubleClick'];
this.hasEverInteracted_ = !!opt_state['hasEverInteracted'];
try {
if (opt_state['element'] && bot.dom.isElement(opt_state['element'])) {
this.setElement((opt_state['element']));
}
} catch (ignored) {
this.buttonPressed_ = null;
}
}
};
goog.utils.inherits(bot.Mouse, bot.Device);
bot.Mouse.State;
bot.Mouse.Button = {
LEFT: 0,
MIDDLE: 1,
RIGHT: 2
};
bot.Mouse.NO_BUTTON_VALUE_INDEX_ = 3;
bot.Mouse.MOUSE_BUTTON_VALUE_MAP_ = (function () {
var buttonValueMap = {};
if (bot.userAgent.IE_DOC_PRE9) {
buttonValueMap[bot.events.EventType.CLICK] = [0, 0, 0, null];
buttonValueMap[bot.events.EventType.CONTEXTMENU] = [null, null, 0, null];
buttonValueMap[bot.events.EventType.MOUSEUP] = [1, 4, 2, null];
buttonValueMap[bot.events.EventType.MOUSEOUT] = [0, 0, 0, 0];
buttonValueMap[bot.events.EventType.MOUSEMOVE] = [1, 4, 2, 0];
} else if (goog.userAgent.WEBKIT || bot.userAgent.IE_DOC_9) {
buttonValueMap[bot.events.EventType.CLICK] = [0, 1, 2, null];
buttonValueMap[bot.events.EventType.CONTEXTMENU] = [null, null, 2, null];
buttonValueMap[bot.events.EventType.MOUSEUP] = [0, 1, 2, null];
buttonValueMap[bot.events.EventType.MOUSEOUT] = [0, 1, 2, 0];
buttonValueMap[bot.events.EventType.MOUSEMOVE] = [0, 1, 2, 0];
} else {
buttonValueMap[bot.events.EventType.CLICK] = [0, 1, 2, null];
buttonValueMap[bot.events.EventType.CONTEXTMENU] = [null, null, 2, null];
buttonValueMap[bot.events.EventType.MOUSEUP] = [0, 1, 2, null];
buttonValueMap[bot.events.EventType.MOUSEOUT] = [0, 0, 0, 0];
buttonValueMap[bot.events.EventType.MOUSEMOVE] = [0, 0, 0, 0];
}
if (bot.userAgent.IE_DOC_10) {
buttonValueMap[bot.events.EventType.MSPOINTERDOWN] =
buttonValueMap[bot.events.EventType.MOUSEUP];
buttonValueMap[bot.events.EventType.MSPOINTERUP] =
buttonValueMap[bot.events.EventType.MOUSEUP];
buttonValueMap[bot.events.EventType.MSPOINTERMOVE] = [-1, -1, -1, -1];
buttonValueMap[bot.events.EventType.MSPOINTEROUT] =
buttonValueMap[bot.events.EventType.MSPOINTERMOVE];
buttonValueMap[bot.events.EventType.MSPOINTEROVER] =
buttonValueMap[bot.events.EventType.MSPOINTERMOVE];
}
buttonValueMap[bot.events.EventType.DBLCLICK] =
buttonValueMap[bot.events.EventType.CLICK];
buttonValueMap[bot.events.EventType.MOUSEDOWN] =
buttonValueMap[bot.events.EventType.MOUSEUP];
buttonValueMap[bot.events.EventType.MOUSEOVER] =
buttonValueMap[bot.events.EventType.MOUSEOUT];
return buttonValueMap;
})();
bot.Mouse.MOUSE_EVENT_MAP_ = (function () {
var map = {};
map[bot.events.EventType.MOUSEDOWN] = bot.events.EventType.MSPOINTERDOWN;
map[bot.events.EventType.MOUSEMOVE] = bot.events.EventType.MSPOINTERMOVE;
map[bot.events.EventType.MOUSEOUT] = bot.events.EventType.MSPOINTEROUT;
map[bot.events.EventType.MOUSEOVER] = bot.events.EventType.MSPOINTEROVER;
map[bot.events.EventType.MOUSEUP] = bot.events.EventType.MSPOINTERUP;
return map;
})();
bot.Mouse.prototype.fireMousedown_ = function (opt_count) {
var isFirefox3 = goog.userAgent.GECKO && !bot.userAgent.isProductVersion(4);
var blocksOnMousedown = (goog.userAgent.WEBKIT || isFirefox3) &&
(bot.dom.isElement(this.getElement(), goog.dom.TagName.OPTION) ||
bot.dom.isElement(this.getElement(), goog.dom.TagName.SELECT));
if (blocksOnMousedown) {
return true;
}
var beforeActiveElement;
var mousedownCanPreemptFocus = goog.userAgent.GECKO || goog.userAgent.IE;
if (mousedownCanPreemptFocus) {
beforeActiveElement = bot.dom.getActiveElement(this.getElement());
}
var performFocus = this.fireMouseEvent_(bot.events.EventType.MOUSEDOWN, null, null, false, opt_count);
if (performFocus && mousedownCanPreemptFocus &&
beforeActiveElement != bot.dom.getActiveElement(this.getElement())) {
return false;
}
return performFocus;
};
bot.Mouse.prototype.pressButton = function (button, opt_count) {
if (this.buttonPressed_ !== null) {
throw new bot.Error(bot.ErrorCode.UNKNOWN_ERROR,
'Cannot press more than one button or an already pressed button.');
}
this.buttonPressed_ = button;
this.elementPressed_ = this.getElement();
var performFocus = this.fireMousedown_(opt_count);
if (performFocus) {
if (bot.userAgent.IE_DOC_10 &&
this.buttonPressed_ == bot.Mouse.Button.LEFT &&
bot.dom.isElement(this.elementPressed_, goog.dom.TagName.OPTION)) {
this.fireMSPointerEvent(bot.events.EventType.MSGOTPOINTERCAPTURE,
this.clientXY_, 0, bot.Device.MOUSE_MS_POINTER_ID,
MSPointerEvent.MSPOINTER_TYPE_MOUSE, true);
}
this.focusOnElement();
}
};
bot.Mouse.prototype.releaseButton = function (opt_force, opt_count) {
if (this.buttonPressed_ === null) {
throw new bot.Error(bot.ErrorCode.UNKNOWN_ERROR,
'Cannot release a button when no button is pressed.');
}
this.maybeToggleOption();
var elementInteractableBeforeMouseup =
bot.dom.isInteractable(this.getElement());
this.fireMouseEvent_(bot.events.EventType.MOUSEUP, null, null, opt_force, opt_count);
try {
if (this.buttonPressed_ == bot.Mouse.Button.LEFT &&
this.getElement() == this.elementPressed_) {
if (!(bot.userAgent.WINDOWS_PHONE &&
bot.dom.isElement(this.elementPressed_, goog.dom.TagName.OPTION))) {
this.clickElement(this.clientXY_,
this.getButtonValue_(bot.events.EventType.CLICK),
elementInteractableBeforeMouseup);
}
this.maybeDoubleClickElement_();
if (bot.userAgent.IE_DOC_10 &&
this.buttonPressed_ == bot.Mouse.Button.LEFT &&
bot.dom.isElement(this.elementPressed_, goog.dom.TagName.OPTION)) {
this.fireMSPointerEvent(bot.events.EventType.MSLOSTPOINTERCAPTURE,
new goog.math.Coordinate(0, 0), 0, bot.Device.MOUSE_MS_POINTER_ID,
MSPointerEvent.MSPOINTER_TYPE_MOUSE, false);
}
} else if (this.buttonPressed_ == bot.Mouse.Button.RIGHT) {
this.fireMouseEvent_(bot.events.EventType.CONTEXTMENU);
}
} catch (ignored) {
}
bot.Device.clearPointerMap();
this.buttonPressed_ = null;
this.elementPressed_ = null;
};
bot.Mouse.prototype.maybeDoubleClickElement_ = function () {
if (this.nextClickIsDoubleClick_) {
this.fireMouseEvent_(bot.events.EventType.DBLCLICK);
}
this.nextClickIsDoubleClick_ = !this.nextClickIsDoubleClick_;
};
bot.Mouse.prototype.move = function (element, coords) {
var toElemWasInteractable = bot.dom.isInteractable(element);
var rect = bot.dom.getClientRect(element);
this.clientXY_.x = coords.x + rect.left;
this.clientXY_.y = coords.y + rect.top;
var fromElement = this.getElement();
if (element != fromElement) {
try {
if (goog.dom.getWindow(goog.dom.getOwnerDocument(fromElement)).closed) {
fromElement = null;
}
} catch (ignore) {
fromElement = null;
}
if (fromElement) {
var isRoot = fromElement === bot.getDocument().documentElement ||
fromElement === bot.getDocument().body;
fromElement = (!this.hasEverInteracted_ && isRoot) ? null : fromElement;
this.fireMouseEvent_(bot.events.EventType.MOUSEOUT, element);
}
this.setElement(element);
if (!goog.userAgent.IE) {
this.fireMouseEvent_(bot.events.EventType.MOUSEOVER, fromElement, null,
toElemWasInteractable);
}
}
this.fireMouseEvent_(bot.events.EventType.MOUSEMOVE, null, null,
toElemWasInteractable);
if (goog.userAgent.IE && element != fromElement) {
this.fireMouseEvent_(bot.events.EventType.MOUSEOVER, fromElement, null,
toElemWasInteractable);
}
this.nextClickIsDoubleClick_ = false;
};
bot.Mouse.prototype.scroll = function (ticks) {
if (ticks == 0) {
throw new bot.Error(bot.ErrorCode.UNKNOWN_ERROR,
'Must scroll a non-zero number of ticks.');
}
var wheelDelta = ticks > 0 ? -120 : 120;
var pixelDelta = ticks > 0 ? 57 : -57;
for (var i = 0; i < Math.abs(ticks); i++) {
this.fireMouseEvent_(bot.events.EventType.MOUSEWHEEL, null, wheelDelta);
if (goog.userAgent.GECKO) {
this.fireMouseEvent_(bot.events.EventType.MOUSEPIXELSCROLL, null,
pixelDelta);
}
}
};
bot.Mouse.prototype.fireMouseEvent_ = function (type, opt_related,
opt_wheelDelta, opt_force, opt_count) {
this.hasEverInteracted_ = true;
if (bot.userAgent.IE_DOC_10) {
var msPointerEvent = bot.Mouse.MOUSE_EVENT_MAP_[type];
if (msPointerEvent) {
if (!this.fireMSPointerEvent(msPointerEvent, this.clientXY_,
this.getButtonValue_(msPointerEvent), bot.Device.MOUSE_MS_POINTER_ID,
MSPointerEvent.MSPOINTER_TYPE_MOUSE, true,
opt_related, opt_force)) {
return false;
}
}
}
return this.fireMouseEvent(type, this.clientXY_,
this.getButtonValue_(type), opt_related, opt_wheelDelta, opt_force, null, opt_count);
};
bot.Mouse.prototype.getButtonValue_ = function (eventType) {
if (!(eventType in bot.Mouse.MOUSE_BUTTON_VALUE_MAP_)) {
return 0;
}
var buttonIndex = this.buttonPressed_ === null ?
bot.Mouse.NO_BUTTON_VALUE_INDEX_ : this.buttonPressed_;
var buttonValue = bot.Mouse.MOUSE_BUTTON_VALUE_MAP_[eventType][buttonIndex];
if (buttonValue === null) {
throw new bot.Error(bot.ErrorCode.UNKNOWN_ERROR,
'Event does not permit the specified mouse button.');
}
return buttonValue;
};
bot.Mouse.prototype.getState = function () {
return {
'buttonPressed': this.buttonPressed_,
'elementPressed': this.elementPressed_,
'clientXY': { 'x': this.clientXY_.x, 'y': this.clientXY_.y },
'nextClickIsDoubleClick': this.nextClickIsDoubleClick_,
'hasEverInteracted': this.hasEverInteracted_,
'element': this.getElement()
};
};