Skip to content

Commit 6e7d2ac

Browse files
committed
Added support for scroll events.
1 parent 778356d commit 6e7d2ac

File tree

2 files changed

+62
-43
lines changed

2 files changed

+62
-43
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,6 @@ The test script will be logged to the console as a JSON string. Save the JSON to
4242

4343
## Requirements
4444

45-
At the moment, jsReplay requires jQuery 1.7+. This requirements will be removed in future versions.
45+
jsReplay currently requires jQuery 1.7+. Future versions of jsReplay will not require jQuery.
4646

4747
jsReplay only supports Chrome and has only been tested in Chrome 59. jsReplay should not be expected to function properly in other web browsers.

replay.js

+61-42
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ var jsReplay = (function() {
8383
var eventTarget = selectorHash[userEvent.selector];
8484
} else {
8585

86-
var eventTarget = $(userEvent.selector)[0];
86+
if (userEvent.selector === "document") {
87+
var eventTarget = document;
88+
} else {
89+
var eventTarget = $(userEvent.selector)[0];
90+
}
8791

8892
if (userEvent.hasOwnProperty("clientX") && userEvent.hasOwnProperty("clientY")) {
8993

@@ -101,21 +105,26 @@ var jsReplay = (function() {
101105
}
102106
}
103107

104-
var launchTime = new Date().getTime()
105-
console.log("Simulating ("+launchTime+"): " + userEvent.type + " selector: " + userEvent.selector);
108+
console.log("Simulating scroll ("+(userEvent.timeStamp/1000).toFixed(3)+"s). Selector: " + userEvent.selector);
109+
110+
var event = null;
106111

107112
switch (userEvent.type) {
113+
case "scroll":
114+
$(eventTarget).scrollLeft(userEvent.scrollLeft);
115+
$(eventTarget).scrollTop(userEvent.scrollTop);
116+
break;
108117
case "focusin":
109118
case "focusout":
110119
case "focus":
111120
case "blur":
112-
var event = new FocusEvent(userEvent.type, userEvent);
121+
event = new FocusEvent(userEvent.type, userEvent);
113122
break;
114123
case "tap":
115124
case "click":
116125
case "mouseup":
117126
case "mousedown":
118-
var event = new MouseEvent(userEvent.type, userEvent);
127+
event = new MouseEvent(userEvent.type, userEvent);
119128
break;
120129
case "touchstart":
121130
case "touchend":
@@ -166,16 +175,16 @@ var jsReplay = (function() {
166175

167176
userEvent.changedTouches = touchList;
168177

169-
var event = new TouchEvent(userEvent.type, userEvent);
178+
event = new TouchEvent(userEvent.type, userEvent);
170179

171180
break;
172181
case "keypress":
173182
case "keydown":
174183
case "keyup":
175-
var event = new KeyboardEvent(userEvent.type, userEvent);
184+
event = new KeyboardEvent(userEvent.type, userEvent);
176185
break;
177186
case "input":
178-
var event = new Event(userEvent.type, userEvent);
187+
event = new Event(userEvent.type, userEvent);
179188
$(userEvent.selector).val(userEvent.value);
180189
break;
181190
case "contains":
@@ -186,7 +195,9 @@ var jsReplay = (function() {
186195
break;
187196
}
188197

189-
eventTarget.dispatchEvent(event);
198+
if (event !== null) {
199+
eventTarget.dispatchEvent(event);
200+
}
190201

191202
};
192203

@@ -299,10 +310,10 @@ var jsReplay = (function() {
299310
// trigger the event
300311
simulateEvent(userEvent);
301312

302-
// continue this loop for events that occurred up to 200ms in the future. we do this because a simple user action like a mouse click
313+
// continue this loop for events that occurred up to 50ms in the future. we do this because a simple user action like a mouse click
303314
// will trigger multiple events (click, mousedown, mouseup, etc). if those events were separated by even 10ms, then the DOM could change in-between
304315
// those events and we'd encounter an element target mismatch. looking forward 200ms and firing them at the same time allows us to avoid this issue.
305-
} while (userEventLength > 0 && ((currentTime+200) > (self.userEventLog[0].timeStamp + timeStartedPlayback)));
316+
} while (userEventLength > 0 && ((currentTime+50) > (self.userEventLog[0].timeStamp + timeStartedPlayback)));
306317
}
307318

308319
// if userEventLength is 0, then that means there are no more events to replay
@@ -362,37 +373,44 @@ var jsReplay = (function() {
362373
if (recordInProgress == true) {
363374

364375
var userEvent = {"selector":getSelector(event.target)};
376+
377+
if (event.type === "scroll") {
378+
userEvent.type = "scroll";
379+
userEvent.scrollTop = $(event.target).scrollTop();
380+
userEvent.scrollLeft = $(event.target).scrollLeft();
381+
userEvent.timeStamp = event.timeStamp;
382+
} else {
383+
for (var prop in event) {
384+
// We can only record plain such as string, numbers and booleans in JSON. Objects will require special processing.
385+
if (["number","string","boolean"].indexOf(typeof event[prop]) > -1
386+
// Exclude certain event event attributes in order to keep the JSON log as small as possible.
387+
// These attributes are not needed to re-create the event during playback.
388+
&& ["AT_TARGET","BUBBLING_PHASE","CAPTURING_PHASE","NONE","DOM_KEY_LOCATION_STANDARD","DOM_KEY_LOCATION_LEFT","DOM_KEY_LOCATION_RIGHT","DOM_KEY_LOCATION_NUMPAD"].indexOf(prop) == -1) {
389+
userEvent[prop] = event[prop];
390+
} else if (["touches","changedTouches"].indexOf(prop) > -1) {
391+
392+
userEvent[prop] = [];
393+
394+
for (var i = 0; i < event[prop].length; i++) {
395+
var touch = event[prop][i];
396+
userEvent[prop].push({
397+
"clientX":touch.clientX
398+
,"clientY":touch.clientY
399+
,"force":touch.force
400+
,"identifier":touch.identifier
401+
,"pageX":touch.pageX
402+
,"pageY":touch.pageY
403+
,"radiusX":touch.radiusX
404+
,"radiusY":touch.radiusY
405+
,"rotationAngle":touch.rotationAngle
406+
,"screenX":touch.screenX
407+
,"screenY":touch.screenY
408+
,"selector":getSelector(touch.target)
409+
});
365410

366-
for (var prop in event) {
367-
// We can only record plain such as string, numbers and booleans in JSON. Objects will require special processing.
368-
if (["number","string","boolean"].indexOf(typeof event[prop]) > -1
369-
// Exclude certain event event attributes in order to keep the JSON log as small as possible.
370-
// These attributes are not needed to re-create the event during playback.
371-
&& ["AT_TARGET","BUBBLING_PHASE","CAPTURING_PHASE","NONE","DOM_KEY_LOCATION_STANDARD","DOM_KEY_LOCATION_LEFT","DOM_KEY_LOCATION_RIGHT","DOM_KEY_LOCATION_NUMPAD"].indexOf(prop) == -1) {
372-
userEvent[prop] = event[prop];
373-
} else if (["touches","changedTouches"].indexOf(prop) > -1) {
374-
375-
userEvent[prop] = [];
376-
377-
for (var i = 0; i < event[prop].length; i++) {
378-
var touch = event[prop][i];
379-
userEvent[prop].push({
380-
"clientX":touch.clientX
381-
,"clientY":touch.clientY
382-
,"force":touch.force
383-
,"identifier":touch.identifier
384-
,"pageX":touch.pageX
385-
,"pageY":touch.pageY
386-
,"radiusX":touch.radiusX
387-
,"radiusY":touch.radiusY
388-
,"rotationAngle":touch.rotationAngle
389-
,"screenX":touch.screenX
390-
,"screenY":touch.screenY
391-
,"selector":getSelector(touch.target)
392-
});
411+
}
393412

394413
}
395-
396414
}
397415
}
398416

@@ -403,8 +421,7 @@ var jsReplay = (function() {
403421
if (userEvent.selector !== null) {
404422
if (playbackInProgress == false) {
405423
userEventLog.push(userEvent);
406-
console.log("LOGGED EVENT:");
407-
console.log(userEventLog);
424+
console.log("Logged "+userEvent.type+" event.");
408425
}
409426
} else {
410427
console.warn("Null selector");
@@ -424,7 +441,8 @@ var jsReplay = (function() {
424441
String, a unique CSS selector for the target element (el).
425442
*/
426443
var getSelector = function(el, names) {
427-
if (el === document || el === document.documentElement || el === document.body) return null;
444+
if (el === document || el === document.documentElement) return "document";
445+
if (el === document.body) return "body";
428446
if (typeof names === "undefined") var names = [];
429447
if (el.id) {
430448
names.unshift('#'+el.id);
@@ -476,6 +494,7 @@ var jsReplay = (function() {
476494
document.addEventListener('touchend',function(event) { logEvent(event); },true);
477495
document.addEventListener('touchmove',function(event) { logEvent(event); },true);
478496
document.addEventListener('touchcancel',function(event) { logEvent(event); },true);
497+
document.addEventListener('scroll',function(event) { logEvent(event); }, true);
479498

480499
return {
481500

0 commit comments

Comments
 (0)