Skip to content

Commit 3229579

Browse files
committed
IE8 compatibility
1 parent ae6fc1f commit 3229579

File tree

10 files changed

+107
-54
lines changed

10 files changed

+107
-54
lines changed

events.js

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,17 @@
1919
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
2020
// USE OR OTHER DEALINGS IN THE SOFTWARE.
2121

22+
var objectCreate = Object.create || objectCreatePolyfill
23+
var objectKeys = Object.keys || objectKeysPolyfill
24+
var bind = Function.prototype.bind || functionBindPolyfill
25+
2226
function EventEmitter() {
23-
EventEmitter.init.call(this);
27+
if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) {
28+
this._events = objectCreate(null);
29+
this._eventsCount = 0;
30+
}
31+
32+
this._maxListeners = this._maxListeners || undefined;
2433
}
2534
module.exports = EventEmitter;
2635

@@ -34,28 +43,29 @@ EventEmitter.prototype._maxListeners = undefined;
3443
// added to it. This is a useful default which helps finding memory leaks.
3544
var defaultMaxListeners = 10;
3645

37-
Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
38-
enumerable: true,
39-
get: function() {
40-
return defaultMaxListeners;
41-
},
42-
set: function(arg) {
43-
// check whether the input is a positive number (whose value is zero or
44-
// greater and not a NaN).
45-
if (typeof arg !== 'number' || arg < 0 || arg !== arg)
46-
throw new TypeError('"defaultMaxListeners" must be a positive number');
47-
defaultMaxListeners = arg;
48-
}
49-
});
50-
51-
EventEmitter.init = function() {
52-
if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
53-
this._events = Object.create(null);
54-
this._eventsCount = 0;
55-
}
56-
57-
this._maxListeners = this._maxListeners || undefined;
58-
};
46+
var hasDefineProperty;
47+
try {
48+
var o = {};
49+
if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 });
50+
hasDefineProperty = o.x === 0;
51+
} catch (err) { hasDefineProperty = false }
52+
if (hasDefineProperty) {
53+
Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
54+
enumerable: true,
55+
get: function() {
56+
return defaultMaxListeners;
57+
},
58+
set: function(arg) {
59+
// check whether the input is a positive number (whose value is zero or
60+
// greater and not a NaN).
61+
if (typeof arg !== 'number' || arg < 0 || arg !== arg)
62+
throw new TypeError('"defaultMaxListeners" must be a positive number');
63+
defaultMaxListeners = arg;
64+
}
65+
});
66+
} else {
67+
EventEmitter.defaultMaxListeners = defaultMaxListeners;
68+
}
5969

