Skip to content

Commit 1f082b7

Browse files
committed
Polyfill native methods
1 parent 933647b commit 1f082b7

File tree

2 files changed

+67
-17
lines changed

2 files changed

+67
-17
lines changed

src/raven.js

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -540,9 +540,13 @@ Raven.prototype = {
540540
_wrapBuiltIns: function() {
541541
var self = this;
542542

543-
var _helper = function _helper(fnName) {
544-
var originalFn = window[fnName];
545-
window[fnName] = function ravenAsyncExtension() {
543+
function fill(obj, name, replacement) {
544+
var orig = obj[name];
545+
obj[name] = replacement(orig);
546+
}
547+
548+
function wrapTimeFn(orig) {
549+
return function (fn, t) { // preserve arity
546550
// Make a copy of the arguments
547551
var args = [].slice.call(arguments);
548552
var originalCallback = args[0];
@@ -553,19 +557,42 @@ Raven.prototype = {
553557
// IE < 9 doesn't support .call/.apply on setInterval/setTimeout, but it
554558
// also supports only two arguments and doesn't care what this is, so we
555559
// can just call the original function directly.
556-
if (originalFn.apply) {
557-
return originalFn.apply(this, args);
560+
if (orig.apply) {
561+
return orig.apply(this, args);
558562
} else {
559-
return originalFn(args[0], args[1]);
563+
return orig(args[0], args[1]);
560564
}
561565
};
562566
};
563567

564-
_helper('setTimeout');
565-
_helper('setInterval');
568+
fill(window, 'setTimeout', wrapTimeFn);
569+
fill(window, 'setInterval', wrapTimeFn);
566570
if (window.requestAnimationFrame) {
567-
_helper('requestAnimationFrame');
571+
fill(window, 'requestAnimationFrame', function (orig) {
572+
return function (cb) {
573+
orig(self.wrap(cb));
574+
}
575+
});
568576
}
577+
578+
// event targets borrowed from bugsnag-js:
579+
// https://github.com/bugsnag/bugsnag-js/blob/master/src/bugsnag.js#L666
580+
'EventTarget Window Node ApplicationCache AudioTrackList ChannelMergerNode CryptoOperation EventSource FileReader HTMLUnknownElement IDBDatabase IDBRequest IDBTransaction KeyOperation MediaController MessagePort ModalWindow Notification SVGElementInstance Screen TextTrack TextTrackCue TextTrackList WebSocket WebSocketWorker Worker XMLHttpRequest XMLHttpRequestEventTarget XMLHttpRequestUpload'.replace(/\w+/g, function (global) {
581+
var proto = window[global] && window[global].prototype;
582+
if (proto && proto.hasOwnProperty && proto.hasOwnProperty('addEventListener')) {
583+
fill(proto, 'addEventListener', function(orig) {
584+
return function (evt, fn, capture, secure) { // preserve arity
585+
try {
586+
if (fn && fn.handleEvent) {
587+
fn.handleEvent = self.wrap(fn.handleEvent, {eventHandler: true});
588+
}
589+
} catch (err) {} // can sometimes get 'Permission denied to access property "handle Event'
590+
return orig.call(this, evt, self.wrap(fn, {eventHandler: true}), capture, secure);
591+
}
592+
});
593+
}
594+
});
595+
569596
},
570597

571598
_drainPlugins: function() {

test/integration/test.js

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ function createIframe(done) {
2424
}
2525

2626
describe('integration', function () {
27-
var defaultStackSize = 0;
27+
var timeoutStackDepth = 0;
28+
var eventHandlerStackDepth = 0;
2829

2930
before(function (done) {
3031
// Before running any tests, throw/catch a known error
@@ -37,10 +38,32 @@ describe('integration', function () {
3738
iframe.contentWindow.foo();
3839
} catch (e) {
3940
var trace = Raven.TraceKit.computeStackTrace(e);
40-
defaultStackSize = trace.stack.length;
41-
document.body.removeChild(iframe);
42-
done();
41+
timeoutStackDepth = trace.stack.length;
42+
}
43+
44+
var doc = iframe.contentWindow.document;
45+
var div = doc.createElement('div');
46+
doc.body.appendChild(div);
47+
div.addEventListener('click', function () {
48+
try {
49+
foo();
50+
} catch (e) {
51+
var trace = Raven.TraceKit.computeStackTrace(e);
52+
eventHandlerStackDepth = trace.stack.length;
53+
}
54+
}, false);
55+
56+
var evt;
57+
if (doc.createEvent) {
58+
evt = doc.createEvent('MouseEvents');
59+
evt.initEvent('click', true, false);
60+
div.dispatchEvent(evt);
61+
} else if(doc.createEventObject) {
62+
div.fireEvent('onclick');
4363
}
64+
65+
document.body.removeChild(iframe);
66+
done();
4467
});
4568
});
4669
});
@@ -114,7 +137,7 @@ describe('integration', function () {
114137
},
115138
function () {
116139
var ravenData = iframe.contentWindow.ravenData;
117-
assert.equal(ravenData.exception.values[0].stacktrace.frames.length, defaultStackSize + 1);
140+
assert.equal(ravenData.exception.values[0].stacktrace.frames.length, eventHandlerStackDepth + 2);
118141
}
119142
);
120143
});
@@ -131,7 +154,7 @@ describe('integration', function () {
131154
},
132155
function () {
133156
var ravenData = iframe.contentWindow.ravenData;
134-
assert.equal(ravenData.exception.values[0].stacktrace.frames.length, defaultStackSize);
157+
assert.equal(ravenData.exception.values[0].stacktrace.frames.length, timeoutStackDepth);
135158
}
136159
);
137160
});
@@ -149,7 +172,7 @@ describe('integration', function () {
149172
},
150173
function () {
151174
var ravenData = iframe.contentWindow.ravenData;
152-
assert.equal(ravenData.exception.values[0].stacktrace.frames.length, defaultStackSize);
175+
assert.equal(ravenData.exception.values[0].stacktrace.frames.length, timeoutStackDepth);
153176
}
154177
);
155178
});
@@ -168,7 +191,7 @@ describe('integration', function () {
168191
},
169192
function () {
170193
var ravenData = iframe.contentWindow.ravenData;
171-
assert.equal(ravenData.exception.values[0].stacktrace.frames.length, defaultStackSize);
194+
assert.equal(ravenData.exception.values[0].stacktrace.frames.length, timeoutStackDepth);
172195
}
173196
);
174197
});

0 commit comments

Comments
 (0)