3
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
4
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
5
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
6
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
7
* Code distributed by Google as part of the polymer project is also
8
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
14
var HAS_NEW_MOUSE = (function() {
17
has = Boolean(new MouseEvent('x'));
23
* Returns the (x,y) coordinates representing the middle of a node.
25
* @param {!HTMLElement} node An element.
27
function middleOfNode(node) {
28
var bcr = node.getBoundingClientRect();
30
y: bcr.top + (bcr.height / 2),
31
x: bcr.left + (bcr.width / 2)
36
* Returns the (x,y) coordinates representing the top left corner of a node.
38
* @param {!HTMLElement} node An element.
40
function topLeftOfNode(node) {
41
var bcr = node.getBoundingClientRect();
49
* Returns a list of Touch objects that correspond to an array of positions
50
* and a target node. The Touch instances will each have a unique Touch
53
* @param {!Array<{ x: number, y: number }>} xyList A list of (x,y) coordinate objects.
54
* @param {!HTMLElement} node A target element node.
56
function makeTouches(xyList, node) {
59
return xyList.map(function(xy) {
67
return window.Touch ? new window.Touch(touchInit) : touchInit;
72
* Generates and dispatches a TouchEvent of a given type, at a specified
73
* position of a target node.
75
* @param {string} type The type of TouchEvent to generate.
76
* @param {{ x: number, y: number }} xy An (x,y) coordinate for the generated
78
* @param {!HTMLElement} node The target element node for the generated
79
* TouchEvent to be dispatched on.
81
function makeSoloTouchEvent(type, xy, node) {
82
xy = xy || middleOfNode(node);
83
var touches = makeTouches([xy], node);
84
var touchEventInit = {
86
targetTouches: touches,
87
changedTouches: touches
91
if (window.TouchEvent) {
92
event = new TouchEvent(type, touchEventInit);
94
event = new CustomEvent(type, { bubbles: true, cancelable: true });
95
for (var property in touchEventInit) {
96
event[property] = touchEventInit[property];
100
node.dispatchEvent(event);
104
* Fires a mouse event on a specific node, at a given set of coordinates.
105
* This event bubbles and is cancellable.
107
* @param {string} type The type of mouse event (such as 'tap' or 'down').
108
* @param {{ x: number, y: number }} xy The (x,y) coordinates the mouse event should be fired from.
109
* @param {!HTMLElement} node The node to fire the event on.
111
function makeMouseEvent(type, xy, node) {
117
// Make this a primary input.
118
buttons: 1 // http://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
122
e = new MouseEvent(type, props);
124
e = document.createEvent('MouseEvent');
126
type, props.bubbles, props.cancelable,
131
props.clientX, props.clientY,
137
null /*relatedTarget*/);
139
node.dispatchEvent(e);
143
* Simulates a mouse move action by firing a `move` mouse event on a
144
* specific node, between a set of coordinates.
146
* @param {!HTMLElement} node The node to fire the event on.
147
* @param {Object} fromXY The (x,y) coordinates the dragging should start from.
148
* @param {Object} toXY The (x,y) coordinates the dragging should end at.
149
* @param {?number} steps Optional. The numbers of steps in the move motion.
150
* If not specified, the default is 5.
152
function move(node, fromXY, toXY, steps) {
154
var dx = Math.round((fromXY.x - toXY.x) / steps);
155
var dy = Math.round((fromXY.y - toXY.y) / steps);
160
for (var i = steps; i > 0; i--) {
161
makeMouseEvent('mousemove', xy, node);
165
makeMouseEvent('mousemove', {
172
* Simulates a mouse dragging action originating in the middle of a specific node.
174
* @param {!HTMLElement} target The node to fire the event on.
175
* @param {?number} dx The horizontal displacement.
176
* @param {?number} dy The vertical displacement
177
* @param {?number} steps Optional. The numbers of steps in the dragging motion.
178
* If not specified, the default is 5.
180
function track(target, dx, dy, steps) {
185
var xy = middleOfNode(target);
190
move(target, xy, xy2, steps);
195
* Fires a `down` mouse event on a specific node, at a given set of coordinates.
196
* This event bubbles and is cancellable. If the (x,y) coordinates are
197
* not specified, the middle of the node will be used instead.
199
* @param {!HTMLElement} node The node to fire the event on.
200
* @param {{ x: number, y: number }=} xy Optional. The (x,y) coordinates the mouse event should be fired from.
202
function down(node, xy) {
203
xy = xy || middleOfNode(node);
204
makeMouseEvent('mousedown', xy, node);
208
* Fires an `up` mouse event on a specific node, at a given set of coordinates.
209
* This event bubbles and is cancellable. If the (x,y) coordinates are
210
* not specified, the middle of the node will be used instead.
212
* @param {!HTMLElement} node The node to fire the event on.
213
* @param {{ x: number, y: number }=} xy Optional. The (x,y) coordinates the mouse event should be fired from.
215
function up(node, xy) {
216
xy = xy || middleOfNode(node);
217
makeMouseEvent('mouseup', xy, node);
221
* Generate a click event on a given node, optionally at a given coordinate.
222
* @param {!HTMLElement} node The node to fire the click event on.
223
* @param {{ x: number, y: number }=} xy Optional. The (x,y) coordinates the mouse event should
226
function click(node, xy) {
227
xy = xy || middleOfNode(node);
228
makeMouseEvent('click', xy, node);
232
* Generate a touchstart event on a given node, optionally at a given coordinate.
233
* @param {!HTMLElement} node The node to fire the click event on.
234
* @param {{ x: number, y: number }=} xy Optional. The (x,y) coordinates the touch event should
237
function touchstart(node, xy) {
238
xy = xy || middleOfNode(node);
239
makeSoloTouchEvent('touchstart', xy, node);
244
* Generate a touchend event on a given node, optionally at a given coordinate.
245
* @param {!HTMLElement} node The node to fire the click event on.
246
* @param {{ x: number, y: number }=} xy Optional. The (x,y) coordinates the touch event should
249
function touchend(node, xy) {
250
xy = xy || middleOfNode(node);
251
makeSoloTouchEvent('touchend', xy, node);
255
* Simulates a complete mouse click by firing a `down` mouse event, followed
256
* by an asynchronous `up` and `tap` events on a specific node. Calls the
257
*`callback` after the `tap` event is fired.
259
* @param {!HTMLElement} target The node to fire the event on.
260
* @param {?Function} callback Optional. The function to be called after the action ends.
262
* emulateTouch: boolean
263
* }} options Optional. Configure the emulation fidelity of the mouse events.
265
function downAndUp(target, callback, options) {
266
if (options && options.emulateTouch) {
272
Polymer.Base.async(function() {
275
callback && callback();
280
* Fires a 'tap' mouse event on a specific node. This respects the pointer-events
281
* set on the node, and will not fire on disabled nodes.
283
* @param {!HTMLElement} node The node to fire the event on.
285
* emulateTouch: boolean
286
* }} options Optional. Configure the emulation fidelity of the mouse event.
288
function tap(node, options) {
289
// Respect nodes that are disabled in the UI.
290
if (window.getComputedStyle(node)['pointer-events'] === 'none')
293
var xy = middleOfNode(node);
295
if (options && options.emulateTouch) {
296
touchstart(node, xy);
306
* Focuses a node by firing a `focus` event. This event does not bubble.
308
* @param {!HTMLElement} target The node to fire the event on.
310
function focus(target) {
311
Polymer.Base.fire('focus', {}, {
318
* Blurs a node by firing a `blur` event. This event does not bubble.
320
* @param {!HTMLElement} target The node to fire the event on.
322
function blur(target) {
323
Polymer.Base.fire('blur', {}, {
330
* Returns a keyboard event. This event bubbles and is cancellable.
332
* @param {string} type The type of keyboard event (such as 'keyup' or 'keydown').
333
* @param {number} keyCode The keyCode for the event.
334
* @param {(string|Array<string>)=} modifiers The key modifiers for the event.
335
* Accepted values are shift, ctrl, alt, meta.
336
* @param {string=} key The KeyboardEvent.key value for the event.
338
function keyboardEventFor(type, keyCode, modifiers, key) {
339
var event = new CustomEvent(type, {
344
event.keyCode = keyCode;
345
event.code = keyCode;
347
modifiers = modifiers || [];
348
if (typeof modifiers === 'string') {
349
modifiers = [modifiers];
351
event.shiftKey = modifiers.indexOf('shift') !== -1;
352
event.altKey = modifiers.indexOf('alt') !== -1;
353
event.ctrlKey = modifiers.indexOf('ctrl') !== -1;
354
event.metaKey = modifiers.indexOf('meta') !== -1;
362
* Fires a keyboard event on a specific node. This event bubbles and is cancellable.
364
* @param {!HTMLElement} target The node to fire the event on.
365
* @param {string} type The type of keyboard event (such as 'keyup' or 'keydown').
366
* @param {number} keyCode The keyCode for the event.
367
* @param {(string|Array<string>)=} modifiers The key modifiers for the event.
368
* Accepted values are shift, ctrl, alt, meta.
369
* @param {string=} key The KeyboardEvent.key value for the event.
371
function keyEventOn(target, type, keyCode, modifiers, key) {
372
target.dispatchEvent(keyboardEventFor(type, keyCode, modifiers, key));
376
* Fires a 'keydown' event on a specific node. This event bubbles and is cancellable.
378
* @param {!HTMLElement} target The node to fire the event on.
379
* @param {number} keyCode The keyCode for the event.
380
* @param {(string|Array<string>)=} modifiers The key modifiers for the event.
381
* Accepted values are shift, ctrl, alt, meta.
382
* @param {string=} key The KeyboardEvent.key value for the event.
384
function keyDownOn(target, keyCode, modifiers, key) {
385
keyEventOn(target, 'keydown', keyCode, modifiers, key);
389
* Fires a 'keyup' event on a specific node. This event bubbles and is cancellable.
391
* @param {!HTMLElement} target The node to fire the event on.
392
* @param {number} keyCode The keyCode for the event.
393
* @param {(string|Array<string>)=} modifiers The key modifiers for the event.
394
* Accepted values are shift, ctrl, alt, meta.
395
* @param {string=} key The KeyboardEvent.key value for the event.
397
function keyUpOn(target, keyCode, modifiers, key) {
398
keyEventOn(target, 'keyup', keyCode, modifiers, key);
402
* Simulates a complete key press by firing a `keydown` keyboard event, followed
403
* by an asynchronous `keyup` event on a specific node.
405
* @param {!HTMLElement} target The node to fire the event on.
406
* @param {number} keyCode The keyCode for the event.
407
* @param {(string|Array<string>)=} modifiers The key modifiers for the event.
408
* Accepted values are shift, ctrl, alt, meta.
409
* @param {string=} key The KeyboardEvent.key value for the event.
411
function pressAndReleaseKeyOn(target, keyCode, modifiers, key) {
412
keyDownOn(target, keyCode, modifiers, key);
413
Polymer.Base.async(function() {
414
keyUpOn(target, keyCode, modifiers, key);
419
* Simulates a complete 'enter' key press by firing a `keydown` keyboard event,
420
* followed by an asynchronous `keyup` event on a specific node.
422
* @param {!HTMLElement} target The node to fire the event on.
424
function pressEnter(target) {
425
pressAndReleaseKeyOn(target, 13);
429
* Simulates a complete 'space' key press by firing a `keydown` keyboard event,
430
* followed by an asynchronous `keyup` event on a specific node.
432
* @param {!HTMLElement} target The node to fire the event on.
434
function pressSpace(target) {
435
pressAndReleaseKeyOn(target, 32);
438
global.MockInteractions = {
443
downAndUp: downAndUp,
446
pressAndReleaseKeyOn: pressAndReleaseKeyOn,
447
pressEnter: pressEnter,
448
pressSpace: pressSpace,
449
keyDownOn: keyDownOn,
451
keyboardEventFor: keyboardEventFor,
452
keyEventOn: keyEventOn,
453
middleOfNode: middleOfNode,
454
topLeftOfNode: topLeftOfNode