6070
// Obviously not all Emitters should be limited to 10. This function allows
6171
// that to be increased. Set to zero for unlimited.
@@ -200,7 +210,7 @@ function _addListener(target, type, listener, prepend) {
200210

201211
events = target._events;
202212
if (!events) {
203-
events = target._events = Object.create(null);
213+
events = target._events = objectCreate(null);
204214
target._eventsCount = 0;
205215
} else {
206216
// To avoid recursion in the case that type === "newListener"! Before
@@ -247,7 +257,9 @@ function _addListener(target, type, listener, prepend) {
247257
w.emitter = target;
248258
w.type = type;
249259
w.count = existing.length;
250-
console.warn('%s: %s', w.name, w.message);
260+
if (typeof console === 'object' && console.warn) {
261+
console.warn('%s: %s', w.name, w.message);
262+
}
251263
}
252264
}
253265
}
@@ -291,7 +303,7 @@ function onceWrapper() {
291303

292304
function _onceWrap(target, type, listener) {
293305
var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
294-
var wrapped = onceWrapper.bind(state);
306+
var wrapped = bind.call(onceWrapper, state);
295307
wrapped.listener = listener;
296308
state.wrapFn = wrapped;
297309
return wrapped;
@@ -330,7 +342,7 @@ EventEmitter.prototype.removeListener =
330342

331343
if (list === listener || list.listener === listener) {
332344
if (--this._eventsCount === 0)
333-
this._events = Object.create(null);
345+
this._events = objectCreate(null);
334346
else {
335347
delete events[type];
336348
if (events.removeListener)
@@ -376,11 +388,11 @@ EventEmitter.prototype.removeAllListeners =
376388
// not listening for removeListener, no need to emit
377389
if (!events.removeListener) {
378390
if (arguments.length === 0) {
379-
this._events = Object.create(null);
391+
this._events = objectCreate(null);
380392
this._eventsCount = 0;
381393
} else if (events[type]) {
382394
if (--this._eventsCount === 0)
383-
this._events = Object.create(null);
395+
this._events = objectCreate(null);
384396
else
385397
delete events[type];
386398
}
@@ -389,15 +401,15 @@ EventEmitter.prototype.removeAllListeners =
389401

390402
// emit removeListener for all listeners on all events
391403
if (arguments.length === 0) {
392-
var keys = Object.keys(events);
404+
var keys = objectKeys(events);
393405
var key;
394406
for (i = 0; i < keys.length; ++i) {
395407
key = keys[i];
396408
if (key === 'removeListener') continue;
397409
this.removeAllListeners(key);
398410
}
399411
this.removeAllListeners('removeListener');
400-
this._events = Object.create(null);
412+
this._events = objectCreate(null);
401413
this._eventsCount = 0;
402414
return this;
403415
}
@@ -486,3 +498,22 @@ function unwrapListeners(arr) {
486498
}
487499
return ret;
488500
}
501+
502+
function objectCreatePolyfill(proto) {
503+
var F = function() {};
504+
F.prototype = proto;
505+
return new F;
506+
}
507+
function objectKeysPolyfill(obj) {
508+
var keys = [];
509+
for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) {
510+
keys.push(k);
511+
}
512+
return k;
513+
}
514+
function functionBindPolyfill(context) {
515+
var fn = this;
516+
return function () {
517+
return fn.apply(context, arguments);
518+
};
519+
}

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@
2323
"node": ">=0.4.x"
2424
},
2525
"devDependencies": {
26+
"isarray": "^2.0.2",
2627
"mocha": "~1.21.4",
28+
"object-keys": "^1.0.11",
2729
"zuul": "~1.10.2"
2830
},
2931
"scripts": {
3032
"test": "mocha --ui qunit -- tests/index.js && zuul -- tests/index.js"
3133
},
3234
"license": "MIT"
33-
}
35+
}

