-
Notifications
You must be signed in to change notification settings - Fork 40
/
detectProgrammaticScroll.js
90 lines (76 loc) · 3.01 KB
/
detectProgrammaticScroll.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
(function(){
function getElementXPath(element) {
if (element && element.id)
return '//*[@id="' + element.id + '"]';
else
return getElementTreeXPath(element);
}
function getElementTreeXPath(element) {
var paths = [];
// Use nodeName (instead of localName) so namespace prefix is included (if any).
for (; element && element.nodeType == 1; element = element.parentNode) {
var index = 0;
for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) {
// Ignore document type declaration.
if (sibling.nodeType == Node.DOCUMENT_TYPE_NODE)
continue;
if (sibling.nodeName == element.nodeName)
++index;
}
var tagName = element.nodeName.toLowerCase();
var pathIndex = (index ? "[" + (index+1) + "]" : "");
paths.splice(0, 0, tagName + pathIndex);
}
return paths.length ? "/" + paths.join("/") : null;
}
// Override function in given prototype to add a log statement
function logMethod(prototype, fname) {
if (!(fname in prototype)) {
console.warn("Warning: can't instrument " + prototype.constructor.name + '.' + fname);
return;
}
var original = prototype[fname];
prototype[fname] = function() {
// Want single line output but with optional callstack - abuse 'error' for this.
// console.trace is also good but expands the callstack by default.'
console.error(prototype.constructor.name + '::' + fname + ' invoked with ' + JSON.stringify(Array.prototype.slice.call(arguments)) + ' on node ' + getElementXPath(this));
// debugger;
original.apply(this, arguments);
};
}
// Override property setter to add a log statement
function logSetter(prototype, property) {
var original = Object.getOwnPropertyDescriptor(prototype, property);
if (!original) {
console.warn("Warning: can't instrument " + prototype.constructor.name + '.' + property +
'. Chrome 43+ required (http://crbug.com/43394)');
return;
}
Object.defineProperty(prototype, property, {
set: function(v) {
var changed = v !== this[property];
console.error(prototype.constructor.name + '::' + property + ' set to:' + v + (changed?' (changed)':' (not changed)'));
// debugger;
if ('set' in original)
original.set.call(this, v);
else
original.value = v;
},
get: function() {
return 'get' in original ? original.get.call(this) : original.value;
}
});
}
for (var m of ['scrollBy', 'scrollTo', 'scroll'])
logMethod(window, m);
// Firefox only
for (var m of ['scrollByLines', 'scrollByPages'])
if (m in window)
logMethod(window, m);
for (var p of ['scrollX', 'scrollY'])
logSetter(window, p);
for (var m of ['scrollIntoView', 'scrollIntoViewIfNeeded', 'focus'])
logMethod(Element.prototype, m);
for (var p of ['scrollTop', 'scrollLeft'])
logSetter(Element.prototype, p);
})();