blob: 251e34d53259cf3942865606ea1c1e751c33f6b3 [file] [log] [blame] [edit]
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
/**
* @fileoverview Functions to do with firing and simulating events.
*/
goog.provide('bot.events');
goog.provide('bot.events.EventArgs');
goog.provide('bot.events.EventType');
goog.provide('bot.events.KeyboardArgs');
goog.provide('bot.events.MSGestureArgs');
goog.provide('bot.events.MSPointerArgs');
goog.provide('bot.events.MouseArgs');
goog.provide('bot.events.Touch');
goog.provide('bot.events.TouchArgs');
goog.require('bot');
goog.require('bot.Error');
goog.require('bot.ErrorCode');
goog.require('bot.userAgent');
goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.events.BrowserEvent');
goog.require('goog.style');
goog.require('goog.userAgent');
goog.require('goog.userAgent.product');
/**
* Whether the browser supports the construction of touch events.
*
* @const
* @type {boolean}
*/
bot.events.SUPPORTS_TOUCH_EVENTS = !(goog.userAgent.IE &&
!bot.userAgent.isEngineVersion(10));
/**
* Whether the browser supports a native touch api.
* @private {boolean}
* @const
*/
bot.events.BROKEN_TOUCH_API_ = (function () {
if (goog.userAgent.product.ANDROID) {
// Native touch api supported starting in version 4.0 (Ice Cream Sandwich).
return !bot.userAgent.isProductVersion(4);
}
return !bot.userAgent.IOS;
})();
/**
* Whether the browser supports the construction of MSPointer events.
*
* @const
* @type {boolean}
*/
bot.events.SUPPORTS_MSPOINTER_EVENTS =
goog.userAgent.IE && bot.getWindow().navigator.msPointerEnabled;
/**
* Arguments to initialize an event.
*
* @typedef {bot.events.MouseArgs|bot.events.KeyboardArgs|bot.events.TouchArgs|
bot.events.MSGestureArgs|bot.events.MSPointerArgs}
*/
bot.events.EventArgs;
/**
* Arguments to initialize a mouse event.
*
* @typedef {{clientX: number,
* clientY: number,
* button: number,
* altKey: boolean,
* ctrlKey: boolean,
* shiftKey: boolean,
* metaKey: boolean,
* relatedTarget: Element,
* wheelDelta: number}}
*/
bot.events.MouseArgs;
/**
* Arguments to initialize a keyboard event.
*
* @typedef {{keyCode: number,
* charCode: number,
* altKey: boolean,
* ctrlKey: boolean,
* shiftKey: boolean,
* metaKey: boolean,
* preventDefault: boolean}}
*/
bot.events.KeyboardArgs;
/**
* Argument to initialize a touch event.
*
* @typedef {{touches: !Array.<bot.events.Touch>,
* targetTouches: !Array.<bot.events.Touch>,
* changedTouches: !Array.<bot.events.Touch>,
* altKey: boolean,
* ctrlKey: boolean,
* shiftKey: boolean,
* metaKey: boolean,
* relatedTarget: Element,
* scale: number,
* rotation: number}}
*/
bot.events.TouchArgs;
/**
* @typedef {{identifier: number,
* screenX: number,
* screenY: number,
* clientX: number,
* clientY: number,
* pageX: number,
* pageY: number}}
*/
bot.events.Touch;
/**
* Arguments to initialize an MSGesture event.
*
* @typedef {{clientX: number,
* clientY: number,
* translationX: number,
* translationY: number,
* scale: number,
* expansion: number,
* rotation: number,
* velocityX: number,
* velocityY: number,
* velocityExpansion: number,
* velocityAngular: number,
* relatedTarget: Element}}
*/
bot.events.MSGestureArgs;
/**
* Arguments to initialize an MSPointer event.
*
* @typedef {{clientX: number,
* clientY: number,
* button: number,
* altKey: boolean,
* ctrlKey: boolean,
* shiftKey: boolean,
* metaKey: boolean,
* relatedTarget: Element,
* width: number,
* height: number,
* pressure: number,
* rotation: number,
* pointerId: number,
* tiltX: number,
* tiltY: number,
* pointerType: number,
* isPrimary: boolean}}
*/
bot.events.MSPointerArgs;
/**
* Factory for event objects of a specific type.
*
* @constructor
* @param {string} type Type of the created events.
* @param {boolean} bubbles Whether the created events bubble.
* @param {boolean} cancelable Whether the created events are cancelable.
* @private
*/
bot.events.EventFactory_ = function (type, bubbles, cancelable) {
/** @private {string} */
this.type_ = type;
/** @private {boolean} */
this.bubbles_ = bubbles;
/** @private {boolean} */
this.cancelable_ = cancelable;
};
/**
* Creates an event.
*
* @param {!Element|!Window} target Target element of the event.
* @param {bot.events.EventArgs=} opt_args Event arguments.
* @return {!Event} Newly created event.
*/
bot.events.EventFactory_.prototype.create = function (target, opt_args) {
var doc = goog.dom.getOwnerDocument(target);
var event = doc.createEvent('HTMLEvents');
event.initEvent(this.type_, this.bubbles_, this.cancelable_);
return event;
};
/**
* Overriding toString to return the unique type string improves debugging,
* and it allows event types to be mapped in JS objects without collisions.
*
* @return {string} String representation of the event type.
* @override
*/
bot.events.EventFactory_.prototype.toString = function () {
return this.type_;
};
/**
* Factory for mouse event objects of a specific type.
*
* @constructor
* @param {string} type Type of the created events.
* @param {boolean} bubbles Whether the created events bubble.
* @param {boolean} cancelable Whether the created events are cancelable.
* @extends {bot.events.EventFactory_}
* @private
*/
bot.events.MouseEventFactory_ = function (type, bubbles, cancelable) {
goog.base(this, type, bubbles, cancelable);
};
goog.inherits(bot.events.MouseEventFactory_, bot.events.EventFactory_);
/**
* @override
*/
bot.events.MouseEventFactory_.prototype.create = function (target, opt_args) {
// Only Gecko supports the mouse pixel scroll event.
if (!goog.userAgent.GECKO && this == bot.events.EventType.MOUSEPIXELSCROLL) {
throw new bot.Error(bot.ErrorCode.UNSUPPORTED_OPERATION,
'Browser does not support a mouse pixel scroll event.');
}
var args = /** @type {!bot.events.MouseArgs} */ (opt_args);
var doc = goog.dom.getOwnerDocument(target);
var event;
var view = goog.dom.getWindow(doc);
event = doc.createEvent('MouseEvents');
var detail = 1;
// All browser but Firefox provide the wheelDelta value in the event.
// Firefox provides the scroll amount in the detail field, where it has the
// opposite polarity of the wheelDelta (upward scroll is negative) and is a
// factor of 40 less than the wheelDelta value.
// The wheelDelta value is normally some multiple of 40.
if (this == bot.events.EventType.MOUSEWHEEL) {
if (!goog.userAgent.GECKO) {
event.wheelDelta = args.wheelDelta;
}
if (goog.userAgent.GECKO) {
detail = args.wheelDelta / -40;
}
}
// Only Gecko supports a mouse pixel scroll event, so we use it as the
// "standard" and pass it along as is as the "detail" of the event.
if (goog.userAgent.GECKO && this == bot.events.EventType.MOUSEPIXELSCROLL) {
detail = args.wheelDelta;
}
// For screenX and screenY, we set those to clientX and clientY values.
// While not strictly correct, applications under test depend on
// accurate relative positioning which is satisfied.
event.initMouseEvent(this.type_, this.bubbles_, this.cancelable_, view,
detail, /*screenX*/ args.clientX, /*screenY*/ args.clientY,
args.clientX, args.clientY, args.ctrlKey, args.altKey,
args.shiftKey, args.metaKey, args.button, args.relatedTarget);
// Trying to modify the properties throws an error,
// so we define getters to return the correct values.
if (goog.userAgent.IE &&
event.pageX === 0 && event.pageY === 0 && Object.defineProperty) {
var scrollElem = goog.dom.getDomHelper(target).getDocumentScrollElement();
var clientElem = goog.style.getClientViewportElement(doc);
var pageX = args.clientX + scrollElem.scrollLeft - clientElem.clientLeft;
var pageY = args.clientY + scrollElem.scrollTop - clientElem.clientTop;
Object.defineProperty(event, 'pageX', {
get: function () {
return pageX;
}
});
Object.defineProperty(event, 'pageY', {
get: function () {
return pageY;
}
});
}
return event;
};
/**
* Factory for keyboard event objects of a specific type.
*
* @constructor
* @param {string} type Type of the created events.
* @param {boolean} bubbles Whether the created events bubble.
* @param {boolean} cancelable Whether the created events are cancelable.
* @extends {bot.events.EventFactory_}
* @private
*/
bot.events.KeyboardEventFactory_ = function (type, bubbles, cancelable) {
goog.base(this, type, bubbles, cancelable);
};
goog.inherits(bot.events.KeyboardEventFactory_, bot.events.EventFactory_);
/**
* @override
*/
bot.events.KeyboardEventFactory_.prototype.create = function (target, opt_args) {
var args = /** @type {!bot.events.KeyboardArgs} */ (opt_args);
var doc = goog.dom.getOwnerDocument(target);
var event;
if (goog.userAgent.GECKO && !bot.userAgent.isEngineVersion(93)) {
var view = goog.dom.getWindow(doc);
var keyCode = args.charCode ? 0 : args.keyCode;
event = doc.createEvent('KeyboardEvent');
event.initKeyEvent(this.type_, this.bubbles_, this.cancelable_, view,
args.ctrlKey, args.altKey, args.shiftKey, args.metaKey, keyCode,
args.charCode);
// https://bugzilla.mozilla.org/show_bug.cgi?id=501496
if (this.type_ == bot.events.EventType.KEYPRESS && args.preventDefault) {
event.preventDefault();
}
} else {
event = doc.createEvent('Events');
event.initEvent(this.type_, this.bubbles_, this.cancelable_);
event.altKey = args.altKey;
event.ctrlKey = args.ctrlKey;
event.metaKey = args.metaKey;
event.shiftKey = args.shiftKey;
event.keyCode = args.charCode || args.keyCode;
if (goog.userAgent.WEBKIT || goog.userAgent.EDGE) {
event.charCode = (this == bot.events.EventType.KEYPRESS) ?
event.keyCode : 0;
}
}
return event;
};
/**
* Enum representing which mechanism to use for creating touch events.
* @enum {number}
* @private
*/
bot.events.TouchEventStrategy_ = {
MOUSE_EVENTS: 1,
INIT_TOUCH_EVENT: 2,
TOUCH_EVENT_CTOR: 3
};
/**
* Factory for touch event objects of a specific type.
*
* @constructor
* @param {string} type Type of the created events.
* @param {boolean} bubbles Whether the created events bubble.
* @param {boolean} cancelable Whether the created events are cancelable.
* @extends {bot.events.EventFactory_}
* @private
*/
bot.events.TouchEventFactory_ = function (type, bubbles, cancelable) {
goog.base(this, type, bubbles, cancelable);
};
goog.inherits(bot.events.TouchEventFactory_, bot.events.EventFactory_);
/**
* @override
*/
bot.events.TouchEventFactory_.prototype.create = function (target, opt_args) {
if (!bot.events.SUPPORTS_TOUCH_EVENTS) {
throw new bot.Error(bot.ErrorCode.UNSUPPORTED_OPERATION,
'Browser does not support firing touch events.');
}
var args = /** @type {!bot.events.TouchArgs} */ (opt_args);
var doc = goog.dom.getOwnerDocument(target);
var view = goog.dom.getWindow(doc);
// Creates a TouchList, using native touch Api, for touch events.
function createNativeTouchList(touchListArgs) {
var touches = goog.array.map(touchListArgs, function (touchArg) {
return doc.createTouch(view, target, touchArg.identifier,
touchArg.pageX, touchArg.pageY, touchArg.screenX, touchArg.screenY);
});
return doc.createTouchList.apply(doc, touches);
}
// Creates a TouchList, using simulated touch Api, for touch events.
function createGenericTouchList(touchListArgs) {
var touches = goog.array.map(touchListArgs, function (touchArg) {
// The target field is not part of the W3C spec, but both android and iOS
// add the target field to each touch.
return {
identifier: touchArg.identifier,
screenX: touchArg.screenX,
screenY: touchArg.screenY,
clientX: touchArg.clientX,
clientY: touchArg.clientY,
pageX: touchArg.pageX,
pageY: touchArg.pageY,
target: target
};
});
touches.item = function (i) {
return touches[i];
};
return touches;
}
function createTouchEventTouchList(touchListArgs) {
/** @type {!Array<!Touch>} */
var touches = goog.array.map(touchListArgs, function (touchArg) {
return new Touch({
identifier: touchArg.identifier,
screenX: touchArg.screenX,
screenY: touchArg.screenY,
clientX: touchArg.clientX,
clientY: touchArg.clientY,
pageX: touchArg.pageX,
pageY: touchArg.pageY,
target: target
});
});
return touches;
}
function createTouchList(touchStrategy, touches) {
switch (touchStrategy) {
case bot.events.TouchEventStrategy_.MOUSE_EVENTS:
return createGenericTouchList(touches);
case bot.events.TouchEventStrategy_.INIT_TOUCH_EVENT:
return createNativeTouchList(touches);
case bot.events.TouchEventStrategy_.TOUCH_EVENT_CTOR:
return createTouchEventTouchList(touches);
}
return null;
}
// TODO(juangj): Always use the TouchEvent constructor, if available.
var strategy;
if (bot.events.BROKEN_TOUCH_API_) {
strategy = bot.events.TouchEventStrategy_.MOUSE_EVENTS;
} else {
if (TouchEvent.prototype.initTouchEvent) {
strategy = bot.events.TouchEventStrategy_.INIT_TOUCH_EVENT;
} else if (TouchEvent && TouchEvent.length > 0) {
strategy = bot.events.TouchEventStrategy_.TOUCH_EVENT_CTOR;
} else {
throw new bot.Error(
bot.ErrorCode.UNSUPPORTED_OPERATION,
'Not able to create touch events in this browser');
}
}
// As a performance optimization, reuse the created touchlist when the lists
// are the same, which is often the case in practice.
var changedTouches = createTouchList(strategy, args.changedTouches);
var touches = (args.touches == args.changedTouches) ?
changedTouches : createTouchList(strategy, args.touches);
var targetTouches = (args.targetTouches == args.changedTouches) ?
changedTouches : createTouchList(strategy, args.targetTouches);
var event;
if (strategy == bot.events.TouchEventStrategy_.MOUSE_EVENTS) {
event = doc.createEvent('MouseEvents');
event.initMouseEvent(this.type_, this.bubbles_, this.cancelable_, view,
/*detail*/ 1, /*screenX*/ 0, /*screenY*/ 0, args.clientX, args.clientY,
args.ctrlKey, args.altKey, args.shiftKey, args.metaKey, /*button*/ 0,
args.relatedTarget);
event.touches = touches;
event.targetTouches = targetTouches;
event.changedTouches = changedTouches;
event.scale = args.scale;
event.rotation = args.rotation;
} else if (strategy == bot.events.TouchEventStrategy_.INIT_TOUCH_EVENT) {
event = doc.createEvent('TouchEvent');
// Different browsers have different implementations of initTouchEvent.
if (event.initTouchEvent.length == 0) {
// Chrome/Android.
event.initTouchEvent(touches, targetTouches, changedTouches,
this.type_, view, /*screenX*/ 0, /*screenY*/ 0, args.clientX,
args.clientY, args.ctrlKey, args.altKey, args.shiftKey, args.metaKey);
} else {
// iOS.
event.initTouchEvent(this.type_, this.bubbles_, this.cancelable_, view,
/*detail*/ 1, /*screenX*/ 0, /*screenY*/ 0, args.clientX,
args.clientY, args.ctrlKey, args.altKey, args.shiftKey, args.metaKey,
touches, targetTouches, changedTouches, args.scale, args.rotation);
}
event.relatedTarget = args.relatedTarget;
} else if (strategy == bot.events.TouchEventStrategy_.TOUCH_EVENT_CTOR) {
var touchProperties = /** @type {!TouchEventInit} */ ({
touches: touches,
targetTouches: targetTouches,
changedTouches: changedTouches,
bubbles: this.bubbles_,
cancelable: this.cancelable_,
ctrlKey: args.ctrlKey,
shiftKey: args.shiftKey,
altKey: args.altKey,
metaKey: args.metaKey
});
event = new TouchEvent(this.type_, touchProperties);
} else {
throw new bot.Error(
bot.ErrorCode.UNSUPPORTED_OPERATION,
'Illegal TouchEventStrategy_ value (this is a bug)');
}
return event;
};
/**
* Factory for MSGesture event objects of a specific type.
*
* @constructor
* @param {string} type Type of the created events.
* @param {boolean} bubbles Whether the created events bubble.
* @param {boolean} cancelable Whether the created events are cancelable.
* @extends {bot.events.EventFactory_}
* @private
*/
bot.events.MSGestureEventFactory_ = function (type, bubbles, cancelable) {
goog.base(this, type, bubbles, cancelable);
};
goog.inherits(bot.events.MSGestureEventFactory_, bot.events.EventFactory_);
/**
* @override
*/
bot.events.MSGestureEventFactory_.prototype.create = function (target,
opt_args) {
if (!bot.events.SUPPORTS_MSPOINTER_EVENTS) {
throw new bot.Error(bot.ErrorCode.UNSUPPORTED_OPERATION,
'Browser does not support MSGesture events.');
}
var args = /** @type {!bot.events.MSGestureArgs} */ (opt_args);
var doc = goog.dom.getOwnerDocument(target);
var view = goog.dom.getWindow(doc);
var event = doc.createEvent('MSGestureEvent');
var timestamp = (new Date).getTime();
// See http://msdn.microsoft.com/en-us/library/windows/apps/hh441187.aspx
event.initGestureEvent(this.type_, this.bubbles_, this.cancelable_, view,
/*detail*/ 1, /*screenX*/ 0, /*screenY*/ 0,
args.clientX, args.clientY, /*offsetX*/ 0,
/*offsetY*/ 0, args.translationX, args.translationY,
args.scale, args.expansion, args.rotation,
args.velocityX, args.velocityY, args.velocityExpansion,
args.velocityAngular, timestamp, args.relatedTarget);
return event;
};
/**
* Factory for MSPointer event objects of a specific type.
*
* @constructor
* @param {string} type Type of the created events.
* @param {boolean} bubbles Whether the created events bubble.
* @param {boolean} cancelable Whether the created events are cancelable.
* @extends {bot.events.EventFactory_}
* @private
*/
bot.events.MSPointerEventFactory_ = function (type, bubbles, cancelable) {
goog.base(this, type, bubbles, cancelable);
};
goog.inherits(bot.events.MSPointerEventFactory_, bot.events.EventFactory_);
/**
* @override
* @suppress {checkTypes} Closure compiler externs don't know about pointer
* events
*/
bot.events.MSPointerEventFactory_.prototype.create = function (target,
opt_args) {
if (!bot.events.SUPPORTS_MSPOINTER_EVENTS) {
throw new bot.Error(bot.ErrorCode.UNSUPPORTED_OPERATION,
'Browser does not support MSPointer events.');
}
var args = /** @type {!bot.events.MSPointerArgs} */ (opt_args);
var doc = goog.dom.getOwnerDocument(target);
var view = goog.dom.getWindow(doc);
var event = doc.createEvent('MSPointerEvent');
// See http://msdn.microsoft.com/en-us/library/ie/hh772109(v=vs.85).aspx
event.initPointerEvent(this.type_, this.bubbles_, this.cancelable_, view,
/*detail*/ 0, /*screenX*/ 0, /*screenY*/ 0,
args.clientX, args.clientY, args.ctrlKey, args.altKey,
args.shiftKey, args.metaKey, args.button,
args.relatedTarget, /*offsetX*/ 0, /*offsetY*/ 0,
args.width, args.height, args.pressure, args.rotation,
args.tiltX, args.tiltY, args.pointerId,
args.pointerType, /*hwTimeStamp*/ 0, args.isPrimary);
return event;
};
/**
* The types of events this modules supports firing.
*
* <p>To see which events bubble and are cancelable, see:
* http://en.wikipedia.org/wiki/DOM_events and
* http://www.w3.org/Submission/pointer-events/#pointer-event-types
*
* @enum {!bot.events.EventFactory_}
*/
bot.events.EventType = {
BLUR: new bot.events.EventFactory_('blur', false, false),
CHANGE: new bot.events.EventFactory_('change', true, false),
FOCUS: new bot.events.EventFactory_('focus', false, false),
FOCUSIN: new bot.events.EventFactory_('focusin', true, false),
FOCUSOUT: new bot.events.EventFactory_('focusout', true, false),
INPUT: new bot.events.EventFactory_('input', true, false),
ORIENTATIONCHANGE: new bot.events.EventFactory_(
'orientationchange', false, false),
PROPERTYCHANGE: new bot.events.EventFactory_('propertychange', false, false),
SELECT: new bot.events.EventFactory_('select', true, false),
SUBMIT: new bot.events.EventFactory_('submit', true, true),
TEXTINPUT: new bot.events.EventFactory_('textInput', true, true),
// Mouse events.
CLICK: new bot.events.MouseEventFactory_('click', true, true),
CONTEXTMENU: new bot.events.MouseEventFactory_('contextmenu', true, true),
DBLCLICK: new bot.events.MouseEventFactory_('dblclick', true, true),
MOUSEDOWN: new bot.events.MouseEventFactory_('mousedown', true, true),
MOUSEMOVE: new bot.events.MouseEventFactory_('mousemove', true, false),
MOUSEOUT: new bot.events.MouseEventFactory_('mouseout', true, true),
MOUSEOVER: new bot.events.MouseEventFactory_('mouseover', true, true),
MOUSEUP: new bot.events.MouseEventFactory_('mouseup', true, true),
MOUSEWHEEL: new bot.events.MouseEventFactory_(
goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel', true, true),
MOUSEPIXELSCROLL: new bot.events.MouseEventFactory_(
'MozMousePixelScroll', true, true),
// Keyboard events.
KEYDOWN: new bot.events.KeyboardEventFactory_('keydown', true, true),
KEYPRESS: new bot.events.KeyboardEventFactory_('keypress', true, true),
KEYUP: new bot.events.KeyboardEventFactory_('keyup', true, true),
// Touch events.
TOUCHEND: new bot.events.TouchEventFactory_('touchend', true, true),
TOUCHMOVE: new bot.events.TouchEventFactory_('touchmove', true, true),
TOUCHSTART: new bot.events.TouchEventFactory_('touchstart', true, true),
// MSGesture events
MSGESTURECHANGE: new bot.events.MSGestureEventFactory_(
'MSGestureChange', true, true),
MSGESTUREEND: new bot.events.MSGestureEventFactory_(
'MSGestureEnd', true, true),
MSGESTUREHOLD: new bot.events.MSGestureEventFactory_(
'MSGestureHold', true, true),
MSGESTURESTART: new bot.events.MSGestureEventFactory_(
'MSGestureStart', true, true),
MSGESTURETAP: new bot.events.MSGestureEventFactory_(
'MSGestureTap', true, true),
MSINERTIASTART: new bot.events.MSGestureEventFactory_(
'MSInertiaStart', true, true),
// MSPointer events
MSGOTPOINTERCAPTURE: new bot.events.MSPointerEventFactory_(
'MSGotPointerCapture', true, false),
MSLOSTPOINTERCAPTURE: new bot.events.MSPointerEventFactory_(
'MSLostPointerCapture', true, false),
MSPOINTERCANCEL: new bot.events.MSPointerEventFactory_(
'MSPointerCancel', true, true),
MSPOINTERDOWN: new bot.events.MSPointerEventFactory_(
'MSPointerDown', true, true),
MSPOINTERMOVE: new bot.events.MSPointerEventFactory_(
'MSPointerMove', true, true),
MSPOINTEROVER: new bot.events.MSPointerEventFactory_(
'MSPointerOver', true, true),
MSPOINTEROUT: new bot.events.MSPointerEventFactory_(
'MSPointerOut', true, true),
MSPOINTERUP: new bot.events.MSPointerEventFactory_(
'MSPointerUp', true, true)
};
/**
* Fire a named event on a particular element.
*
* @param {!Element|!Window} target The element on which to fire the event.
* @param {!bot.events.EventType} type Event type.
* @param {bot.events.EventArgs=} opt_args Arguments to initialize the event.
* @return {boolean} Whether the event fired successfully or was cancelled.
*/
bot.events.fire = function (target, type, opt_args) {
var factory = /** @type {!bot.events.EventFactory_} */ (type);
var event = factory.create(target, opt_args);
// Ensure the event's isTrusted property is set to false, so that
// bot.events.isSynthetic() can identify synthetic events from native ones.
if (!('isTrusted' in event)) {
event['isTrusted'] = false;
}
return target.dispatchEvent(event);
};
/**
* Returns whether the event was synthetically created by the atoms;
* if false, was created by the browser in response to a live user action.
*
* @param {!(Event|goog.events.BrowserEvent)} event An event.
* @return {boolean} Whether the event was synthetically created.
*/
bot.events.isSynthetic = function (event) {
var e = event.getBrowserEvent ? event.getBrowserEvent() : event;
return 'isTrusted' in e ? !e['isTrusted'] : false;
};