tests/common.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ var mustCallChecks = [];
2828
function runCallChecks(exitCode) {
2929
if (exitCode !== 0) return;
3030

31-
var failed = mustCallChecks.filter(function(context) {
31+
var failed = filter(mustCallChecks, function(context) {
3232
if ('minimum' in context) {
3333
context.messageSegment = 'at least ' + context.minimum;
3434
return context.actual < context.minimum;
@@ -38,13 +38,15 @@ function runCallChecks(exitCode) {
3838
}
3939
});
4040

41-
failed.forEach(function(context) {
41+
for (var i = 0; i < failed.length; i++) {
42+
var context = failed[i];
4243
console.log('Mismatched %s function calls. Expected %s, actual %d.',
4344
context.name,
4445
context.messageSegment,
4546
context.actual);
46-
console.log(context.stack.split('\n').slice(2).join('\n'));
47-
});
47+
// IE8 has no .stack
48+
if (context.stack) console.log(context.stack.split('\n').slice(2).join('\n'));
49+
}
4850

4951
assert.strictEqual(failed.length, 0);
5052
}
@@ -90,3 +92,12 @@ exports.mustNotCall = function(msg) {
9092
assert.fail(msg || 'function should not have been called');
9193
};
9294
};
95+
96+
function filter(arr, fn) {
97+
if (arr.filter) return arr.filter(fn);
98+
var filtered = [];
99+
for (var i = 0; i < arr.length; i++) {
100+
if (fn(arr[i], i, arr)) filtered.push(arr[i]);
101+
}
102+
return filtered
103+
}

tests/legacy-compat.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,5 @@ for (var i=0 ; i<fns.length ; ++i) {
1212
}
1313

1414
if (!Array.isArray) {
15-
Array.isArray = function(arr) {
16-
return Object.prototype.toString.call(arr) === '[object Array]';
17-
}
15+
Array.isArray = require('isarray');
1816
}

tests/listeners-side-effects.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,16 @@ require('./common');
2323
var assert = require('assert');
2424

2525
var EventEmitter = require('../').EventEmitter;
26+
var objectKeys = require('object-keys');
2627

2728
var e = new EventEmitter();
2829
var fl; // foo listeners
2930

3031
fl = e.listeners('foo');
3132
assert.ok(Array.isArray(fl));
3233
assert.strictEqual(fl.length, 0);
33-
assert.ok(!(e._events instanceof Object));
34-
assert.strictEqual(Object.keys(e._events).length, 0);
34+
if (Object.create) assert.ok(!(e._events instanceof Object));
35+
assert.strictEqual(objectKeys(e._events).length, 0);
3536

3637
e.on('foo', assert.fail);
3738
fl = e.listeners('foo');

tests/max-listeners.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ var assert = require('assert');
2424
var events = require('../');
2525
var e = new events.EventEmitter();
2626

27+
var hasDefineProperty = !!Object.defineProperty;
28+
try { Object.defineProperty({}, 'x', { value: 0 }); } catch (err) { hasDefineProperty = false }
29+
2730
e.on('maxListeners', common.mustCall());
2831

2932
// Should not corrupt the 'maxListeners' queue.
@@ -33,9 +36,12 @@ var throwsObjs = [NaN, -1, 'and even this'];
3336
var maxError = /^TypeError: "n" argument must be a positive number$/;
3437
var defError = /^TypeError: "defaultMaxListeners" must be a positive number$/;
3538

36-
throwsObjs.forEach(function(obj) {
39+
for (var i = 0; i < throwsObjs.length; i++) {
40+
var obj = throwsObjs[i];
3741
assert.throws(function() { e.setMaxListeners(obj); }, maxError);
38-
assert.throws(function() { events.defaultMaxListeners = obj; }, defError);
39-
});
42+
if (hasDefineProperty) {
43+
assert.throws(function() { events.defaultMaxListeners = obj; }, defError);
44+
}
45+
}
4046

4147
e.emit('maxListeners');

tests/once.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,10 @@ assert.throws(function() {
7272
var restArgs = args.slice(1);
7373
assert.ok(Array.isArray(params));
7474
assert.strictEqual(params.length, restArgs.length);
75-
params.forEach(function(param, index) {
75+
for (var index = 0; index < params.length; index++) {
76+
var param = params[index];
7677
assert.strictEqual(param, restArgs[index]);
77-
});
78+
}
7879
}));
7980

8081
EventEmitter.prototype.emit.apply(ee, args);

tests/remove-all-listeners.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,10 @@ function expect(expected) {
3636
var sortedActual = actual.sort();
3737
var sortedExpected = expected.sort();
3838
assert.strictEqual(sortedActual.length, sortedExpected.length);
39-
sortedActual.forEach(function(value, index) {
39+
for (var index = 0; index < sortedActual.length; index++) {
40+
var value = sortedActual[index];
4041
assert.strictEqual(value, sortedExpected[index]);
41-
});
42+
}
4243
});
4344
function listener(name) {
4445
actual.push(name);
@@ -109,7 +110,7 @@ function expect(expected) {
109110
// Check for regression where removeAllListeners() throws when
110111
// there exists a 'removeListener' listener, but there exists
111112
// no listeners for the provided event type.
112-
assert.doesNotThrow(ee.removeAllListeners.bind(ee, 'foo'));
113+
assert.doesNotThrow(function () { ee.removeAllListeners(ee, 'foo') });
113114
}
114115

115116
{

tests/set-max-listeners-side-effects.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@
2222
require('./common');
2323
var assert = require('assert');
2424
var events = require('../');
25+
var objectKeys = require('object-keys');
2526

2627
var e = new events.EventEmitter();
2728

28-
assert.ok(!(e._events instanceof Object));
29-
assert.strictEqual(Object.keys(e._events).length, 0);
29+
if (Object.create) assert.ok(!(e._events instanceof Object));
30+
assert.strictEqual(objectKeys(e._events).length, 0);
3031
e.setMaxListeners(5);
31-
assert.strictEqual(Object.keys(e._events).length, 0);
32+
assert.strictEqual(objectKeys(e._events).length, 0);

tests/subclass.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var common = require('./common');
2323
var assert = require('assert');
2424
var EventEmitter = require('../').EventEmitter;
2525
var util = require('util');
26+
var objectKeys = require('object-keys');
2627

2728
var after_checks = [];
2829
after(function() {
@@ -53,8 +54,8 @@ assert.throws(function() {
5354
}, /blerg/);
5455

5556
after_checks.push(function() {
56-
assert.ok(!(myee._events instanceof Object));
57-
assert.strictEqual(Object.keys(myee._events).length, 0);
57+
if (Object.create) assert.ok(!(myee._events instanceof Object));
58+
assert.strictEqual(objectKeys(myee._events).length, 0);
5859
});
5960

6061

0 commit comments

Comments
 (0)