From eaa02cd2ada21377f921579d8977b1a0ed1e328c Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 11 Jun 2015 11:37:43 +0100 Subject: [PATCH] Add utils.inherits. Make User inherit EventEmitter. utils.inherits is the Node.js impl but with the addition of a polyfill for Object.create(). --- lib/client.js | 31 +++++++++------- lib/models/user.js | 3 ++ lib/utils.js | 92 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 14 deletions(-) diff --git a/lib/client.js b/lib/client.js index 35c98482a..93b672738 100644 --- a/lib/client.js +++ b/lib/client.js @@ -33,9 +33,6 @@ function MatrixClient(opts) { ["baseUrl", "request", "accessToken", "userId", "store"] ); - // super call - EventEmitter.call(this); - this.store = opts.store || new MatrixInMemoryStore(); // track our position in the overall eventstream this.fromToken = undefined; @@ -53,16 +50,7 @@ function MatrixClient(opts) { }; this._http = new httpApi.MatrixHttpApi(httpOpts); } -// inherit from EventEmitter (not with ECMA5 Object.prototype for compat with IE8) -// See MDN for this shim impl. -function createObject(proto) { - function Ctor() { } - Ctor.prototype = proto; - return new Ctor(); -} -MatrixClient.prototype = createObject(EventEmitter.prototype); -/** */ -MatrixClient.constructor = module.exports.MatrixClient; +utils.inherits(MatrixClient, EventEmitter); /** * Get the data store for this client. @@ -848,7 +836,7 @@ MatrixClient.prototype.startClient = function(historyLen) { return new MatrixEvent(event); }; utils.forEach(utils.map(data.presence, eventMapper), function(e) { - var user = new User(e.getContent().user_id); + var user = createNewUser(self, e.getContent().user_id); user.setPresenceEvent(e); self.store.storeUser(user); }); @@ -977,6 +965,21 @@ MatrixClient.prototype.stopClient = function() { // TODO: f.e. Room => self.store.storeRoom(room) ? }; + +function reEmit(reEmitEntity, emittableEntity, eventNames) { + utils.forEach(eventNames, function(eventName) { + emittableEntity.on(eventName, function() { + reEmitEntity.emit(eventName, arguments); + }); + }); +} + +function createNewUser(client, userId) { + var user = new User(userId); + reEmit(client, user, ["User.avatarUrl", "User.displayName", "User.presence"]); + return user; +} + /** */ module.exports.MatrixClient = MatrixClient; diff --git a/lib/models/user.js b/lib/models/user.js index ffeb6a612..205b6dbb9 100644 --- a/lib/models/user.js +++ b/lib/models/user.js @@ -2,6 +2,8 @@ /** * @module models/user */ + var EventEmitter = require("events").EventEmitter; + var utils = require("../utils"); /** * Construct a new User. A User must have an ID and can optionally have extra @@ -22,6 +24,7 @@ function User(userId) { this.avatarUrl = null; this.lastActiveAgo = 0; } +utils.inherits(User, EventEmitter); /** * Update this User with the given presence event. May fire "User.presence", diff --git a/lib/utils.js b/lib/utils.js index 48db9ed8b..15a6c8f54 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -157,3 +157,95 @@ module.exports.checkObjectHasNoAdditionalKeys = function(obj, allowedKeys) { } } }; + +/** + * Inherit the prototype methods from one constructor into another. This is a + * port of the Node.js implementation with an Object.create polyfill. + * + * @param {function} ctor Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor Constructor function to inherit prototype from. + */ +module.exports.inherits = function(ctor, superCtor) { + // Add Object.create polyfill for IE8 + // Source: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript + // /Reference/Global_Objects/Object/create#Polyfill + if (typeof Object.create != 'function') { + // Production steps of ECMA-262, Edition 5, 15.2.3.5 + // Reference: http://es5.github.io/#x15.2.3.5 + Object.create = (function() { + // To save on memory, use a shared constructor + function Temp() {} + + // make a safe reference to Object.prototype.hasOwnProperty + var hasOwn = Object.prototype.hasOwnProperty; + + return function(O) { + // 1. If Type(O) is not Object or Null throw a TypeError exception. + if (typeof O != 'object') { + throw new TypeError('Object prototype may only be an Object or null'); + } + + // 2. Let obj be the result of creating a new object as if by the + // expression new Object() where Object is the standard built-in + // constructor with that name + // 3. Set the [[Prototype]] internal property of obj to O. + Temp.prototype = O; + var obj = new Temp(); + Temp.prototype = null; // Let's not keep a stray reference to O... + + // 4. If the argument Properties is present and not undefined, add + // own properties to obj as if by calling the standard built-in + // function Object.defineProperties with arguments obj and + // Properties. + if (arguments.length > 1) { + // Object.defineProperties does ToObject on its first argument. + var Properties = Object(arguments[1]); + for (var prop in Properties) { + if (hasOwn.call(Properties, prop)) { + obj[prop] = Properties[prop]; + } + } + } + + // 5. Return obj + return obj; + }; + })(); + } + // END polyfill + + // Add util.inherits from Node.js + // Source: + // https://github.com/joyent/node/blob/master/lib/util.js + // Copyright Joyent, Inc. and other Node contributors. + // + // Permission is hereby granted, free of charge, to any person obtaining a + // copy of this software and associated documentation files (the + // "Software"), to deal in the Software without restriction, including + // without limitation the rights to use, copy, modify, merge, publish, + // distribute, sublicense, and/or sell copies of the Software, and to permit + // persons to whom the Software is furnished to do so, subject to the + // following conditions: + // + // The above copyright notice and this permission notice shall be included + // in all copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN + // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + // USE OR OTHER DEALINGS IN THE SOFTWARE. + ctor.super_ = superCtor; + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); +};